openxr rendering

This commit is contained in:
galister
2024-01-28 01:53:47 +01:00
parent 4aa52c1e67
commit 93125dd65e
7 changed files with 368 additions and 159 deletions

View File

@@ -1,7 +1,176 @@
pub struct OpenXrOverlayData {}
use std::sync::Arc;
impl Default for OpenXrOverlayData {
fn default() -> Self {
Self {}
use super::XrState;
use crate::{
backend::overlay::OverlayData,
graphics::{WlxPass, WlxPipeline},
shaders::{frag_srgb, vert_common},
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,
};
#[derive(Default)]
pub struct OpenXrOverlayData {
inner: Option<XrOverlayData>,
pub(super) init: bool,
}
impl OverlayData<OpenXrOverlayData> {
pub(super) fn initialize(&mut self, xr: &XrState, state: &mut AppState) {
let Some(my_view) = self.view() else {
log::error!("Failed to get view for overlay");
return;
};
self.data.inner = {
let extent = my_view.image().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 = 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 pipeline = state.graphics.create_pipeline(
view.clone(),
vert_common::load(state.graphics.device.clone()).unwrap(),
frag_srgb::load(state.graphics.device.clone()).unwrap(),
state.graphics.native_format,
);
let set = pipeline.uniform_sampler(0, my_view.clone(), Filter::Linear);
let pass = pipeline.create_pass(
[view.image().extent()[0] as _, view.image().extent()[1] as _],
state.graphics.quad_verts.clone(),
state.graphics.quad_indices.clone(),
vec![set],
);
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,
pass,
}
})
.collect();
Some(XrOverlayData {
swapchain,
framebuffers,
extent,
})
};
}
pub(super) fn present_xr(
&mut self,
xr: &XrState,
state: &mut AppState,
) -> Option<(xr::SwapchainSubImage<xr::Vulkan>, xr::Extent2Df)> {
if self.data.inner.is_none() {
self.initialize(xr, state);
return None;
}
let data = self.data.inner.as_mut().unwrap();
let idx = data.swapchain.acquire_image().unwrap();
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);
command_buffer.run_ref(&frame.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,
))
}
}
struct XrOverlayData {
swapchain: xr::Swapchain<xr::Vulkan>,
extent: [u32; 3],
framebuffers: Vec<XrFramebuffer>,
}
struct XrFramebuffer {
inner: Arc<Framebuffer>,
view: Arc<ImageView>,
pipeline: Arc<WlxPipeline>,
pass: WlxPass,
}