Skip to content

Commit

Permalink
check the validity of builder structs
Browse files Browse the repository at this point in the history
The only thing that isn't checked is that the `space` and `swapchain` handles come from the same session.
The spec only mentions this for the cube layer, but it is probably required for all layers.
  • Loading branch information
Timbals committed Jul 24, 2024
1 parent 6c46df7 commit fa4acaf
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 6 deletions.
8 changes: 7 additions & 1 deletion generator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1759,9 +1759,15 @@ impl Parser {
quote! {
#[repr(transparent)]
pub struct #base_ident #type_params {
_inner: sys::#sys_ident,
inner: sys::#sys_ident,
#marker
}
impl #type_params #base_ident #type_args {
#[inline]
pub(crate) fn as_raw(&self) -> &sys::#sys_ident {
&self.inner
}
}
#(#builders)*
}
}
Expand Down
24 changes: 24 additions & 0 deletions openxr/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ impl Action<Haptic> {
subaction_path: Path,
event: &HapticBase,
) -> Result<()> {
self.assert_event_validity(event);

let info = sys::HapticActionInfo {
ty: sys::HapticActionInfo::TYPE,
next: ptr::null(),
Expand All @@ -144,6 +146,28 @@ impl Action<Haptic> {
Ok(())
}

/// Check the invariants of the passed haptic `event`.
/// The lifetime guarantees the validity of the non-null pointers.
fn assert_event_validity(&self, event: &HapticBase) {
match event.as_raw().ty {
sys::HapticVibration::TYPE => {
// nothing to check
}
sys::HapticPcmVibrationFB::TYPE => {
assert!(self.instance().exts().fb_haptic_pcm.is_some());
let event =
unsafe { std::mem::transmute::<&HapticBase, &HapticPcmVibrationFB>(event) }
.as_raw();
assert!(event.buffer_size > 0);
assert_ne!(event.buffer, ptr::null());
assert_ne!(event.samples_consumed, ptr::null_mut());
}
ty => {
panic!("unsupported haptic type: {:?}", ty)
}
}
}

pub fn stop_feedback<G>(&self, session: &Session<G>, subaction_path: Path) -> Result<()> {
let info = sys::HapticActionInfo {
ty: sys::HapticActionInfo::TYPE,
Expand Down
116 changes: 113 additions & 3 deletions openxr/src/frame_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl<G: Graphics> FrameStream<G> {
environment_blend_mode: EnvironmentBlendMode,
layers: &[&CompositionLayerBase<'_, G>],
) -> Result<()> {
assert!(layers.len() <= u32::MAX as usize);
self.assert_layers_validity(layers);
let info = sys::FrameEndInfo {
ty: sys::FrameEndInfo::TYPE,
next: ptr::null(),
Expand Down Expand Up @@ -139,8 +139,8 @@ impl<G: Graphics> FrameStream<G> {
layers: &[&CompositionLayerBase<'_, G>],
secondary_info: SecondaryEndInfo<'_, '_, '_, G>,
) -> Result<()> {
assert!(layers.len() <= u32::MAX as usize);
assert!(secondary_info.layers.len() <= u32::MAX as usize);
self.assert_layers_validity(layers);
self.assert_layers_validity(secondary_info.layers);
let single_secondary_info = [sys::SecondaryViewConfigurationLayerInfoMSFT {
ty: sys::SecondaryViewConfigurationLayerInfoMSFT::TYPE,
next: ptr::null(),
Expand Down Expand Up @@ -174,4 +174,114 @@ impl<G: Graphics> FrameStream<G> {
fn fp(&self) -> &raw::Instance {
self.session.instance().fp()
}

/// Check the invariants of the passed `layers`.
/// The lifetimes guarantee the validity of non-null handles.
fn assert_layers_validity(&self, layers: &[&CompositionLayerBase<'_, G>]) {
// TODO `space` and `swapchain` must be from the same session (only in the spec for cube)
assert!(layers.len() <= u32::MAX as usize);
for &layer in layers {
match layer.as_raw().ty {
sys::CompositionLayerProjection::TYPE => {
let layer = unsafe {
std::mem::transmute::<
&CompositionLayerBase<G>,
&CompositionLayerProjection<G>,
>(layer)
}
.as_raw();
assert_ne!(layer.space, sys::Space::NULL);
assert!(layer.view_count > 0);
let views = unsafe {
std::slice::from_raw_parts(layer.views, layer.view_count as usize)
};
for view in views {
assert_ne!(view.sub_image.swapchain, sys::Swapchain::NULL);
}
}
sys::CompositionLayerQuad::TYPE => {
let layer = unsafe {
std::mem::transmute::<&CompositionLayerBase<G>, &CompositionLayerQuad<G>>(
layer,
)
}
.as_raw();
assert_ne!(layer.space, sys::Space::NULL);
assert_ne!(layer.sub_image.swapchain, sys::Swapchain::NULL);
}
sys::CompositionLayerCylinderKHR::TYPE => {
assert!(self
.session
.instance()
.exts()
.khr_composition_layer_cylinder
.is_some());
let layer = unsafe {
std::mem::transmute::<
&CompositionLayerBase<G>,
&CompositionLayerCylinderKHR<G>,
>(layer)
}
.as_raw();
assert_ne!(layer.space, sys::Space::NULL);
assert_ne!(layer.sub_image.swapchain, sys::Swapchain::NULL);
}
sys::CompositionLayerCubeKHR::TYPE => {
assert!(self
.session
.instance()
.exts()
.khr_composition_layer_cube
.is_some());
let layer =
unsafe {
std::mem::transmute::<
&CompositionLayerBase<G>,
&CompositionLayerCubeKHR<G>,
>(layer)
}
.as_raw();
assert_ne!(layer.space, sys::Space::NULL);
assert_ne!(layer.swapchain, sys::Swapchain::NULL);
}
sys::CompositionLayerEquirectKHR::TYPE => {
assert!(self
.session
.instance()
.exts()
.khr_composition_layer_equirect
.is_some());
let layer = unsafe {
std::mem::transmute::<
&CompositionLayerBase<G>,
&CompositionLayerEquirectKHR<G>,
>(layer)
}
.as_raw();
assert_ne!(layer.space, sys::Space::NULL);
assert_ne!(layer.sub_image.swapchain, sys::Swapchain::NULL);
}
sys::CompositionLayerEquirect2KHR::TYPE => {
assert!(self
.session
.instance()
.exts()
.khr_composition_layer_equirect2
.is_some());
let layer = unsafe {
std::mem::transmute::<
&CompositionLayerBase<G>,
&CompositionLayerEquirect2KHR<G>,
>(layer)
}
.as_raw();
assert_ne!(layer.space, sys::Space::NULL);
assert_ne!(layer.sub_image.swapchain, sys::Swapchain::NULL);
}
ty => {
panic!("unsupported layer type: {:?}", ty)
}
}
}
}
}
16 changes: 14 additions & 2 deletions openxr/src/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7269,9 +7269,15 @@ pub(crate) mod builder {
}
#[repr(transparent)]
pub struct CompositionLayerBase<'a, G: Graphics> {
_inner: sys::CompositionLayerBaseHeader,
inner: sys::CompositionLayerBaseHeader,
_marker: PhantomData<&'a G>,
}
impl<'a, G: Graphics> CompositionLayerBase<'a, G> {
#[inline]
pub(crate) fn as_raw(&self) -> &sys::CompositionLayerBaseHeader {
&self.inner
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct CompositionLayerProjection<'a, G: Graphics> {
Expand Down Expand Up @@ -7789,9 +7795,15 @@ pub(crate) mod builder {
}
#[repr(transparent)]
pub struct HapticBase<'a> {
_inner: sys::HapticBaseHeader,
inner: sys::HapticBaseHeader,
_marker: PhantomData<&'a ()>,
}
impl<'a> HapticBase<'a> {
#[inline]
pub(crate) fn as_raw(&self) -> &sys::HapticBaseHeader {
&self.inner
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct HapticVibration<'a> {
Expand Down

0 comments on commit fa4acaf

Please sign in to comment.