refactor rendering interface, working edit overlay

This commit is contained in:
galister
2025-11-12 20:02:20 +09:00
parent 350c931749
commit 6b5b95bd88
25 changed files with 371 additions and 341 deletions

View File

@@ -1,7 +1,6 @@
use std::{marker::PhantomData, sync::Arc}; use std::{marker::PhantomData, sync::Arc};
use vulkano::{ use vulkano::{
DeviceSize,
buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}, buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer},
command_buffer::{ command_buffer::{
AutoCommandBufferBuilder, ClearColorImageInfo, CommandBufferExecFuture, CopyBufferToImageInfo, CopyImageInfo, AutoCommandBufferBuilder, ClearColorImageInfo, CommandBufferExecFuture, CopyBufferToImageInfo, CopyImageInfo,
@@ -9,13 +8,14 @@ use vulkano::{
}, },
device::Queue, device::Queue,
format::{ClearColorValue, ClearValue, Format}, format::{ClearColorValue, ClearValue, Format},
image::{Image, ImageCreateInfo, ImageType, ImageUsage, view::ImageView}, image::{view::ImageView, Image, ImageCreateInfo, ImageType, ImageUsage},
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter}, memory::allocator::{AllocationCreateInfo, MemoryTypeFilter},
render_pass::{AttachmentLoadOp, AttachmentStoreOp}, render_pass::{AttachmentLoadOp, AttachmentStoreOp},
sync::{GpuFuture, future::NowFuture}, sync::{future::NowFuture, GpuFuture},
DeviceSize,
}; };
use super::{WGfx, pass::WGfxPass}; use super::{pass::WGfxPass, WGfx};
pub type GfxCommandBuffer = WCommandBuffer<CmdBufGfx>; pub type GfxCommandBuffer = WCommandBuffer<CmdBufGfx>;
pub type XferCommandBuffer = WCommandBuffer<CmdBufXfer>; pub type XferCommandBuffer = WCommandBuffer<CmdBufXfer>;
@@ -44,13 +44,24 @@ impl<T> WCommandBuffer<T> {
} }
} }
#[derive(Clone, Copy)] #[derive(Default, Clone, Copy)]
pub enum WGfxClearMode { pub enum WGfxClearMode {
Keep, #[default]
DontCare, DontCare,
Keep,
Clear([f32; 4]), Clear([f32; 4]),
} }
#[allow(dead_code)]
impl WGfxClearMode {
pub fn or_default(self, def: WGfxClearMode) -> WGfxClearMode {
match self {
Self::DontCare => def,
s => s,
}
}
}
impl WCommandBuffer<CmdBufGfx> { impl WCommandBuffer<CmdBufGfx> {
pub fn begin_rendering(&mut self, render_target: Arc<ImageView>, clear_mode: WGfxClearMode) -> anyhow::Result<()> { pub fn begin_rendering(&mut self, render_target: Arc<ImageView>, clear_mode: WGfxClearMode) -> anyhow::Result<()> {
self.command_buffer.begin_rendering(RenderingInfo { self.command_buffer.begin_rendering(RenderingInfo {

View File

@@ -15,7 +15,7 @@
border_color="#0044CC" border="2" round="8" color="#000A1C" color2="#000002" gradient="vertical" /> border_color="#0044CC" border="2" round="8" color="#000A1C" color2="#000002" gradient="vertical" />
<elements> <elements>
<div width="600" height="600"> <div width="100%" height="100%">
<rectangle width="100%" height="100%" padding="4" gap="4" align_items="center" justify_content="center" color="#000000DD" flex_direction="row"> <rectangle width="100%" height="100%" padding="4" gap="4" align_items="center" justify_content="center" color="#000000DD" flex_direction="row">
<div></div> <div></div>
<div flex_direction="column"> <div flex_direction="column">

View File

@@ -0,0 +1,35 @@
<layout>
<theme>
<var key="border" value="2" />
</theme>
<macro name="button_style"
margin="2" overflow="hidden" box_sizing="border_box" align_items="center" justify_content="center"
border_color="#0044CC" border="2" round="8" color="#000A1C" color2="#000002" gradient="vertical" />
<template name="Set">
<Button macro="button_style" _press="::SetToggle ${handle}">
<sprite width="40" height="40" color="~set_color" src="watch/set2.svg" />
<div position="absolute" margin_top="9">
<label text="${display}" size="24" color="#00050F" weight="bold" />
</div>
</Button>
</template>
<elements>
<div width="400" height="200">
<rectangle width="100%" height="100%" padding="4" box_sizing="content_box" flex_wrap="wrap" flex_direction="column" gap="4" color="~bg_color">
<label text="Select set to edit" size="48" color="#ffffff" weight="bold" />
<div width="100%" flex_direction="row">
<div id="sets">
<!-- Will populate <Set> tags at runtime -->
</div>
<Button macro="button_style" _press="::EditToggle">
<sprite color="~set_color" width="40" height="40" src="watch/edit.svg" />
</Button>
</div>
<label text="" size="48" color="#ffffff" weight="bold" />
</rectangle>
</div>
</elements>
</layout>

View File

@@ -1,6 +1,6 @@
use std::f32::consts::PI; use std::f32::consts::PI;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use ash::vk::SubmitInfo; use ash::vk::SubmitInfo;
use glam::{Affine3A, Vec3, Vec3A, Vec4}; use glam::{Affine3A, Vec3, Vec3A, Vec4};
@@ -8,7 +8,6 @@ use idmap::IdMap;
use ovr_overlay::overlay::OverlayManager; use ovr_overlay::overlay::OverlayManager;
use ovr_overlay::sys::ETrackingUniverseOrigin; use ovr_overlay::sys::ETrackingUniverseOrigin;
use vulkano::{ use vulkano::{
VulkanObject,
command_buffer::{ command_buffer::{
CommandBufferBeginInfo, CommandBufferLevel, CommandBufferUsage, RecordingCommandBuffer, CommandBufferBeginInfo, CommandBufferLevel, CommandBufferUsage, RecordingCommandBuffer,
}, },
@@ -16,19 +15,19 @@ use vulkano::{
image::view::ImageView, image::view::ImageView,
image::{Image, ImageLayout}, image::{Image, ImageLayout},
sync::{ sync::{
AccessFlags, DependencyInfo, ImageMemoryBarrier, PipelineStages,
fence::{Fence, FenceCreateInfo}, fence::{Fence, FenceCreateInfo},
AccessFlags, DependencyInfo, ImageMemoryBarrier, PipelineStages,
}, },
VulkanObject,
}; };
use wgui::gfx::WGfx; use wgui::gfx::WGfx;
use crate::backend::input::{HoverResult, PointerHit}; use crate::backend::input::{HoverResult, PointerHit};
use crate::graphics::CommandBuffers;
use crate::state::AppState; use crate::state::AppState;
use crate::subsystem::hid::WheelDelta; use crate::subsystem::hid::WheelDelta;
use crate::windowing::Z_ORDER_LINES; use crate::windowing::backend::{FrameMeta, OverlayBackend, RenderResources, ShouldRender};
use crate::windowing::backend::{FrameMeta, OverlayBackend, ShouldRender};
use crate::windowing::window::{OverlayWindowConfig, OverlayWindowData}; use crate::windowing::window::{OverlayWindowConfig, OverlayWindowData};
use crate::windowing::Z_ORDER_LINES;
use super::overlay::OpenVrOverlayData; use super::overlay::OpenVrOverlayData;
@@ -189,14 +188,8 @@ impl OverlayBackend for LineBackend {
fn should_render(&mut self, _: &mut AppState) -> anyhow::Result<ShouldRender> { fn should_render(&mut self, _: &mut AppState) -> anyhow::Result<ShouldRender> {
Ok(ShouldRender::Unable) Ok(ShouldRender::Unable)
} }
fn render( fn render(&mut self, _: &mut AppState, _: &mut RenderResources) -> anyhow::Result<()> {
&mut self, unreachable!()
_: &mut AppState,
_: Arc<ImageView>,
_: &mut CommandBuffers,
_: f32,
) -> anyhow::Result<bool> {
Ok(false)
} }
fn frame_meta(&mut self) -> Option<FrameMeta> { fn frame_meta(&mut self) -> Option<FrameMeta> {
Some(FrameMeta { Some(FrameMeta {

View File

@@ -29,14 +29,18 @@ use crate::{
BackendError, BackendError,
}, },
config::save_state, config::save_state,
graphics::{init_openvr_graphics, CommandBuffers}, graphics::{init_openvr_graphics, GpuFutures},
overlays::{ overlays::{
toast::{Toast, ToastTopic}, toast::{Toast, ToastTopic},
watch::{watch_fade, WATCH_NAME}, watch::{watch_fade, WATCH_NAME},
}, },
state::AppState, state::AppState,
subsystem::notifications::NotificationManager, subsystem::notifications::NotificationManager,
windowing::{backend::ShouldRender, manager::OverlayWindowManager, window::OverlayWindowData}, windowing::{
backend::{RenderResources, ShouldRender},
manager::OverlayWindowManager,
window::OverlayWindowData,
},
}; };
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
@@ -311,7 +315,7 @@ pub fn openvr_run(
} }
app.hid_provider.inner.commit(); app.hid_provider.inner.commit();
let mut buffers = CommandBuffers::default(); let mut futures = GpuFutures::default();
lines.update(universe.clone(), &mut overlay_mgr, &mut app)?; lines.update(universe.clone(), &mut overlay_mgr, &mut app)?;
@@ -338,26 +342,17 @@ pub fn openvr_run(
let ShouldRender::Should = o.should_render(&mut app)? else { let ShouldRender::Should = o.should_render(&mut app)? else {
continue; continue;
}; };
if !o.ensure_image_allocated(&mut app)? { let meta = o.config.backend.frame_meta().unwrap();
continue; let tgt = o.ensure_staging_image(&mut app, meta.extent)?;
} let mut rdr = RenderResources::new(app.gfx.clone(), tgt, &meta, 1.0)?;
o.data.image_dirty = o.render( o.render(&mut app, &mut rdr)?;
&mut app, o.data.image_dirty = true;
o.data.image_view.as_ref().unwrap().clone(), futures.execute(rdr.end()?)?;
&mut buffers,
1.0, // alpha is instead set using OVR API
)?;
} }
} }
log::trace!("Rendering overlays"); log::trace!("Rendering overlays");
futures.wait()?;
if let Some(mut future) = buffers.execute_now(app.gfx.queue_gfx.clone())? {
if let Err(e) = future.flush() {
return Err(BackendError::Fatal(e.into()));
}
future.cleanup_finished();
}
overlays overlays
.values_mut() .values_mut()

View File

@@ -62,21 +62,33 @@ impl OverlayWindowData<OpenVrOverlayData> {
Ok(handle) Ok(handle)
} }
pub(super) fn ensure_image_allocated(&mut self, app: &mut AppState) -> anyhow::Result<bool> { pub(super) fn ensure_staging_image(
if self.data.image_view.is_some() { &mut self,
return Ok(true); app: &mut AppState,
extent: [u32; 3],
) -> anyhow::Result<Arc<ImageView>> {
if let Some(image_view) = self.data.image_view.as_ref()
&& image_view.image().extent() == extent
{
return Ok(image_view.clone());
} }
let Some(meta) = self.config.backend.frame_meta() else {
return Ok(false); log::debug!(
}; "{}: recreating staging image at {}x{}",
self.config.name,
extent[0],
extent[1],
);
let image = app.gfx.new_image( let image = app.gfx.new_image(
meta.extent[0], extent[0],
meta.extent[1], extent[1],
app.gfx.surface_format, app.gfx.surface_format,
ImageUsage::TRANSFER_SRC | ImageUsage::COLOR_ATTACHMENT | ImageUsage::SAMPLED, ImageUsage::TRANSFER_SRC | ImageUsage::COLOR_ATTACHMENT | ImageUsage::SAMPLED,
)?; )?;
self.data.image_view = Some(ImageView::new_default(image)?); let image_view = ImageView::new_default(image)?;
Ok(true) self.data.image_view = Some(image_view.clone());
Ok(image_view)
} }
pub(super) fn after_input( pub(super) fn after_input(

View File

@@ -18,7 +18,7 @@ use wgui::gfx::{
use crate::{ use crate::{
backend::openxr::helpers, backend::openxr::helpers,
graphics::{CommandBuffers, Vert2Uv}, graphics::{GpuFutures, Vert2Uv},
state::AppState, state::AppState,
}; };
use vulkano::{ use vulkano::{
@@ -152,7 +152,7 @@ impl LinePool {
pub(super) fn render( pub(super) fn render(
&mut self, &mut self,
app: &AppState, app: &AppState,
buf: &mut CommandBuffers, futures: &mut GpuFutures,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
for line in self.lines.values_mut() { for line in self.lines.values_mut() {
if let Some(inner) = line.maybe_line.as_mut() { if let Some(inner) = line.maybe_line.as_mut() {
@@ -167,7 +167,7 @@ impl LinePool {
cmd_buffer.run_ref(&self.pass)?; cmd_buffer.run_ref(&self.pass)?;
cmd_buffer.end_rendering()?; cmd_buffer.end_rendering()?;
buf.push(cmd_buffer.build()?); futures.execute((cmd_buffer.queue.clone(), cmd_buffer.build()?))?;
} }
} }

View File

@@ -23,14 +23,18 @@ use crate::{
BackendError, BackendError,
}, },
config::save_state, config::save_state,
graphics::{init_openxr_graphics, CommandBuffers}, graphics::{init_openxr_graphics, GpuFutures},
overlays::{ overlays::{
toast::{Toast, ToastTopic}, toast::{Toast, ToastTopic},
watch::{watch_fade, WATCH_NAME}, watch::{watch_fade, WATCH_NAME},
}, },
state::AppState, state::AppState,
subsystem::notifications::NotificationManager, subsystem::notifications::NotificationManager,
windowing::{backend::ShouldRender, manager::OverlayWindowManager, window::OverlayWindowData}, windowing::{
backend::{RenderResources, ShouldRender},
manager::OverlayWindowManager,
window::OverlayWindowData,
},
}; };
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
@@ -378,10 +382,10 @@ pub fn openxr_run(
} }
// Begin rendering // Begin rendering
let mut buffers = CommandBuffers::default(); let mut futures = GpuFutures::default();
if !main_session_visible && let Some(skybox) = skybox.as_mut() { if !main_session_visible && let Some(skybox) = skybox.as_mut() {
skybox.render(&xr_state, &app, &mut buffers)?; skybox.render(&xr_state, &app, &mut futures)?;
} }
for o in overlays.values_mut() { for o in overlays.values_mut() {
@@ -402,30 +406,20 @@ pub fn openxr_run(
}; };
if should_render { if should_render {
if !o.ensure_swapchain(&app, &xr_state)? { let meta = o.config.backend.frame_meta().unwrap(); // want panic
continue; let tgt = o.ensure_swapchain_acquire(&app, &xr_state, meta.extent)?;
} let mut rdr = RenderResources::new(app.gfx.clone(), tgt, &meta, alpha)?;
let tgt = o.data.swapchain.as_mut().unwrap().acquire_wait_image()?; // want o.render(&mut app, &mut rdr)?;
if !o.render(&mut app, tgt, &mut buffers, alpha)? {
o.data.swapchain.as_mut().unwrap().ensure_image_released()?; // want
continue;
}
o.data.last_alpha = alpha; o.data.last_alpha = alpha;
futures.execute(rdr.end()?)?;
} else if o.data.swapchain.is_none() { } else if o.data.swapchain.is_none() {
continue; continue;
} }
o.data.cur_visible = true; o.data.cur_visible = true;
} }
lines.render(&app, &mut buffers)?; lines.render(&app, &mut futures)?;
futures.wait()?;
let future = buffers.execute_now(app.gfx.queue_gfx.clone())?;
if let Some(mut future) = future {
if let Err(e) = future.flush() {
return Err(BackendError::Fatal(e.into()));
}
future.cleanup_finished();
}
// End rendering // End rendering
// Layer composition // Layer composition

View File

@@ -1,11 +1,12 @@
use glam::Vec3A; use glam::Vec3A;
use openxr::{self as xr, CompositionLayerFlags}; use openxr::{self as xr, CompositionLayerFlags};
use std::f32::consts::PI; use std::{f32::consts::PI, sync::Arc};
use vulkano::image::view::ImageView;
use xr::EyeVisibility; use xr::EyeVisibility;
use super::{CompositionLayer, XrState, helpers, swapchain::WlxSwapchain}; use super::{helpers, swapchain::WlxSwapchain, CompositionLayer, XrState};
use crate::{ use crate::{
backend::openxr::swapchain::{SwapchainOpts, create_swapchain}, backend::openxr::swapchain::{create_swapchain, SwapchainOpts},
state::AppState, state::AppState,
windowing::window::OverlayWindowData, windowing::window::OverlayWindowData,
}; };
@@ -20,41 +21,28 @@ pub struct OpenXrOverlayData {
} }
impl OverlayWindowData<OpenXrOverlayData> { impl OverlayWindowData<OpenXrOverlayData> {
pub(super) fn ensure_swapchain<'a>( pub(super) fn ensure_swapchain_acquire<'a>(
&'a mut self, &'a mut self,
app: &AppState, app: &AppState,
xr: &'a XrState, xr: &'a XrState,
) -> anyhow::Result<bool> { extent: [u32; 3],
let Some(meta) = self.frame_meta() else { ) -> anyhow::Result<Arc<ImageView>> {
log::warn!( if let Some(swapchain) = self.data.swapchain.as_mut()
"{}: swapchain cannot be created due to missing metadata", && swapchain.extent == extent
self.config.name
);
return Ok(false);
};
if self
.data
.swapchain
.as_ref()
.is_some_and(|s| s.extent == meta.extent)
{ {
return Ok(true); return Ok(swapchain.acquire_wait_image()?);
} }
log::debug!( log::debug!(
"{}: recreating swapchain at {}x{}", "{}: recreating swapchain at {}x{}",
self.config.name, self.config.name,
meta.extent[0], extent[0],
meta.extent[1], extent[1],
); );
self.data.swapchain = Some(create_swapchain( let mut swapchain = create_swapchain(xr, app.gfx.clone(), extent, SwapchainOpts::new())?;
xr, let tgt = swapchain.acquire_wait_image()?;
app.gfx.clone(), self.data.swapchain = Some(swapchain);
meta.extent, Ok(tgt)
SwapchainOpts::new(),
)?);
Ok(true)
} }
pub(super) fn present<'a>( pub(super) fn present<'a>(

View File

@@ -15,7 +15,7 @@ use wgui::gfx::{cmd::WGfxClearMode, pipeline::WPipelineCreateInfo};
use crate::{ use crate::{
backend::openxr::{helpers::translation_rotation_to_posef, swapchain::SwapchainOpts}, backend::openxr::{helpers::translation_rotation_to_posef, swapchain::SwapchainOpts},
config_io, config_io,
graphics::{dds::WlxCommandBufferDds, CommandBuffers, ExtentExt}, graphics::{dds::WlxCommandBufferDds, ExtentExt, GpuFutures},
state::AppState, state::AppState,
}; };
@@ -85,7 +85,7 @@ impl Skybox {
&'a mut self, &'a mut self,
xr: &'a XrState, xr: &'a XrState,
app: &AppState, app: &AppState,
buf: &mut CommandBuffers, futures: &mut GpuFutures,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
if self.sky.is_some() { if self.sky.is_some() {
return Ok(()); return Ok(());
@@ -119,7 +119,7 @@ impl Skybox {
cmd_buffer.run_ref(&pass)?; cmd_buffer.run_ref(&pass)?;
cmd_buffer.end_rendering()?; cmd_buffer.end_rendering()?;
buf.push(cmd_buffer.build()?); futures.execute((cmd_buffer.queue.clone(), cmd_buffer.build()?))?;
self.sky = Some(swapchain); self.sky = Some(swapchain);
Ok(()) Ok(())
@@ -129,7 +129,7 @@ impl Skybox {
&'a mut self, &'a mut self,
xr: &'a XrState, xr: &'a XrState,
app: &AppState, app: &AppState,
buf: &mut CommandBuffers, futures: &mut GpuFutures,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
if self.grid.is_some() { if self.grid.is_some() {
return Ok(()); return Ok(());
@@ -165,7 +165,7 @@ impl Skybox {
cmd_buffer.run_ref(&pass)?; cmd_buffer.run_ref(&pass)?;
cmd_buffer.end_rendering()?; cmd_buffer.end_rendering()?;
buf.push(cmd_buffer.build()?); futures.execute((cmd_buffer.queue.clone(), cmd_buffer.build()?))?;
self.grid = Some(swapchain); self.grid = Some(swapchain);
Ok(()) Ok(())
@@ -175,7 +175,7 @@ impl Skybox {
&mut self, &mut self,
xr: &XrState, xr: &XrState,
app: &AppState, app: &AppState,
buf: &mut CommandBuffers, buf: &mut GpuFutures,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
self.prepare_sky(xr, app, buf)?; self.prepare_sky(xr, app, buf)?;
self.prepare_grid(xr, app, buf)?; self.prepare_grid(xr, app, buf)?;

View File

@@ -636,28 +636,32 @@ fn queue_families_priorities(
} }
#[derive(Default)] #[derive(Default)]
pub struct CommandBuffers { pub struct GpuFutures {
inner: Vec<Arc<PrimaryAutoCommandBuffer>>, futures: Vec<Box<dyn GpuFuture>>,
} }
impl CommandBuffers { impl GpuFutures {
pub fn push(&mut self, buffer: Arc<PrimaryAutoCommandBuffer>) { pub fn execute(
self.inner.push(buffer); &mut self,
cmd: (Arc<Queue>, Arc<PrimaryAutoCommandBuffer>),
) -> anyhow::Result<()> {
self.futures.push(cmd.1.execute(cmd.0)?.boxed());
Ok(())
} }
pub fn execute_now(self, queue: Arc<Queue>) -> anyhow::Result<Option<Box<dyn GpuFuture>>> { pub fn wait(self) -> anyhow::Result<()> {
let mut buffers = self.inner.into_iter(); let mut it = self.futures.into_iter();
let Some(first) = buffers.next() else { let Some(mut all) = it.next() else {
return Ok(None); return Ok(());
}; };
for f in it {
let future = first.execute(queue)?; all = all.join(f).boxed();
let mut future: Box<dyn GpuFuture> = Box::new(future);
for buf in buffers {
future = Box::new(future.then_execute_same_queue(buf)?);
} }
Ok(Some(future)) let finished = all.then_signal_fence_and_flush()?;
finished.wait(None)?;
Ok(())
} }
} }

View File

@@ -1,9 +1,8 @@
use std::{cell::RefCell, rc::Rc, sync::Arc}; use std::{cell::RefCell, rc::Rc};
use button::setup_custom_button; use button::setup_custom_button;
use glam::{Affine2, Vec2, vec2}; use glam::{vec2, Affine2, Vec2};
use label::setup_custom_label; use label::setup_custom_label;
use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView};
use wgui::{ use wgui::{
assets::AssetPath, assets::AssetPath,
drawing, drawing,
@@ -16,15 +15,14 @@ use wgui::{
layout::{Layout, LayoutParams, WidgetID}, layout::{Layout, LayoutParams, WidgetID},
parser::ParserState, parser::ParserState,
renderer_vk::context::Context as WguiContext, renderer_vk::context::Context as WguiContext,
widget::{EventResult, label::WidgetLabel, rectangle::WidgetRectangle}, widget::{label::WidgetLabel, rectangle::WidgetRectangle, EventResult},
}; };
use crate::{ use crate::{
backend::input::{Haptics, HoverResult, PointerHit, PointerMode}, backend::input::{Haptics, HoverResult, PointerHit, PointerMode},
graphics::{CommandBuffers, ExtentExt},
state::AppState, state::AppState,
subsystem::hid::WheelDelta, subsystem::hid::WheelDelta,
windowing::backend::{FrameMeta, OverlayBackend, ShouldRender, ui_transform}, windowing::backend::{ui_transform, FrameMeta, OverlayBackend, RenderResources, ShouldRender},
}; };
use super::{timer::GuiTimer, timestep::Timestep}; use super::{timer::GuiTimer, timestep::Timestep};
@@ -222,31 +220,11 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
}) })
} }
fn render( fn render(&mut self, app: &mut AppState, rdr: &mut RenderResources) -> anyhow::Result<()> {
&mut self,
app: &mut AppState,
tgt: Arc<ImageView>,
buf: &mut CommandBuffers,
mut alpha: f32,
) -> anyhow::Result<bool> {
self.context self.context
.update_viewport(&mut app.wgui_shared, tgt.extent_u32arr(), 1.0)?; .update_viewport(&mut app.wgui_shared, rdr.extent, 1.0)?;
self.layout.update(self.max_size, self.timestep.alpha)?; self.layout.update(self.max_size, self.timestep.alpha)?;
// FIXME: pass this properly
let mut clear = WGfxClearMode::Clear([0., 0., 0., 0.]);
if alpha < 0. {
alpha *= -1.;
clear = WGfxClearMode::Keep;
}
let mut cmd_buf = app
.gfx
.create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)
.unwrap(); // want panic
cmd_buf.begin_rendering(tgt, clear)?;
let globals = self.layout.state.globals.clone(); // sorry let globals = self.layout.state.globals.clone(); // sorry
let mut globals = globals.get(); let mut globals = globals.get();
@@ -254,22 +232,20 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
globals: &mut globals, globals: &mut globals,
layout: &mut self.layout, layout: &mut self.layout,
debug_draw: false, debug_draw: false,
alpha, alpha: rdr.alpha,
})?; })?;
self.context.draw( self.context.draw(
&globals.font_system, &globals.font_system,
&mut app.wgui_shared, &mut app.wgui_shared,
&mut cmd_buf, &mut rdr.cmd_buf,
&primitives, &primitives,
)?; )?;
cmd_buf.end_rendering()?; Ok(())
buf.push(cmd_buf.build()?);
Ok(true)
} }
fn frame_meta(&mut self) -> Option<FrameMeta> { fn frame_meta(&mut self) -> Option<FrameMeta> {
Some(FrameMeta { Some(FrameMeta {
clear: WGfxClearMode::Clear([0., 0., 0., 0.]),
extent: [ extent: [
self.max_size.x.min(self.layout.content_size.x) as _, self.max_size.x.min(self.layout.content_size.x) as _,
self.max_size.y.min(self.layout.content_size.y) as _, self.max_size.y.min(self.layout.content_size.y) as _,

View File

@@ -5,14 +5,14 @@ use std::{
}; };
use glam::vec2; use glam::vec2;
use vulkano::image::{view::ImageView, ImageUsage};
use crate::{ use crate::{
backend::input::HoverResult, backend::input::HoverResult,
gui::panel::GuiPanel, gui::panel::GuiPanel,
state::AppState, state::AppState,
subsystem::hid::WheelDelta,
windowing::{ windowing::{
backend::{DummyBackend, OverlayBackend, ShouldRender}, backend::{DummyBackend, OverlayBackend, RenderResources, ShouldRender},
window::OverlayWindowConfig, window::OverlayWindowConfig,
}, },
}; };
@@ -38,15 +38,13 @@ impl EditModeManager {
let inner = mem::replace(&mut owc.backend, Box::new(DummyBackend {})); let inner = mem::replace(&mut owc.backend, Box::new(DummyBackend {}));
let mut panel = self.panel_pool.pop(); let mut panel = self.panel_pool.pop();
if panel.is_none() { if panel.is_none() {
panel = Some(make_adjustment_panel(app)?); panel = Some(make_edit_panel(app)?);
} }
let mut panel = panel.unwrap(); let mut panel = panel.unwrap();
panel.state = owc.name.clone(); panel.state = owc.name.clone();
owc.backend = Box::new(EditModeBackendWrapper { owc.backend = Box::new(EditModeBackendWrapper {
inner: ManuallyDrop::new(inner), inner: ManuallyDrop::new(inner),
panel: ManuallyDrop::new(panel), panel: ManuallyDrop::new(panel),
can_render_inner: false,
image: None,
}); });
owc.editing = true; owc.editing = true;
@@ -79,8 +77,6 @@ impl EditModeManager {
pub struct EditModeBackendWrapper { pub struct EditModeBackendWrapper {
panel: ManuallyDrop<EditModeWrapPanel>, panel: ManuallyDrop<EditModeWrapPanel>,
inner: ManuallyDrop<Box<dyn OverlayBackend>>, inner: ManuallyDrop<Box<dyn OverlayBackend>>,
image: Option<Arc<ImageView>>,
can_render_inner: bool,
} }
impl OverlayBackend for EditModeBackendWrapper { impl OverlayBackend for EditModeBackendWrapper {
@@ -99,8 +95,7 @@ impl OverlayBackend for EditModeBackendWrapper {
fn should_render(&mut self, app: &mut crate::state::AppState) -> anyhow::Result<ShouldRender> { fn should_render(&mut self, app: &mut crate::state::AppState) -> anyhow::Result<ShouldRender> {
let i = self.inner.should_render(app)?; let i = self.inner.should_render(app)?;
self.can_render_inner = !matches!(i, ShouldRender::Unable); if !matches!(i, ShouldRender::Unable)
if self.can_render_inner
&& let Some(ref frame_meta) = self.inner.frame_meta() && let Some(ref frame_meta) = self.inner.frame_meta()
{ {
let new_size = vec2(frame_meta.extent[0] as _, frame_meta.extent[1] as _); let new_size = vec2(frame_meta.extent[0] as _, frame_meta.extent[1] as _);
@@ -109,6 +104,8 @@ impl OverlayBackend for EditModeBackendWrapper {
self.panel.max_size = new_size; self.panel.max_size = new_size;
self.panel.update_layout()?; self.panel.update_layout()?;
} }
} else {
return Ok(ShouldRender::Unable);
} }
let p = self.panel.should_render(app)?; let p = self.panel.should_render(app)?;
@@ -118,39 +115,19 @@ impl OverlayBackend for EditModeBackendWrapper {
(ShouldRender::Should, ShouldRender::Can) => ShouldRender::Should, (ShouldRender::Should, ShouldRender::Can) => ShouldRender::Should,
(ShouldRender::Can, ShouldRender::Should) => ShouldRender::Should, (ShouldRender::Can, ShouldRender::Should) => ShouldRender::Should,
(ShouldRender::Can, ShouldRender::Can) => ShouldRender::Can, (ShouldRender::Can, ShouldRender::Can) => ShouldRender::Can,
// (ShouldRender::Unable, ShouldRender::Should) if self.image.is_some() => {
// ShouldRender::Should
// }
// (ShouldRender::Unable, ShouldRender::Can) if self.image.is_some() => ShouldRender::Can,
_ => ShouldRender::Unable, _ => ShouldRender::Unable,
}) })
} }
fn render( fn render(
&mut self, &mut self,
app: &mut crate::state::AppState, app: &mut crate::state::AppState,
tgt: std::sync::Arc<vulkano::image::view::ImageView>, rdr: &mut RenderResources,
buf: &mut crate::graphics::CommandBuffers, ) -> anyhow::Result<()> {
alpha: f32, self.inner.render(app, rdr)?;
) -> anyhow::Result<bool> { self.panel.render(app, rdr)
if self.can_render_inner {
if self.image.is_none()
&& let Some(ref meta) = self.inner.frame_meta()
{
let image = app.gfx.new_image(
meta.extent[0],
meta.extent[1],
app.gfx.surface_format,
ImageUsage::COLOR_ATTACHMENT | ImageUsage::SAMPLED,
)?;
self.image = Some(ImageView::new_default(image)?);
}
self.inner.render(app, tgt.clone(), buf, alpha)?;
}
self.panel.render(app, tgt, buf, -1.)
} }
fn frame_meta(&mut self) -> Option<crate::windowing::backend::FrameMeta> { fn frame_meta(&mut self) -> Option<crate::windowing::backend::FrameMeta> {
self.inner.frame_meta().or_else(|| self.panel.frame_meta()) self.inner.frame_meta()
} }
fn on_hover( fn on_hover(
&mut self, &mut self,
@@ -177,19 +154,17 @@ impl OverlayBackend for EditModeBackendWrapper {
&mut self, &mut self,
app: &mut crate::state::AppState, app: &mut crate::state::AppState,
hit: &crate::backend::input::PointerHit, hit: &crate::backend::input::PointerHit,
delta_y: f32, delta: WheelDelta,
delta_x: f32,
) { ) {
self.panel.on_scroll(app, hit, delta_y, delta_x); self.panel.on_scroll(app, hit, delta);
} }
fn get_interaction_transform(&mut self) -> Option<glam::Affine2> { fn get_interaction_transform(&mut self) -> Option<glam::Affine2> {
self.inner.get_interaction_transform() self.inner.get_interaction_transform()
} }
} }
fn make_adjustment_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> { fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
let mut panel = GuiPanel::new_from_template(app, "gui/adjust.xml", "".into(), None, true)?; let panel = GuiPanel::new_from_template(app, "gui/edit.xml", "".into(), None, true)?;
panel.update_layout()?;
Ok(panel) Ok(panel)
} }

View File

@@ -9,7 +9,7 @@ use wgui::{
layout::LayoutParams, layout::LayoutParams,
parser::Fetchable, parser::Fetchable,
renderer_vk::util, renderer_vk::util,
taffy::{self, prelude::length, BoxSizing}, taffy::{self, prelude::length},
widget::{ widget::{
div::WidgetDiv, div::WidgetDiv,
rectangle::{WidgetRectangle, WidgetRectangleParams}, rectangle::{WidgetRectangle, WidgetRectangleParams},

View File

@@ -1,10 +1,8 @@
use std::{ use std::{
cell::Cell, cell::Cell,
process::{Child, Command}, process::{Child, Command},
sync::Arc,
}; };
use vulkano::image::view::ImageView;
use wgui::{ use wgui::{
drawing, drawing,
event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex}, event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex},
@@ -12,11 +10,10 @@ use wgui::{
use crate::{ use crate::{
backend::input::{HoverResult, PointerHit}, backend::input::{HoverResult, PointerHit},
graphics::CommandBuffers,
gui::panel::GuiPanel, gui::panel::GuiPanel,
state::AppState, state::AppState,
subsystem::hid::{ALT, CTRL, KeyModifier, META, SHIFT, SUPER, VirtualKey, WheelDelta}, subsystem::hid::{KeyModifier, VirtualKey, WheelDelta, ALT, CTRL, META, SHIFT, SUPER},
windowing::backend::{FrameMeta, OverlayBackend, ShouldRender}, windowing::backend::{FrameMeta, OverlayBackend, RenderResources, ShouldRender},
}; };
pub mod builder; pub mod builder;
@@ -36,14 +33,8 @@ impl OverlayBackend for KeyboardBackend {
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> { fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
self.panel.should_render(app) self.panel.should_render(app)
} }
fn render( fn render(&mut self, app: &mut AppState, rdr: &mut RenderResources) -> anyhow::Result<()> {
&mut self, self.panel.render(app, rdr)
app: &mut AppState,
tgt: Arc<ImageView>,
buf: &mut CommandBuffers,
alpha: f32,
) -> anyhow::Result<bool> {
self.panel.render(app, tgt, buf, alpha)
} }
fn frame_meta(&mut self) -> Option<FrameMeta> { fn frame_meta(&mut self) -> Option<FrameMeta> {
self.panel.frame_meta() self.panel.frame_meta()

View File

@@ -5,21 +5,19 @@ use std::{
use futures::{Future, FutureExt}; use futures::{Future, FutureExt};
use glam::{Affine2, Affine3A, Vec3}; use glam::{Affine2, Affine3A, Vec3};
use vulkano::image::view::ImageView; use wlx_capture::pipewire::{pipewire_select_screen, PipewireCapture, PipewireSelectScreenResult};
use wlx_capture::pipewire::{PipewireCapture, PipewireSelectScreenResult, pipewire_select_screen};
use crate::{ use crate::{
backend::{ backend::{
input::{HoverResult, PointerHit}, input::{HoverResult, PointerHit},
task::TaskType, task::TaskType,
}, },
graphics::CommandBuffers,
state::{AppSession, AppState}, state::{AppSession, AppState},
subsystem::hid::WheelDelta, subsystem::hid::WheelDelta,
windowing::{ windowing::{
OverlaySelector, backend::{ui_transform, FrameMeta, OverlayBackend, RenderResources, ShouldRender},
backend::{FrameMeta, OverlayBackend, ShouldRender, ui_transform},
window::{OverlayWindowConfig, OverlayWindowState}, window::{OverlayWindowConfig, OverlayWindowState},
OverlaySelector,
}, },
}; };
@@ -93,16 +91,12 @@ impl OverlayBackend for MirrorBackend {
.as_mut() .as_mut()
.map_or(Ok(ShouldRender::Unable), |r| r.should_render(app)) .map_or(Ok(ShouldRender::Unable), |r| r.should_render(app))
} }
fn render( fn render(&mut self, app: &mut AppState, rdr: &mut RenderResources) -> anyhow::Result<()> {
&mut self, let Some(renderer) = self.renderer.as_mut() else {
app: &mut AppState, anyhow::bail!("render failed after should_render passed");
tgt: Arc<ImageView>, };
buf: &mut CommandBuffers,
alpha: f32, renderer.render(app, rdr)?;
) -> anyhow::Result<bool> {
let mut result = false;
if let Some(renderer) = self.renderer.as_mut() {
result = renderer.render(app, tgt, buf, alpha)?;
if let Some(meta) = renderer.frame_meta() { if let Some(meta) = renderer.frame_meta() {
let extent = meta.extent; let extent = meta.extent;
if self.last_extent != extent { if self.last_extent != extent {
@@ -110,9 +104,8 @@ impl OverlayBackend for MirrorBackend {
self.interaction_transform = Some(ui_transform([extent[0], extent[1]])); self.interaction_transform = Some(ui_transform([extent[0], extent[1]]));
} }
} }
}
Ok(result) Ok(())
} }
fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()> { fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()> {
if let Some(renderer) = self.renderer.as_mut() { if let Some(renderer) = self.renderer.as_mut() {

View File

@@ -1,8 +1,7 @@
pub mod adjust;
pub mod anchor; pub mod anchor;
pub mod bar; pub mod bar;
pub mod custom; pub mod custom;
//pub mod edit; pub mod edit;
pub mod keyboard; pub mod keyboard;
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
pub mod mirror; pub mod mirror;

View File

@@ -1,21 +1,20 @@
use std::{ use std::{
sync::{Arc, LazyLock, atomic::AtomicU64}, sync::{atomic::AtomicU64, Arc, LazyLock},
time::Instant, time::Instant,
}; };
use glam::{Affine2, Vec2, vec2}; use glam::{vec2, Affine2, Vec2};
use vulkano::image::view::ImageView; use wlx_capture::{frame::Transform, WlxCapture};
use wlx_capture::{WlxCapture, frame::Transform};
use crate::{ use crate::{
backend::input::{HoverResult, PointerHit, PointerMode}, backend::input::{HoverResult, PointerHit, PointerMode},
graphics::{CommandBuffers, ExtentExt}, graphics::ExtentExt,
state::AppState, state::AppState,
subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta}, subsystem::hid::{WheelDelta, MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT},
windowing::backend::{FrameMeta, OverlayBackend, ShouldRender}, windowing::backend::{FrameMeta, OverlayBackend, RenderResources, ShouldRender},
}; };
use super::capture::{ScreenPipeline, WlxCaptureIn, WlxCaptureOut, receive_callback}; use super::capture::{receive_callback, ScreenPipeline, WlxCaptureIn, WlxCaptureOut};
const CURSOR_SIZE: f32 = 16. / 1440.; const CURSOR_SIZE: f32 = 16. / 1440.;
@@ -179,25 +178,14 @@ impl OverlayBackend for ScreenBackend {
Ok(ShouldRender::Unable) Ok(ShouldRender::Unable)
} }
} }
fn render( fn render(&mut self, app: &mut AppState, rdr: &mut RenderResources) -> anyhow::Result<()> {
&mut self, // want panic; must be some if should_render was not Unable
app: &mut AppState, let capture = self.cur_frame.take().unwrap();
tgt: Arc<ImageView>,
buf: &mut CommandBuffers,
alpha: f32,
) -> anyhow::Result<bool> {
let Some(capture) = self.cur_frame.take() else {
return Ok(false);
};
// want panic; must be Some if cur_frame is also Some // want panic; must be Some if cur_frame is also Some
self.pipeline self.pipeline.as_mut().unwrap().render(&capture, app, rdr)?;
.as_mut()
.unwrap()
.render(&capture, app, tgt, buf, alpha)?;
self.capture.request_new_frame(); self.capture.request_new_frame();
Ok(true) Ok(())
} }
fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> { fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
self.capture.pause(); self.capture.pause();

View File

@@ -7,29 +7,28 @@ use vulkano::{
command_buffer::CommandBufferUsage, command_buffer::CommandBufferUsage,
device::Queue, device::Queue,
format::Format, format::Format,
image::{Image, sampler::Filter, view::ImageView}, image::{sampler::Filter, view::ImageView, Image},
pipeline::graphics::color_blend::AttachmentBlend, pipeline::graphics::color_blend::AttachmentBlend,
}; };
use wgui::gfx::{ use wgui::gfx::{
WGfx,
cmd::WGfxClearMode, cmd::WGfxClearMode,
pass::WGfxPass, pass::WGfxPass,
pipeline::{WGfxPipeline, WPipelineCreateInfo}, pipeline::{WGfxPipeline, WPipelineCreateInfo},
WGfx,
}; };
use wlx_capture::{ use wlx_capture::{
WlxCapture,
frame::{self as wlx_frame, DrmFormat, FrameFormat, MouseMeta, Transform, WlxFrame}, frame::{self as wlx_frame, DrmFormat, FrameFormat, MouseMeta, Transform, WlxFrame},
WlxCapture,
}; };
use crate::{ use crate::{
config::GeneralConfig, config::GeneralConfig,
graphics::{ graphics::{
CommandBuffers, Vert2Uv, dmabuf::{fourcc_to_vk, WGfxDmabuf},
dmabuf::{WGfxDmabuf, fourcc_to_vk}, upload_quad_vertices, Vert2Uv,
upload_quad_vertices,
}, },
state::AppState, state::AppState,
windowing::backend::FrameMeta, windowing::backend::{FrameMeta, RenderResources},
}; };
const CURSOR_SIZE: f32 = 16. / 1440.; const CURSOR_SIZE: f32 = 16. / 1440.;
@@ -147,20 +146,14 @@ impl ScreenPipeline {
&mut self, &mut self,
capture: &WlxCaptureOut, capture: &WlxCaptureOut,
app: &mut AppState, app: &mut AppState,
tgt: Arc<ImageView>, rdr: &mut RenderResources,
buf: &mut CommandBuffers,
alpha: f32,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let view = ImageView::new_default(capture.image.clone())?; let view = ImageView::new_default(capture.image.clone())?;
self.pass.update_sampler(0, view, app.gfx.texture_filter)?; self.pass.update_sampler(0, view, app.gfx.texture_filter)?;
self.buf_alpha.write()?[0] = alpha; self.buf_alpha.write()?[0] = rdr.alpha;
let mut cmd = app rdr.cmd_buf.run_ref(&self.pass)?;
.gfx
.create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
cmd.begin_rendering(tgt, WGfxClearMode::DontCare)?;
cmd.run_ref(&self.pass)?;
if let Some(mouse) = capture.mouse.as_ref() { if let Some(mouse) = capture.mouse.as_ref() {
let size = CURSOR_SIZE * self.extentf[1]; let size = CURSOR_SIZE * self.extentf[1];
@@ -176,11 +169,9 @@ impl ScreenPipeline {
size, size,
)?; )?;
cmd.run_ref(&self.mouse.pass)?; rdr.cmd_buf.run_ref(&self.mouse.pass)?;
} }
cmd.end_rendering()?;
buf.push(cmd.build()?);
Ok(()) Ok(())
} }
} }
@@ -217,6 +208,7 @@ pub struct WlxCaptureOut {
impl WlxCaptureOut { impl WlxCaptureOut {
pub(super) fn get_frame_meta(&self, config: &GeneralConfig) -> FrameMeta { pub(super) fn get_frame_meta(&self, config: &GeneralConfig) -> FrameMeta {
FrameMeta { FrameMeta {
clear: WGfxClearMode::DontCare,
extent: extent_from_format(self.format, config), extent: extent_from_format(self.format, config),
transform: affine_from_format(&self.format), transform: affine_from_format(&self.format),
format: self.image.format(), format: self.image.format(),

View File

@@ -0,0 +1,80 @@
use std::time::Duration;
use glam::{Affine3A, Vec3};
use crate::{
gui::{panel::GuiPanel, timer::GuiTimer},
state::AppState,
windowing::{
window::{OverlayWindowConfig, OverlayWindowState, Positioning},
Z_ORDER_WATCH,
},
};
pub const EDIT_NAME: &str = "edit";
struct EditState {
num_sets: usize,
current_set: usize,
}
#[allow(clippy::significant_drop_tightening)]
pub fn create_edit(
app: &mut AppState,
num_sets: usize,
current_set: usize,
) -> anyhow::Result<OverlayWindowConfig> {
let state = EditState {
num_sets,
current_set,
};
let mut panel = GuiPanel::new_from_template(
app,
"gui/watch.xml",
state,
Some(Box::new(
move |id, widget, doc_params, layout, parser_state| {
if &*id != "sets" {
return Ok(());
}
for idx in 0..num_sets {
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
params.insert("display".into(), (idx + 1).to_string().into());
params.insert("handle".into(), idx.to_string().into());
parser_state.instantiate_template(doc_params, "Set", layout, widget, params)?;
}
Ok(())
},
)),
)?;
panel
.timers
.push(GuiTimer::new(Duration::from_millis(100), 0));
let positioning = Positioning::FollowHand {
hand: app.session.config.watch_hand as _,
lerp: 1.0,
};
panel.update_layout()?;
Ok(OverlayWindowConfig {
name: EDIT_NAME.into(),
z_order: Z_ORDER_WATCH,
default_state: OverlayWindowState {
interactable: true,
positioning,
transform: Affine3A::from_scale_rotation_translation(
Vec3::ONE * 0.115,
app.session.config.watch_rot,
app.session.config.watch_pos,
) * Affine3A::from_translation(Vec3::Y * 0.075),
..OverlayWindowState::default()
},
show_on_spawn: true,
global: true,
..OverlayWindowConfig::from_backend(Box::new(panel))
})
}

View File

@@ -1,17 +1,17 @@
use glam::{Affine2, Affine3A, Quat, Vec3, vec3}; use glam::{vec3, Affine2, Affine3A, Quat, Vec3};
use smallvec::smallvec; use smallvec::smallvec;
use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc}; use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc};
use vulkano::{ use vulkano::{
buffer::{BufferUsage, Subbuffer}, buffer::{BufferUsage, Subbuffer},
command_buffer::CommandBufferUsage, command_buffer::CommandBufferUsage,
format::Format, format::Format,
image::{Image, ImageTiling, SubresourceLayout, view::ImageView}, image::{view::ImageView, Image, ImageTiling, SubresourceLayout},
}; };
use wayvr_ipc::packet_server::{self, PacketServer, WvrStateChanged}; use wayvr_ipc::packet_server::{self, PacketServer, WvrStateChanged};
use wgui::gfx::{ use wgui::gfx::{
WGfx,
pass::WGfxPass, pass::WGfxPass,
pipeline::{WGfxPipeline, WPipelineCreateInfo}, pipeline::{WGfxPipeline, WPipelineCreateInfo},
WGfx,
}; };
use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane}; use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane};
@@ -20,19 +20,20 @@ use crate::{
input::{self, HoverResult}, input::{self, HoverResult},
task::TaskType, task::TaskType,
wayvr::{ wayvr::{
self, WayVR, WayVRAction, WayVRDisplayClickAction, display, self, display,
server_ipc::{gen_args_vec, gen_env_vec}, server_ipc::{gen_args_vec, gen_env_vec},
WayVR, WayVRAction, WayVRDisplayClickAction,
}, },
}, },
config_wayvr, config_wayvr,
graphics::{CommandBuffers, Vert2Uv, dmabuf::WGfxDmabuf}, graphics::{dmabuf::WGfxDmabuf, Vert2Uv},
state::{self, AppState}, state::{self, AppState},
subsystem::{hid::WheelDelta, input::KeyboardFocus}, subsystem::{hid::WheelDelta, input::KeyboardFocus},
windowing::{ windowing::{
OverlayID, OverlaySelector, Z_ORDER_DASHBOARD, backend::{ui_transform, FrameMeta, OverlayBackend, RenderResources, ShouldRender},
backend::{FrameMeta, OverlayBackend, ShouldRender, ui_transform},
manager::OverlayWindowManager, manager::OverlayWindowManager,
window::{OverlayWindowConfig, OverlayWindowData, OverlayWindowState}, window::{OverlayWindowConfig, OverlayWindowData, OverlayWindowState},
OverlayID, OverlaySelector, Z_ORDER_DASHBOARD,
}, },
}; };
@@ -660,11 +661,9 @@ impl OverlayBackend for WayVRBackend {
fn render( fn render(
&mut self, &mut self,
app: &mut state::AppState, _app: &mut state::AppState,
tgt: Arc<ImageView>, rdr: &mut RenderResources,
buf: &mut CommandBuffers, ) -> anyhow::Result<()> {
alpha: f32,
) -> anyhow::Result<bool> {
let ctx = self.context.borrow(); let ctx = self.context.borrow();
let wayvr = ctx.wayvr.borrow_mut(); let wayvr = ctx.wayvr.borrow_mut();
@@ -689,26 +688,12 @@ impl OverlayBackend for WayVRBackend {
} }
} }
let Some(image) = self.image.as_ref() else { let image = self.image.as_ref().unwrap();
return Ok(false);
};
self.pass self.pass
.update_sampler(0, image.vk_image_view.clone(), self.graphics.texture_filter)?; .update_sampler(0, image.vk_image_view.clone(), self.graphics.texture_filter)?;
self.buf_alpha.write()?[0] = alpha; self.buf_alpha.write()?[0] = rdr.alpha;
rdr.cmd_buf.run_ref(&self.pass)?;
let mut cmd_buffer = app Ok(())
.gfx
.create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
cmd_buffer.begin_rendering(
tgt,
wgui::gfx::cmd::WGfxClearMode::Clear([0.0, 0.0, 0.0, 1.0]),
)?;
cmd_buffer.run_ref(&self.pass)?;
cmd_buffer.end_rendering()?;
buf.push(cmd_buffer.build()?);
Ok(true)
} }
fn frame_meta(&mut self) -> Option<FrameMeta> { fn frame_meta(&mut self) -> Option<FrameMeta> {

View File

@@ -1,5 +1,5 @@
use glam::Vec2; use glam::Vec2;
use idmap::{IdMap, idmap}; use idmap::{idmap, IdMap};
use idmap_derive::IntegerId; use idmap_derive::IntegerId;
use input_linux::{ use input_linux::{
AbsoluteAxis, AbsoluteInfo, AbsoluteInfoSetup, EventKind, InputId, Key, RelativeAxis, AbsoluteAxis, AbsoluteInfo, AbsoluteInfoSetup, EventKind, InputId, Key, RelativeAxis,

View File

@@ -1,10 +1,19 @@
use glam::{Affine2, Affine3A, Vec2}; use glam::{Affine2, Affine3A, Vec2};
use std::{any::Any, sync::Arc}; use std::{any::Any, sync::Arc};
use vulkano::{format::Format, image::view::ImageView}; use vulkano::{
command_buffer::{CommandBufferUsage, PrimaryAutoCommandBuffer},
device::Queue,
format::Format,
image::view::ImageView,
};
use wgui::gfx::{
cmd::{GfxCommandBuffer, WGfxClearMode},
WGfx,
};
use crate::{ use crate::{
backend::input::{HoverResult, PointerHit}, backend::input::{HoverResult, PointerHit},
graphics::CommandBuffers, graphics::ExtentExt,
state::AppState, state::AppState,
subsystem::hid::WheelDelta, subsystem::hid::WheelDelta,
}; };
@@ -14,6 +23,7 @@ pub struct FrameMeta {
pub extent: [u32; 3], pub extent: [u32; 3],
pub transform: Affine3A, pub transform: Affine3A,
pub format: Format, pub format: Format,
pub clear: WGfxClearMode,
} }
pub enum ShouldRender { pub enum ShouldRender {
@@ -25,6 +35,35 @@ pub enum ShouldRender {
Unable, Unable,
} }
pub struct RenderResources {
pub alpha: f32,
pub cmd_buf: GfxCommandBuffer,
pub extent: [u32; 2],
}
impl RenderResources {
pub fn new(
gfx: Arc<WGfx>,
tgt: Arc<ImageView>,
meta: &FrameMeta,
alpha: f32,
) -> anyhow::Result<Self> {
let mut cmd_buf = gfx.create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
cmd_buf.begin_rendering(tgt, meta.clear)?;
Ok(Self {
cmd_buf,
alpha,
extent: meta.extent.extent_u32arr(),
})
}
pub fn end(mut self) -> anyhow::Result<(Arc<Queue>, Arc<PrimaryAutoCommandBuffer>)> {
self.cmd_buf.end_rendering()?;
Ok((self.cmd_buf.queue.clone(), self.cmd_buf.build()?))
}
}
pub trait OverlayBackend: Any { pub trait OverlayBackend: Any {
/// Called once, before the first frame is rendered /// Called once, before the first frame is rendered
fn init(&mut self, app: &mut AppState) -> anyhow::Result<()>; fn init(&mut self, app: &mut AppState) -> anyhow::Result<()>;
@@ -35,13 +74,7 @@ pub trait OverlayBackend: Any {
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender>; fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender>;
/// Called when the contents need to be rendered to the swapchain /// Called when the contents need to be rendered to the swapchain
fn render( fn render(&mut self, app: &mut AppState, rdr: &mut RenderResources) -> anyhow::Result<()>;
&mut self,
app: &mut AppState,
tgt: Arc<ImageView>,
buf: &mut CommandBuffers,
alpha: f32,
) -> anyhow::Result<bool>;
/// Called to retrieve the effective extent of the image /// Called to retrieve the effective extent of the image
/// Used for creating swapchains. /// Used for creating swapchains.
@@ -85,17 +118,11 @@ impl OverlayBackend for DummyBackend {
fn should_render(&mut self, _: &mut AppState) -> anyhow::Result<ShouldRender> { fn should_render(&mut self, _: &mut AppState) -> anyhow::Result<ShouldRender> {
Ok(ShouldRender::Unable) Ok(ShouldRender::Unable)
} }
fn render( fn render(&mut self, _: &mut AppState, _: &mut RenderResources) -> anyhow::Result<()> {
&mut self, unreachable!()
_: &mut AppState,
_: Arc<ImageView>,
_: &mut CommandBuffers,
_: f32,
) -> anyhow::Result<bool> {
Ok(false)
} }
fn frame_meta(&mut self) -> Option<FrameMeta> { fn frame_meta(&mut self) -> Option<FrameMeta> {
None unreachable!()
} }
fn on_hover(&mut self, _: &mut AppState, _: &PointerHit) -> HoverResult { fn on_hover(&mut self, _: &mut AppState, _: &PointerHit) -> HoverResult {
@@ -103,7 +130,7 @@ impl OverlayBackend for DummyBackend {
} }
fn on_left(&mut self, _: &mut AppState, _: usize) {} fn on_left(&mut self, _: &mut AppState, _: usize) {}
fn on_pointer(&mut self, _: &mut AppState, _: &PointerHit, _: bool) {} fn on_pointer(&mut self, _: &mut AppState, _: &PointerHit, _: bool) {}
fn on_scroll(&mut self, _: &mut AppState, _: &PointerHit, _: f32, _: f32) {} fn on_scroll(&mut self, _: &mut AppState, _: &PointerHit, _: WheelDelta) {}
fn get_interaction_transform(&mut self) -> Option<glam::Affine2> { fn get_interaction_transform(&mut self) -> Option<glam::Affine2> {
None None
} }

View File

@@ -5,7 +5,7 @@ use slotmap::{HopSlotMap, Key, SecondaryMap};
use crate::{ use crate::{
overlays::{ overlays::{
adjust::EditModeManager, anchor::create_anchor, keyboard::builder::create_keyboard, anchor::create_anchor, edit::EditModeManager, keyboard::builder::create_keyboard,
screen::create_screens, watch::create_watch, screen::create_screens, watch::create_watch,
}, },
state::AppState, state::AppState,

View File

@@ -1,14 +1,12 @@
use glam::{Affine3A, Mat3A, Quat, Vec3, Vec3A}; use glam::{Affine3A, Mat3A, Quat, Vec3, Vec3A};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{f32::consts::PI, sync::Arc}; use std::{f32::consts::PI, sync::Arc};
use vulkano::image::view::ImageView;
use crate::{ use crate::{
graphics::CommandBuffers,
state::{AppState, LeftRight}, state::{AppState, LeftRight},
subsystem::input::KeyboardFocus, subsystem::input::KeyboardFocus,
windowing::{ windowing::{
backend::{FrameMeta, OverlayBackend, ShouldRender}, backend::{FrameMeta, OverlayBackend, RenderResources, ShouldRender},
snap_upright, snap_upright,
}, },
}; };
@@ -68,14 +66,8 @@ impl<T> OverlayWindowData<T> {
pub fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> { pub fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
self.config.backend.should_render(app) self.config.backend.should_render(app)
} }
pub fn render( pub fn render(&mut self, app: &mut AppState, rdr: &mut RenderResources) -> anyhow::Result<()> {
&mut self, self.config.backend.render(app, rdr)
app: &mut AppState,
tgt: Arc<ImageView>,
buf: &mut CommandBuffers,
alpha: f32,
) -> anyhow::Result<bool> {
self.config.backend.render(app, tgt, buf, alpha)
} }
pub fn frame_meta(&mut self) -> Option<FrameMeta> { pub fn frame_meta(&mut self) -> Option<FrameMeta> {
self.config.backend.frame_meta() self.config.backend.frame_meta()