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
use std::{ffi::CString, marker::PhantomData, ptr};
use crate::*;
/// A set of images to be rendered to using a particular graphics API `G`
pub struct Swapchain<G: Graphics> {
session: Session<G>,
handle: sys::Swapchain,
_marker: PhantomData<G>,
/// Whether `wait_image` was called more recently than `release_image`
waited: bool,
}
impl<G: Graphics> Swapchain<G> {
/// Take ownership of an existing swapchain handle
///
/// # Safety
///
/// `handle` must be a valid swapchain handle associated with `session` and created with `flags`.
#[inline]
pub unsafe fn from_raw(session: Session<G>, handle: sys::Swapchain) -> Self {
Self {
session,
handle,
_marker: PhantomData,
waited: false,
}
}
/// Access the raw swapchain handle
#[inline]
pub fn as_raw(&self) -> sys::Swapchain {
self.handle
}
/// Access the `Instance` self is descended from
#[inline]
pub fn instance(&self) -> &Instance {
self.session.instance()
}
/// Set the debug name of this `Swapchain`, if `XR_EXT_debug_utils` is loaded
#[inline]
pub fn set_name(&mut self, name: &str) -> Result<()> {
// We don't forward to the locking version on Instance because this object can't be cloned
if let Some(fp) = self.instance().exts().ext_debug_utils.as_ref() {
let name = CString::new(name).unwrap();
let info = sys::DebugUtilsObjectNameInfoEXT {
ty: sys::DebugUtilsObjectNameInfoEXT::TYPE,
next: ptr::null(),
object_type: ObjectType::SWAPCHAIN,
object_handle: self.as_raw().into_raw(),
object_name: name.as_ptr(),
};
unsafe {
cvt((fp.set_debug_utils_object_name)(
self.instance().as_raw(),
&info,
))?;
}
}
Ok(())
}
#[inline]
pub fn enumerate_images(&self) -> Result<Vec<G::SwapchainImage>> {
G::enumerate_swapchain_images(self)
}
/// Determine the index of the next image to render to in the swapchain image array
#[inline]
pub fn acquire_image(&mut self) -> Result<u32> {
let mut out = 0;
unsafe {
cvt((self.fp().acquire_swapchain_image)(
self.as_raw(),
ptr::null(),
&mut out,
))?;
}
Ok(out)
}
/// Wait for the compositor to finish reading from the oldest unwaited acquired image
#[inline]
pub fn wait_image(&mut self, timeout: Duration) -> Result<()> {
assert!(
!self.waited,
"release_image must be called before wait_image can be called again"
);
let info = sys::SwapchainImageWaitInfo {
ty: sys::SwapchainImageWaitInfo::TYPE,
next: ptr::null_mut(),
timeout,
};
unsafe {
cvt((self.fp().wait_swapchain_image)(self.as_raw(), &info))?;
}
self.waited = true;
Ok(())
}
/// Release the oldest acquired image
#[inline]
pub fn release_image(&mut self) -> Result<()> {
assert!(
self.waited,
"wait_image must be called before release_image"
);
unsafe {
cvt((self.fp().release_swapchain_image)(
self.as_raw(),
ptr::null(),
))?;
}
self.waited = false;
Ok(())
}
// Private helper
#[inline]
fn fp(&self) -> &raw::Instance {
self.session.instance().fp()
}
}
impl<G: Graphics> Drop for Swapchain<G> {
fn drop(&mut self) {
unsafe {
(self.fp().destroy_swapchain)(self.as_raw());
}
}
}