fix openxr screen freeze
This commit is contained in:
@@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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> {}
|
||||||
|
|||||||
@@ -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]
|
||||||
|
}
|
||||||
|
|||||||
@@ -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},
|
||||||
|
|||||||
Reference in New Issue
Block a user