sbs 3d support
This commit is contained in:
@@ -1,19 +1,20 @@
|
||||
use glam::{Affine3A, Vec3, Vec3A};
|
||||
use idmap::IdMap;
|
||||
use openxr as xr;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
f32::consts::PI,
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
|
||||
use wgui::gfx::{
|
||||
WGfx,
|
||||
cmd::WGfxClearMode,
|
||||
pass::WGfxPass,
|
||||
pipeline::{WGfxPipeline, WPipelineCreateInfo},
|
||||
WGfx,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -27,8 +28,8 @@ use vulkano::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
swapchain::{create_swapchain, SwapchainOpts, WlxSwapchain},
|
||||
CompositionLayer, XrState,
|
||||
swapchain::{SwapchainOpts, WlxSwapchain, create_swapchain},
|
||||
};
|
||||
|
||||
static LINE_AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(1);
|
||||
@@ -156,7 +157,13 @@ impl LinePool {
|
||||
) -> anyhow::Result<()> {
|
||||
for line in self.lines.values_mut() {
|
||||
if let Some(inner) = line.maybe_line.as_mut() {
|
||||
let tgt = line.swapchain.acquire_wait_image()?;
|
||||
let tgt = line
|
||||
.swapchain
|
||||
.acquire_wait_image()?
|
||||
.views
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
self.buf_color.write()?[0..6].copy_from_slice(&COLORS[inner.color]);
|
||||
|
||||
@@ -167,7 +174,7 @@ impl LinePool {
|
||||
cmd_buffer.run_ref(&self.pass)?;
|
||||
cmd_buffer.end_rendering()?;
|
||||
|
||||
futures.execute((cmd_buffer.queue.clone(), cmd_buffer.build()?))?;
|
||||
futures.execute(cmd_buffer.queue.clone(), cmd_buffer.build()?)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,8 +184,8 @@ impl LinePool {
|
||||
pub(super) fn present<'a>(
|
||||
&'a mut self,
|
||||
xr: &'a XrState,
|
||||
) -> anyhow::Result<Vec<CompositionLayer<'a>>> {
|
||||
let mut quads = Vec::new();
|
||||
) -> anyhow::Result<SmallVec<[CompositionLayer<'a>; 2]>> {
|
||||
let mut quads = SmallVec::new_const();
|
||||
|
||||
for line in self.lines.values_mut() {
|
||||
line.swapchain.ensure_image_released()?;
|
||||
@@ -186,7 +193,7 @@ impl LinePool {
|
||||
if let Some(inner) = line.maybe_line.take() {
|
||||
let quad = xr::CompositionLayerQuad::new()
|
||||
.pose(inner.pose)
|
||||
.sub_image(line.swapchain.get_subimage())
|
||||
.sub_image(line.swapchain.get_subimage(0))
|
||||
.eye_visibility(xr::EyeVisibility::BOTH)
|
||||
.space(&xr.stage)
|
||||
.size(xr::Extent2Df {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
ops::Add,
|
||||
sync::{Arc, atomic::Ordering},
|
||||
sync::{atomic::Ordering, Arc},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
@@ -14,25 +14,25 @@ use vulkano::{Handle, VulkanObject};
|
||||
use wlx_common::overlays::ToastTopic;
|
||||
|
||||
use crate::{
|
||||
FRAME_COUNTER, RUNNING,
|
||||
backend::{
|
||||
BackendError,
|
||||
input::interact,
|
||||
openxr::{lines::LinePool, overlay::OpenXrOverlayData},
|
||||
task::{OverlayTask, TaskType},
|
||||
BackendError, XrBackend,
|
||||
},
|
||||
config::save_state,
|
||||
graphics::{GpuFutures, init_openxr_graphics},
|
||||
graphics::{init_openxr_graphics, GpuFutures},
|
||||
overlays::{
|
||||
toast::Toast,
|
||||
watch::{WATCH_NAME, watch_fade},
|
||||
watch::{watch_fade, WATCH_NAME},
|
||||
},
|
||||
state::AppState,
|
||||
subsystem::notifications::NotificationManager,
|
||||
windowing::{
|
||||
backend::{RenderResources, ShouldRender},
|
||||
backend::{RenderResources, RenderTarget, ShouldRender},
|
||||
manager::OverlayWindowManager,
|
||||
},
|
||||
FRAME_COUNTER, RUNNING,
|
||||
};
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
@@ -70,7 +70,7 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
||||
|
||||
let mut app = {
|
||||
let (gfx, gfx_extras) = init_openxr_graphics(xr_instance.clone(), system)?;
|
||||
AppState::from_graphics(gfx, gfx_extras)?
|
||||
AppState::from_graphics(gfx, gfx_extras, XrBackend::OpenXR)?
|
||||
};
|
||||
|
||||
let environment_blend_mode = {
|
||||
@@ -403,11 +403,12 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
||||
|
||||
if should_render {
|
||||
let meta = o.config.backend.frame_meta().unwrap(); // want panic
|
||||
let tgt = o.ensure_swapchain_acquire(&app, &xr_state, meta.extent)?;
|
||||
let wsi = o.ensure_swapchain_acquire(&app, &xr_state, meta.extent)?;
|
||||
let tgt = RenderTarget { views: wsi.views };
|
||||
let mut rdr = RenderResources::new(app.gfx.clone(), tgt, &meta, alpha)?;
|
||||
o.render(&mut app, &mut rdr)?;
|
||||
o.data.last_alpha = alpha;
|
||||
futures.execute(rdr.end()?)?;
|
||||
futures.execute_results(rdr.end()?)?;
|
||||
} else if o.data.swapchain.is_none() {
|
||||
continue;
|
||||
}
|
||||
@@ -439,18 +440,13 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
||||
o.data.swapchain.as_mut().unwrap().ensure_image_released()?;
|
||||
continue;
|
||||
}
|
||||
let maybe_layer = o.present(&xr_state)?;
|
||||
if matches!(maybe_layer, CompositionLayer::None) {
|
||||
continue;
|
||||
for layer in o.present(&xr_state)? {
|
||||
layers.push((dist_sq, layer));
|
||||
}
|
||||
layers.push((dist_sq, maybe_layer));
|
||||
}
|
||||
|
||||
for maybe_layer in lines.present(&xr_state)? {
|
||||
if matches!(maybe_layer, CompositionLayer::None) {
|
||||
continue;
|
||||
}
|
||||
layers.push((0.0, maybe_layer));
|
||||
for layer in lines.present(&xr_state)? {
|
||||
layers.push((0.0, layer));
|
||||
}
|
||||
// End layer composition
|
||||
|
||||
@@ -468,7 +464,6 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
||||
CompositionLayer::Quad(ref l) => l as &xr::CompositionLayerBase<xr::Vulkan>,
|
||||
CompositionLayer::Cylinder(ref l) => l as &xr::CompositionLayerBase<xr::Vulkan>,
|
||||
CompositionLayer::Equirect2(ref l) => l as &xr::CompositionLayerBase<xr::Vulkan>,
|
||||
CompositionLayer::None => unreachable!(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -523,7 +518,6 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
||||
}
|
||||
|
||||
pub(super) enum CompositionLayer<'a> {
|
||||
None,
|
||||
Quad(xr::CompositionLayerQuad<'a, xr::Vulkan>),
|
||||
Cylinder(xr::CompositionLayerCylinderKHR<'a, xr::Vulkan>),
|
||||
Equirect2(xr::CompositionLayerEquirect2KHR<'a, xr::Vulkan>),
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use glam::Vec3A;
|
||||
use openxr::{self as xr, CompositionLayerFlags};
|
||||
use std::{f32::consts::PI, sync::Arc};
|
||||
use vulkano::image::view::ImageView;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::f32::consts::PI;
|
||||
use xr::EyeVisibility;
|
||||
|
||||
use super::{CompositionLayer, XrState, helpers, swapchain::WlxSwapchain};
|
||||
use super::{helpers, swapchain::WlxSwapchain, CompositionLayer, XrState};
|
||||
use crate::{
|
||||
backend::openxr::swapchain::{SwapchainOpts, create_swapchain},
|
||||
backend::openxr::swapchain::{create_swapchain, SwapchainOpts, WlxSwapchainImage},
|
||||
state::AppState,
|
||||
windowing::window::OverlayWindowData,
|
||||
};
|
||||
@@ -26,7 +26,7 @@ impl OverlayWindowData<OpenXrOverlayData> {
|
||||
app: &AppState,
|
||||
xr: &'a XrState,
|
||||
extent: [u32; 3],
|
||||
) -> anyhow::Result<Arc<ImageView>> {
|
||||
) -> anyhow::Result<WlxSwapchainImage> {
|
||||
if let Some(swapchain) = self.data.swapchain.as_mut()
|
||||
&& swapchain.extent == extent
|
||||
{
|
||||
@@ -34,10 +34,11 @@ impl OverlayWindowData<OpenXrOverlayData> {
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
"{}: recreating swapchain at {}x{}",
|
||||
"{}: recreating swapchain at {}x{}x{}",
|
||||
self.config.name,
|
||||
extent[0],
|
||||
extent[1],
|
||||
extent[2],
|
||||
);
|
||||
let mut swapchain = create_swapchain(xr, app.gfx.clone(), extent, SwapchainOpts::new())?;
|
||||
let tgt = swapchain.acquire_wait_image()?;
|
||||
@@ -48,21 +49,31 @@ impl OverlayWindowData<OpenXrOverlayData> {
|
||||
pub(super) fn present<'a>(
|
||||
&'a mut self,
|
||||
xr: &'a XrState,
|
||||
) -> anyhow::Result<CompositionLayer<'a>> {
|
||||
) -> anyhow::Result<SmallVec<[CompositionLayer<'a>; 2]>> {
|
||||
let mut layers = SmallVec::new_const();
|
||||
|
||||
let Some(swapchain) = self.data.swapchain.as_mut() else {
|
||||
log::warn!("{}: swapchain not ready", self.config.name);
|
||||
return Ok(CompositionLayer::None);
|
||||
log::trace!("{}: no swapchain", self.config.name);
|
||||
return Ok(layers);
|
||||
};
|
||||
if !swapchain.ever_acquired {
|
||||
log::warn!("{}: swapchain not rendered", self.config.name);
|
||||
return Ok(CompositionLayer::None);
|
||||
return Ok(layers);
|
||||
}
|
||||
swapchain.ensure_image_released()?;
|
||||
|
||||
// overlays without active_state don't get queued for present
|
||||
let state = self.config.active_state.as_ref().unwrap();
|
||||
|
||||
let sub_image = swapchain.get_subimage();
|
||||
let sub_images: SmallVec<[_; 2]> = if swapchain.extent[2] > 1 {
|
||||
smallvec![
|
||||
(swapchain.get_subimage(0), EyeVisibility::LEFT),
|
||||
(swapchain.get_subimage(1), EyeVisibility::RIGHT),
|
||||
]
|
||||
} else {
|
||||
smallvec![(swapchain.get_subimage(0), EyeVisibility::BOTH),]
|
||||
};
|
||||
|
||||
let transform = state.transform * self.config.backend.frame_meta().unwrap().transform; // contract
|
||||
|
||||
let aspect_ratio = swapchain.extent[1] as f32 / swapchain.extent[0] as f32;
|
||||
@@ -89,30 +100,35 @@ impl OverlayWindowData<OpenXrOverlayData> {
|
||||
let posef = helpers::translation_rotation_to_posef(center_point, quat);
|
||||
let angle = 2.0 * (scale_x / (2.0 * radius));
|
||||
|
||||
let cylinder = xr::CompositionLayerCylinderKHR::new()
|
||||
.layer_flags(flags)
|
||||
.pose(posef)
|
||||
.sub_image(sub_image)
|
||||
.eye_visibility(EyeVisibility::BOTH)
|
||||
.space(&xr.stage)
|
||||
.radius(radius)
|
||||
.central_angle(angle)
|
||||
.aspect_ratio(aspect_ratio);
|
||||
Ok(CompositionLayer::Cylinder(cylinder))
|
||||
for sub_image in sub_images {
|
||||
let cylinder = xr::CompositionLayerCylinderKHR::new()
|
||||
.layer_flags(flags)
|
||||
.pose(posef)
|
||||
.sub_image(sub_image.0)
|
||||
.eye_visibility(sub_image.1)
|
||||
.space(&xr.stage)
|
||||
.radius(radius)
|
||||
.central_angle(angle)
|
||||
.aspect_ratio(aspect_ratio);
|
||||
layers.push(CompositionLayer::Cylinder(cylinder))
|
||||
}
|
||||
} else {
|
||||
let posef = helpers::transform_to_posef(&transform);
|
||||
let quad = xr::CompositionLayerQuad::new()
|
||||
.layer_flags(flags)
|
||||
.pose(posef)
|
||||
.sub_image(sub_image)
|
||||
.eye_visibility(EyeVisibility::BOTH)
|
||||
.space(&xr.stage)
|
||||
.size(xr::Extent2Df {
|
||||
width: scale_x,
|
||||
height: scale_y,
|
||||
});
|
||||
Ok(CompositionLayer::Quad(quad))
|
||||
for sub_image in sub_images {
|
||||
let quad = xr::CompositionLayerQuad::new()
|
||||
.layer_flags(flags)
|
||||
.pose(posef)
|
||||
.sub_image(sub_image.0)
|
||||
.eye_visibility(sub_image.1)
|
||||
.space(&xr.stage)
|
||||
.size(xr::Extent2Df {
|
||||
width: scale_x,
|
||||
height: scale_y,
|
||||
});
|
||||
layers.push(CompositionLayer::Quad(quad))
|
||||
}
|
||||
}
|
||||
Ok(layers)
|
||||
}
|
||||
|
||||
pub(super) fn after_input(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
|
||||
@@ -15,13 +15,13 @@ use wgui::gfx::{cmd::WGfxClearMode, pipeline::WPipelineCreateInfo};
|
||||
use crate::{
|
||||
backend::openxr::{helpers::translation_rotation_to_posef, swapchain::SwapchainOpts},
|
||||
config_io,
|
||||
graphics::{ExtentExt, GpuFutures, dds::WlxCommandBufferDds},
|
||||
graphics::{dds::WlxCommandBufferDds, ExtentExt, GpuFutures},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
use super::{
|
||||
swapchain::{create_swapchain, WlxSwapchain},
|
||||
CompositionLayer, XrState,
|
||||
swapchain::{WlxSwapchain, create_swapchain},
|
||||
};
|
||||
|
||||
pub(super) struct Skybox {
|
||||
@@ -94,7 +94,12 @@ impl Skybox {
|
||||
|
||||
let extent = self.view.image().extent();
|
||||
let mut swapchain = create_swapchain(xr, app.gfx.clone(), extent, opts)?;
|
||||
let tgt = swapchain.acquire_wait_image()?;
|
||||
let tgt = swapchain
|
||||
.acquire_wait_image()?
|
||||
.views
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
let pipeline = app.gfx.create_pipeline(
|
||||
app.gfx_extras.shaders.get("vert_quad").unwrap(), // want panic
|
||||
app.gfx_extras.shaders.get("frag_srgb").unwrap(), // want panic
|
||||
@@ -119,7 +124,7 @@ impl Skybox {
|
||||
cmd_buffer.run_ref(&pass)?;
|
||||
cmd_buffer.end_rendering()?;
|
||||
|
||||
futures.execute((cmd_buffer.queue.clone(), cmd_buffer.build()?))?;
|
||||
futures.execute(cmd_buffer.queue.clone(), cmd_buffer.build()?)?;
|
||||
|
||||
self.sky = Some(swapchain);
|
||||
Ok(())
|
||||
@@ -148,7 +153,12 @@ impl Skybox {
|
||||
WPipelineCreateInfo::new(app.gfx.surface_format).use_blend(AttachmentBlend::alpha()),
|
||||
)?;
|
||||
|
||||
let tgt = swapchain.acquire_wait_image()?;
|
||||
let tgt = swapchain
|
||||
.acquire_wait_image()?
|
||||
.views
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
let pass = pipeline.create_pass(
|
||||
tgt.extent_f32(),
|
||||
app.gfx_extras.quad_verts.clone(),
|
||||
@@ -165,7 +175,7 @@ impl Skybox {
|
||||
cmd_buffer.run_ref(&pass)?;
|
||||
cmd_buffer.end_rendering()?;
|
||||
|
||||
futures.execute((cmd_buffer.queue.clone(), cmd_buffer.build()?))?;
|
||||
futures.execute(cmd_buffer.queue.clone(), cmd_buffer.build()?)?;
|
||||
|
||||
self.grid = Some(swapchain);
|
||||
Ok(())
|
||||
@@ -211,7 +221,7 @@ impl Skybox {
|
||||
.layer_flags(xr::CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA)
|
||||
.pose(pose)
|
||||
.radius(10.0)
|
||||
.sub_image(self.sky.as_ref().unwrap().get_subimage())
|
||||
.sub_image(self.sky.as_ref().unwrap().get_subimage(0))
|
||||
.eye_visibility(xr::EyeVisibility::BOTH)
|
||||
.space(&xr.stage)
|
||||
.central_horizontal_angle(HORIZ_ANGLE)
|
||||
@@ -226,7 +236,7 @@ impl Skybox {
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
})
|
||||
.sub_image(self.grid.as_ref().unwrap().get_subimage())
|
||||
.sub_image(self.grid.as_ref().unwrap().get_subimage(0))
|
||||
.eye_visibility(xr::EyeVisibility::BOTH)
|
||||
.space(&xr.stage);
|
||||
|
||||
|
||||
@@ -5,8 +5,12 @@ use openxr as xr;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use vulkano::{
|
||||
image::{
|
||||
sys::RawImage,
|
||||
view::{ImageView, ImageViewCreateInfo},
|
||||
ImageCreateInfo, ImageUsage,
|
||||
},
|
||||
Handle,
|
||||
image::{ImageCreateInfo, ImageUsage, sys::RawImage, view::ImageView},
|
||||
};
|
||||
use wgui::gfx::WGfx;
|
||||
|
||||
@@ -47,7 +51,7 @@ pub(super) fn create_swapchain(
|
||||
width: extent[0],
|
||||
height: extent[1],
|
||||
face_count: 1,
|
||||
array_size: 1,
|
||||
array_size: extent[2],
|
||||
mip_count: 1,
|
||||
})?;
|
||||
|
||||
@@ -63,7 +67,8 @@ pub(super) fn create_swapchain(
|
||||
vk_image,
|
||||
ImageCreateInfo {
|
||||
format: gfx.surface_format as _,
|
||||
extent,
|
||||
extent: [extent[0], extent[1], 1],
|
||||
array_layers: extent[2],
|
||||
usage: ImageUsage::COLOR_ATTACHMENT,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -71,9 +76,15 @@ pub(super) fn create_swapchain(
|
||||
};
|
||||
// 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)?)
|
||||
let mut wsi = WlxSwapchainImage::default();
|
||||
for d in 0..extent[2] {
|
||||
let mut create_info = ImageViewCreateInfo::from_image(&*image);
|
||||
create_info.subresource_range.array_layers = d..d + 1;
|
||||
wsi.views.push(ImageView::new(image.clone(), create_info)?);
|
||||
}
|
||||
Ok(wsi)
|
||||
})
|
||||
.collect::<anyhow::Result<SmallVec<[Arc<ImageView>; 4]>>>()?;
|
||||
.collect::<anyhow::Result<SmallVec<[WlxSwapchainImage; 4]>>>()?;
|
||||
|
||||
Ok(WlxSwapchain {
|
||||
acquired: false,
|
||||
@@ -84,16 +95,21 @@ pub(super) fn create_swapchain(
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub(super) struct WlxSwapchainImage {
|
||||
pub views: SmallVec<[Arc<ImageView>; 2]>,
|
||||
}
|
||||
|
||||
pub(super) struct WlxSwapchain {
|
||||
acquired: bool,
|
||||
pub(super) ever_acquired: bool,
|
||||
pub(super) swapchain: xr::Swapchain<xr::Vulkan>,
|
||||
pub(super) extent: [u32; 3],
|
||||
pub(super) images: SmallVec<[Arc<ImageView>; 4]>,
|
||||
pub(super) images: SmallVec<[WlxSwapchainImage; 4]>,
|
||||
}
|
||||
|
||||
impl WlxSwapchain {
|
||||
pub(super) fn acquire_wait_image(&mut self) -> anyhow::Result<Arc<ImageView>> {
|
||||
pub(super) fn acquire_wait_image(&mut self) -> anyhow::Result<WlxSwapchainImage> {
|
||||
let idx = self.swapchain.acquire_image()? as usize;
|
||||
self.swapchain.wait_image(xr::Duration::INFINITE)?;
|
||||
self.ever_acquired = true;
|
||||
@@ -109,7 +125,7 @@ impl WlxSwapchain {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn get_subimage(&self) -> xr::SwapchainSubImage<'_, xr::Vulkan> {
|
||||
pub(super) fn get_subimage(&self, array_index: u32) -> xr::SwapchainSubImage<'_, xr::Vulkan> {
|
||||
debug_assert!(self.ever_acquired, "swapchain was never acquired!");
|
||||
xr::SwapchainSubImage::new()
|
||||
.swapchain(&self.swapchain)
|
||||
@@ -120,6 +136,6 @@ impl WlxSwapchain {
|
||||
height: self.extent[1] as _,
|
||||
},
|
||||
})
|
||||
.image_array_index(0)
|
||||
.image_array_index(array_index)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user