fix openxr screen freeze

This commit is contained in:
galister
2024-01-28 13:08:57 +01:00
parent f96083e770
commit 335652ecb1
6 changed files with 91 additions and 59 deletions

View File

@@ -127,4 +127,7 @@ impl OverlayRenderer for StaticRenderer {
fn view(&mut self) -> Option<Arc<ImageView>> { fn view(&mut self) -> Option<Arc<ImageView>> {
Some(self.view.clone()) Some(self.view.clone())
} }
fn extent(&self) -> [u32; 3] {
self.view.image().extent().clone()
}
} }

View File

@@ -1,11 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use super::XrState; use super::XrState;
use crate::{ use crate::{backend::overlay::OverlayData, graphics::WlxPipeline, state::AppState};
backend::overlay::OverlayData,
graphics::{WlxPass, WlxPipeline},
state::AppState,
};
use ash::vk::{self}; use ash::vk::{self};
use openxr as xr; use openxr as xr;
use vulkano::{ use vulkano::{
@@ -17,25 +13,30 @@ use vulkano::{
#[derive(Default)] #[derive(Default)]
pub struct OpenXrOverlayData { pub struct OpenXrOverlayData {
last_view: Option<Arc<ImageView>>,
inner: Option<XrOverlayData>, inner: Option<XrOverlayData>,
pub(super) init: bool, pub(super) init: bool,
} }
impl OverlayData<OpenXrOverlayData> { impl OverlayData<OpenXrOverlayData> {
pub(super) fn initialize(&mut self, xr: &XrState, state: &mut AppState) { pub(super) fn present_xr(
let Some(my_view) = self.view() else { &mut self,
log::error!("Failed to get view for overlay"); xr: &XrState,
return; state: &mut AppState,
) -> Option<(xr::SwapchainSubImage<xr::Vulkan>, xr::Extent2Df)> {
if let Some(new_view) = self.view() {
self.data.last_view = Some(new_view);
}
let my_view = if let Some(view) = self.data.last_view.as_ref() {
view.clone()
} else {
log::warn!("{}: Will not show - image not ready", self.state.name);
return None;
}; };
self.data.inner = { let data = self.data.inner.get_or_insert_with(|| {
let extent = my_view.image().extent(); let extent = self.backend.extent();
log::info!(
"{}: Create swapchain {}x{}",
self.state.name,
extent[0],
extent[1]
);
let swapchain = xr let swapchain = xr
.session .session
@@ -53,7 +54,7 @@ impl OverlayData<OpenXrOverlayData> {
}) })
.unwrap(); .unwrap();
let framebuffers = swapchain let framebuffers: Vec<XrFramebuffer> = swapchain
.enumerate_images() .enumerate_images()
.unwrap() .unwrap()
.into_iter() .into_iter()
@@ -87,13 +88,6 @@ impl OverlayData<OpenXrOverlayData> {
shaders.get("frag_srgb").unwrap().clone(), shaders.get("frag_srgb").unwrap().clone(),
state.graphics.native_format, 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( let inner = Framebuffer::new(
pipeline.render_pass.clone(), pipeline.render_pass.clone(),
@@ -110,30 +104,25 @@ impl OverlayData<OpenXrOverlayData> {
inner, inner,
view, view,
pipeline, pipeline,
pass,
} }
}) })
.collect(); .collect();
Some(XrOverlayData { log::info!(
"{}: Created swapchain {}x{} depth: {}, {} MB",
self.state.name,
extent[0],
extent[1],
framebuffers.len(),
extent[0] * extent[1] * 4 * framebuffers.len() as u32 / 1024 / 1024
);
XrOverlayData {
swapchain, swapchain,
framebuffers, framebuffers,
extent, 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(); let idx = data.swapchain.acquire_image().unwrap();
@@ -144,7 +133,21 @@ impl OverlayData<OpenXrOverlayData> {
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit) .create_command_buffer(CommandBufferUsage::OneTimeSubmit)
.begin_render_pass(&frame.pipeline); .begin_render_pass(&frame.pipeline);
command_buffer.run_ref(&frame.pass);
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(); command_buffer.end_render_pass().build_and_execute_now();
data.swapchain.release_image().unwrap(); data.swapchain.release_image().unwrap();
@@ -180,5 +183,4 @@ struct XrFramebuffer {
inner: Arc<Framebuffer>, inner: Arc<Framebuffer>,
view: Arc<ImageView>, view: Arc<ImageView>,
pipeline: Arc<WlxPipeline>, pipeline: Arc<WlxPipeline>,
pass: WlxPass,
} }

View File

@@ -150,6 +150,7 @@ pub trait OverlayRenderer {
fn resume(&mut self, app: &mut AppState); fn resume(&mut self, app: &mut AppState);
fn render(&mut self, app: &mut AppState); fn render(&mut self, app: &mut AppState);
fn view(&mut self) -> Option<Arc<ImageView>>; fn view(&mut self) -> Option<Arc<ImageView>>;
fn extent(&self) -> [u32; 3];
} }
pub struct FallbackRenderer; pub struct FallbackRenderer;
@@ -162,6 +163,9 @@ impl OverlayRenderer for FallbackRenderer {
fn view(&mut self) -> Option<Arc<ImageView>> { fn view(&mut self) -> Option<Arc<ImageView>> {
None None
} }
fn extent(&self) -> [u32; 3] {
[0, 0, 0]
}
} }
// Boilerplate and dummies // Boilerplate and dummies
@@ -204,6 +208,9 @@ impl OverlayRenderer for SplitOverlayBackend {
fn view(&mut self) -> Option<Arc<ImageView>> { fn view(&mut self) -> Option<Arc<ImageView>> {
self.renderer.view() self.renderer.view()
} }
fn extent(&self) -> [u32; 3] {
self.renderer.extent()
}
} }
impl InteractionHandler for SplitOverlayBackend { impl InteractionHandler for SplitOverlayBackend {
fn on_left(&mut self, app: &mut AppState, pointer: usize) { fn on_left(&mut self, app: &mut AppState, pointer: usize) {

View File

@@ -462,6 +462,9 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
fn view(&mut self) -> Option<Arc<ImageView>> { fn view(&mut self) -> Option<Arc<ImageView>> {
Some(self.view_final.clone()) Some(self.view_final.clone())
} }
fn extent(&self) -> [u32; 3] {
self.view_final.image().extent().clone()
}
} }
impl<D, S> OverlayBackend for Canvas<D, S> {} impl<D, S> OverlayBackend for Canvas<D, S> {}

View File

@@ -112,17 +112,13 @@ struct ScreenPipeline {
} }
impl ScreenPipeline { impl ScreenPipeline {
fn new(graphics: Arc<WlxGraphics>, image: &Image) -> Self { fn new(graphics: Arc<WlxGraphics>, image: &Image, extent: &[u32; 3]) -> Self {
let dim = image.extent(); let dim = image.extent();
let vertex_buffer = let vertex_buffer =
graphics.upload_verts(dim[0] as _, dim[1] as _, 0.0, 0.0, dim[0] as _, dim[1] as _); graphics.upload_verts(dim[0] as _, dim[1] as _, 0.0, 0.0, dim[0] as _, dim[1] as _);
// TODO make this a setting let render_texture = graphics.render_texture(extent[0], extent[1], Format::R8G8B8A8_UNORM);
let render_w = dim[0].min(1920);
let render_h = (dim[1] as f32 / dim[0] as f32 * render_w as f32) as u32;
let render_texture = graphics.render_texture(render_w, render_h, Format::R8G8B8A8_UNORM);
let view = ImageView::new_default(render_texture).unwrap(); let view = ImageView::new_default(render_texture).unwrap();
@@ -204,10 +200,12 @@ impl ScreenPipeline {
} }
pub struct ScreenRenderer { pub struct ScreenRenderer {
name: Arc<str>,
capture: Box<dyn WlxCapture>, capture: Box<dyn WlxCapture>,
receiver: Option<Receiver<WlxFrame>>, receiver: Option<Receiver<WlxFrame>>,
pipeline: Option<ScreenPipeline>, pipeline: Option<ScreenPipeline>,
last_image: Option<Arc<ImageView>>, last_image: Option<Arc<ImageView>>,
extent: [u32; 3],
} }
impl ScreenRenderer { impl ScreenRenderer {
@@ -216,11 +214,14 @@ impl ScreenRenderer {
return None; return None;
}; };
let capture = WlrDmabufCapture::new(client, output.id); let capture = WlrDmabufCapture::new(client, output.id);
Some(ScreenRenderer { Some(ScreenRenderer {
name: output.name.clone(),
capture: Box::new(capture), capture: Box::new(capture),
receiver: None, receiver: None,
pipeline: None, pipeline: None,
last_image: None, last_image: None,
extent: extent_from_res(output.size),
}) })
} }
@@ -235,16 +236,21 @@ impl ScreenRenderer {
let capture = PipewireCapture::new(name, node_id, 60); let capture = PipewireCapture::new(name, node_id, 60);
Some(ScreenRenderer { Some(ScreenRenderer {
name: output.name.clone(),
capture: Box::new(capture), capture: Box::new(capture),
receiver: None, receiver: None,
pipeline: None, pipeline: None,
last_image: None, last_image: None,
extent: extent_from_res(output.size),
}) })
} }
} }
impl OverlayRenderer for ScreenRenderer { impl OverlayRenderer for ScreenRenderer {
fn init(&mut self, _app: &mut AppState) {} fn init(&mut self, app: &mut AppState) {
let images = app.graphics.shared_images.read().unwrap();
self.last_image = Some(images.get("fallback").unwrap().clone());
}
fn render(&mut self, app: &mut AppState) { fn render(&mut self, app: &mut AppState) {
let receiver = self.receiver.get_or_insert_with(|| self.capture.init()); let receiver = self.receiver.get_or_insert_with(|| self.capture.init());
@@ -256,10 +262,10 @@ impl OverlayRenderer for ScreenRenderer {
continue; continue;
} }
if let Some(new) = app.graphics.dmabuf_texture(frame) { if let Some(new) = app.graphics.dmabuf_texture(frame) {
let pipeline = self let pipeline = self.pipeline.get_or_insert_with(|| {
.pipeline ScreenPipeline::new(app.graphics.clone(), &new, &self.extent)
.get_or_insert_with(|| ScreenPipeline::new(app.graphics.clone(), &new)); });
log::info!("New frame"); log::debug!("{}: New DMA-buf frame", self.name);
pipeline.render(new); pipeline.render(new);
self.last_image = Some(pipeline.view()); self.last_image = Some(pipeline.view());
} }
@@ -273,6 +279,7 @@ impl OverlayRenderer for ScreenRenderer {
log::error!("No fd"); log::error!("No fd");
continue; continue;
}; };
log::debug!("{}: New MemFd frame", self.name);
let format = fourcc_to_vk(frame.format.fourcc); let format = fourcc_to_vk(frame.format.fourcc);
let len = frame.plane.stride as usize * frame.format.height as usize; let len = frame.plane.stride as usize * frame.format.height as usize;
@@ -300,6 +307,7 @@ impl OverlayRenderer for ScreenRenderer {
self.last_image = Some(ImageView::new_default(image).unwrap()); self.last_image = Some(ImageView::new_default(image).unwrap());
} }
WlxFrame::MemPtr(frame) => { WlxFrame::MemPtr(frame) => {
log::debug!("{}: New MemPtr frame", self.name);
let mut upload = app let mut upload = app
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit); .create_command_buffer(CommandBufferUsage::OneTimeSubmit);
@@ -328,6 +336,9 @@ impl OverlayRenderer for ScreenRenderer {
fn view(&mut self) -> Option<Arc<ImageView>> { fn view(&mut self) -> Option<Arc<ImageView>> {
self.last_image.take() self.last_image.take()
} }
fn extent(&self) -> [u32; 3] {
self.extent.clone()
}
} }
fn try_create_screen<O>(wl: &WlxClient, id: u32, session: &AppSession) -> Option<OverlayData<O>> fn try_create_screen<O>(wl: &WlxClient, id: u32, session: &AppSession) -> Option<OverlayData<O>>
@@ -441,3 +452,12 @@ where
{ {
todo!() todo!()
} }
fn extent_from_res(res: (i32, i32)) -> [u32; 3] {
// screens above a certain resolution will have severe aliasing
// TODO make dynamic. maybe don't go above HMD resolution?
let w = res.0.min(1920) as u32;
let h = (res.1 as f32 / res.0 as f32 * w as f32) as u32;
[w, h, 1]
}

View File

@@ -1,10 +1,7 @@
use std::{env::VarError, path::Path, sync::Arc}; use std::{env::VarError, path::Path, sync::Arc};
use glam::{Quat, Vec3}; use glam::{Quat, Vec3};
use vulkano::{ use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::view::ImageView};
command_buffer::CommandBufferUsage, format::Format, image::view::ImageView,
shader::ShaderModule,
};
use crate::{ use crate::{
backend::{common::TaskContainer, input::InputState}, backend::{common::TaskContainer, input::InputState},