use std::sync::Arc; use ash::vk; use openxr as xr; use smallvec::SmallVec; use vulkano::{ image::{sampler::Filter, sys::RawImage, view::ImageView, ImageCreateInfo, ImageUsage}, Handle, }; use crate::graphics::{WlxCommandBuffer, WlxGraphics, WlxPipeline, WlxPipelineDynamic}; use super::XrState; pub(super) fn create_swapchain_render_data( xr: &XrState, graphics: Arc, extent: [u32; 3], ) -> anyhow::Result { let swapchain = xr.session.create_swapchain(&xr::SwapchainCreateInfo { create_flags: xr::SwapchainCreateFlags::EMPTY, usage_flags: xr::SwapchainUsageFlags::COLOR_ATTACHMENT | xr::SwapchainUsageFlags::SAMPLED, format: graphics.native_format as _, sample_count: 1, width: extent[0], height: extent[1], face_count: 1, array_size: 1, mip_count: 1, })?; let shaders = graphics.shared_shaders.read().unwrap(); let pipeline = graphics.create_pipeline_dynamic( shaders.get("vert_common").unwrap().clone(), shaders.get("frag_srgb").unwrap().clone(), graphics.native_format, ); let images = swapchain .enumerate_images() .unwrap() .into_iter() .map(|handle| { let vk_image = vk::Image::from_raw(handle); // thanks @yshui let raw_image = unsafe { RawImage::from_handle( graphics.device.clone(), vk_image, ImageCreateInfo { format: graphics.native_format, extent, usage: ImageUsage::COLOR_ATTACHMENT, ..Default::default() }, )? }; // SAFETY: OpenXR guarantees that the image is a swapchain image, thus has memory backing it. let image = Arc::new(unsafe { raw_image.assume_bound() }); Ok(ImageView::new_default(image)?) }) .collect::; 4]>>>()?; Ok(SwapchainRenderData { swapchain, pipeline, images, extent, }) } pub(super) struct SwapchainRenderData { pub(super) swapchain: xr::Swapchain, pub(super) pipeline: Arc>, pub(super) extent: [u32; 3], pub(super) images: SmallVec<[Arc; 4]>, } impl SwapchainRenderData { pub(super) fn acquire_present_release( &mut self, command_buffer: &mut WlxCommandBuffer, view: Arc, alpha: f32, ) -> Result, xr::sys::Result> { let idx = self.swapchain.acquire_image()? as usize; self.swapchain.wait_image(xr::Duration::INFINITE)?; let render_target = &mut self.images[idx]; command_buffer.begin_rendering(render_target.clone()); let target_extent = render_target.image().extent(); let set0 = self .pipeline .uniform_sampler(0, view.clone(), Filter::Linear); let set1 = self.pipeline.uniform_buffer(1, vec![alpha]); let pass = self.pipeline.create_pass( [target_extent[0] as _, target_extent[1] as _], command_buffer.graphics.quad_verts.clone(), command_buffer.graphics.quad_indices.clone(), vec![set0, set1], ); command_buffer.run_ref(&pass); command_buffer.end_rendering(); self.swapchain.release_image()?; Ok(xr::SwapchainSubImage::new() .swapchain(&self.swapchain) .image_rect(xr::Rect2Di { offset: xr::Offset2Di { x: 0, y: 0 }, extent: xr::Extent2Di { width: target_extent[0] as _, height: target_extent[1] as _, }, }) .image_array_index(0)) } }