1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
use std::ptr; use crate::*; /// Handle for managing frame presentation /// /// This is a secondary interface to a `Session` object that exposes only the frame wait/begin/end /// operations. These are separated so that `&mut self` receivers can be used to statically /// guarantee that calls are synchronized as required by OpenXR, enabling a safe interface. /// /// # Example /// /// A typical presentation loop body should look roughly as follows: /// /// ```no_run /// # fn dummy<G: openxr::Graphics>( /// # session: &openxr::Session<G>, /// # swapchain: &mut openxr::Swapchain<G>, /// # frame_waiter: &mut openxr::FrameWaiter, /// # frame_stream: &mut openxr::FrameStream<G>, /// # world_space: &openxr::Space, /// # view_resolution: &[openxr::Extent2Di], /// # ) { /// let state = frame_waiter.wait().unwrap(); /// let image = swapchain.acquire_image().unwrap(); /// swapchain.wait_image(openxr::Duration::INFINITE).unwrap(); /// /// frame_stream.begin().unwrap(); /// /// if state.should_render { /// // draw scene... /// } /// /// let (view_flags, views) = session /// .locate_views( /// openxr::ViewConfigurationType::PRIMARY_STEREO, /// state.predicted_display_time, /// world_space, /// ) /// .unwrap(); /// /// // set view matrices and submit to GPU... /// /// swapchain.release_image().unwrap(); /// frame_stream /// .end( /// state.predicted_display_time, /// openxr::EnvironmentBlendMode::OPAQUE, /// &[&openxr::CompositionLayerProjection::new() /// .space(world_space) /// .views(&[ /// openxr::CompositionLayerProjectionView::new() /// .pose(views[0].pose) /// .fov(views[0].fov) /// .sub_image( /// openxr::SwapchainSubImage::new() /// .swapchain(swapchain) /// .image_array_index(0) /// .image_rect(openxr::Rect2Di { /// offset: openxr::Offset2Di { x: 0, y: 0 }, /// extent: view_resolution[0], /// }), /// ), /// openxr::CompositionLayerProjectionView::new() /// .pose(views[1].pose) /// .fov(views[1].fov) /// .sub_image( /// openxr::SwapchainSubImage::new() /// .swapchain(swapchain) /// .image_array_index(1) /// .image_rect(openxr::Rect2Di { /// offset: openxr::Offset2Di { x: 0, y: 0 }, /// extent: view_resolution[1], /// }), /// ), /// ])], /// ) /// .unwrap(); /// # } /// ``` pub struct FrameStream<G: Graphics> { session: Session<G>, } impl<G: Graphics> FrameStream<G> { pub(crate) fn new(session: Session<G>) -> Self { Self { session } } /// Indicate that graphics device work is beginning #[inline] pub fn begin(&mut self) -> Result<()> { unsafe { cvt((self.fp().begin_frame)( self.session.as_raw(), builder::FrameBeginInfo::new().as_raw(), ))?; } Ok(()) } /// Indicate that all graphics work for the frame has been submitted /// /// `layers` is an array of references to any type of composition layer, /// e.g. `CompositionLayerProjection`. #[inline] pub fn end( &mut self, display_time: Time, environment_blend_mode: EnvironmentBlendMode, layers: &[&CompositionLayerBase<'_, G>], ) -> Result<()> { assert!(layers.len() <= u32::max_value() as usize); let info = sys::FrameEndInfo { ty: sys::FrameEndInfo::TYPE, next: ptr::null(), display_time, environment_blend_mode, layer_count: layers.len() as u32, layers: layers.as_ptr() as _, }; unsafe { cvt((self.fp().end_frame)(self.session.as_raw(), &info))?; } Ok(()) } // Private helper #[inline] fn fp(&self) -> &raw::Instance { self.session.instance().fp() } } #[derive(Debug, Copy, Clone)] pub struct FrameState { pub predicted_display_time: Time, pub predicted_display_period: Duration, pub should_render: bool, }