openxr lasers

This commit is contained in:
galister
2024-01-28 17:15:50 +01:00
parent d66d39066c
commit e1e8165cc6
8 changed files with 380 additions and 198 deletions

View File

@@ -1,29 +1,27 @@
use std::sync::Arc;
use super::XrState;
use crate::{backend::overlay::OverlayData, graphics::WlxPipeline, state::AppState};
use ash::vk::{self};
use openxr as xr;
use vulkano::{
command_buffer::CommandBufferUsage,
image::{sampler::Filter, view::ImageView, ImageCreateInfo, ImageUsage},
render_pass::{Framebuffer, FramebufferCreateInfo},
Handle,
use std::sync::Arc;
use xr::{CompositionLayerFlags, EyeVisibility};
use super::{swapchain::SwapchainRenderData, transform_to_posef, XrState};
use crate::{
backend::{openxr::swapchain::create_swapchain_render_data, overlay::OverlayData},
graphics::WlxCommandBuffer,
};
use vulkano::image::view::ImageView;
#[derive(Default)]
pub struct OpenXrOverlayData {
last_view: Option<Arc<ImageView>>,
inner: Option<XrOverlayData>,
pub(super) swapchain: Option<SwapchainRenderData>,
pub(super) init: bool,
}
impl OverlayData<OpenXrOverlayData> {
pub(super) fn present_xr(
&mut self,
xr: &XrState,
state: &mut AppState,
) -> Option<(xr::SwapchainSubImage<xr::Vulkan>, xr::Extent2Df)> {
pub(super) fn present_xr<'a>(
&'a mut self,
xr: &'a XrState,
command_buffer: &mut WlxCommandBuffer,
) -> Option<xr::CompositionLayerQuad<xr::Vulkan>> {
if let Some(new_view) = self.view() {
self.data.last_view = Some(new_view);
}
@@ -35,152 +33,35 @@ impl OverlayData<OpenXrOverlayData> {
return None;
};
let data = self.data.inner.get_or_insert_with(|| {
let data = self.data.swapchain.get_or_insert_with(|| {
let extent = self.backend.extent();
let swapchain = xr
.session
.create_swapchain(&xr::SwapchainCreateInfo {
create_flags: xr::SwapchainCreateFlags::EMPTY,
usage_flags: xr::SwapchainUsageFlags::COLOR_ATTACHMENT
| xr::SwapchainUsageFlags::SAMPLED,
format: state.graphics.native_format as _,
sample_count: 1,
width: extent[0],
height: extent[1],
face_count: 1,
array_size: 1,
mip_count: 1,
})
.unwrap();
let framebuffers: Vec<XrFramebuffer> = swapchain
.enumerate_images()
.unwrap()
.into_iter()
.map(|handle| {
let vk_image = vk::Image::from_raw(handle);
// thanks @yshui
let raw_image = unsafe {
vulkano::image::sys::RawImage::from_handle(
state.graphics.device.clone(),
vk_image,
ImageCreateInfo {
format: state.graphics.native_format,
extent,
usage: ImageUsage::COLOR_ATTACHMENT | ImageUsage::TRANSFER_DST,
..Default::default()
},
)
.unwrap()
};
// SAFETY: OpenXR guarantees that the image is a swapchain image, thus has memory backing it.
let image = Arc::new(unsafe { raw_image.assume_bound() });
let view = ImageView::new_default(image).unwrap();
// HACK: maybe not create one pipeline per image?
let shaders = state.graphics.shared_shaders.read().unwrap();
let pipeline = state.graphics.create_pipeline(
view.clone(),
shaders.get("vert_common").unwrap().clone(),
shaders.get("frag_srgb").unwrap().clone(),
state.graphics.native_format,
);
let inner = Framebuffer::new(
pipeline.render_pass.clone(),
FramebufferCreateInfo {
attachments: vec![view.clone()],
extent: [view.image().extent()[0] as _, view.image().extent()[1] as _],
layers: 1,
..Default::default()
},
)
.unwrap();
XrFramebuffer {
inner,
view,
pipeline,
}
})
.collect();
let srd = create_swapchain_render_data(xr, command_buffer.graphics.clone(), extent);
log::info!(
"{}: Created swapchain {}x{}, {} images, {} MB",
self.state.name,
extent[0],
extent[1],
framebuffers.len(),
extent[0] * extent[1] * 4 * framebuffers.len() as u32 / 1024 / 1024
srd.images.len(),
extent[0] * extent[1] * 4 * srd.images.len() as u32 / 1024 / 1024
);
XrOverlayData {
swapchain,
framebuffers,
extent,
}
srd
});
let idx = data.swapchain.acquire_image().unwrap();
let sub_image = data.acquire_present_release(command_buffer, my_view);
let posef = transform_to_posef(&self.state.transform);
data.swapchain.wait_image(xr::Duration::INFINITE).unwrap();
let frame = &data.framebuffers[idx as usize];
let mut command_buffer = state
.graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
.begin_render_pass(&frame.pipeline);
let set = frame
.pipeline
.uniform_sampler(0, my_view.clone(), Filter::Linear);
let pass = frame.pipeline.create_pass(
[
my_view.image().extent()[0] as _,
my_view.image().extent()[1] as _,
],
state.graphics.quad_verts.clone(),
state.graphics.quad_indices.clone(),
vec![set],
);
command_buffer.run_ref(&pass);
command_buffer.end_render_pass().build_and_execute_now();
data.swapchain.release_image().unwrap();
let extent = xr::Extent2Df {
width: self.state.width,
height: (data.extent[1] as f32 / data.extent[0] as f32) * self.state.width,
};
Some((
xr::SwapchainSubImage::new()
.swapchain(&data.swapchain)
.image_rect(xr::Rect2Di {
offset: xr::Offset2Di { x: 0, y: 0 },
extent: xr::Extent2Di {
width: data.extent[0] as _,
height: data.extent[1] as _,
},
})
.image_array_index(0),
extent,
))
let quad = xr::CompositionLayerQuad::new()
.pose(posef)
.sub_image(sub_image)
.eye_visibility(EyeVisibility::BOTH)
.layer_flags(CompositionLayerFlags::CORRECT_CHROMATIC_ABERRATION)
.space(&xr.stage)
.size(xr::Extent2Df {
width: self.state.width,
height: (self.backend.extent()[1] as f32 / self.backend.extent()[0] as f32)
* self.state.width,
});
Some(quad)
}
}
struct XrOverlayData {
swapchain: xr::Swapchain<xr::Vulkan>,
extent: [u32; 3],
framebuffers: Vec<XrFramebuffer>,
}
struct XrFramebuffer {
inner: Arc<Framebuffer>,
view: Arc<ImageView>,
pipeline: Arc<WlxPipeline>,
}