even more error handling

This commit is contained in:
galister
2024-02-19 03:21:00 +01:00
parent 1d9fa95ea0
commit 5d812c3b09
16 changed files with 541 additions and 499 deletions

View File

@@ -55,11 +55,11 @@ where
crate::overlays::screen::get_screens_x11(&app.session)? crate::overlays::screen::get_screens_x11(&app.session)?
}; };
let mut watch = create_watch::<T>(&app, &screens); let mut watch = create_watch::<T>(&app, &screens)?;
watch.state.want_visible = true; watch.state.want_visible = true;
overlays.insert(watch.state.id, watch); overlays.insert(watch.state.id, watch);
let mut keyboard = create_keyboard(&app); let mut keyboard = create_keyboard(&app)?;
keyboard.state.show_hide = true; keyboard.state.show_hide = true;
keyboard.state.want_visible = false; keyboard.state.want_visible = false;
overlays.insert(keyboard.state.id, keyboard); overlays.insert(keyboard.state.id, keyboard);

View File

@@ -25,26 +25,26 @@ pub(super) struct LinePool {
} }
impl LinePool { impl LinePool {
pub fn new(graphics: Arc<WlxGraphics>) -> Self { pub fn new(graphics: Arc<WlxGraphics>) -> anyhow::Result<Self> {
let mut command_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit); let mut command_buffer =
graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
let buf = vec![255; 16]; let buf = vec![255; 16];
let texture = command_buffer.texture2d(2, 2, Format::R8G8B8A8_UNORM, &buf); let texture = command_buffer.texture2d(2, 2, Format::R8G8B8A8_UNORM, &buf)?;
command_buffer.build_and_execute_now(); command_buffer.build_and_execute_now()?;
graphics graphics
.transition_layout( .transition_layout(
texture.clone(), texture.clone(),
ImageLayout::ShaderReadOnlyOptimal, ImageLayout::ShaderReadOnlyOptimal,
ImageLayout::TransferSrcOptimal, ImageLayout::TransferSrcOptimal,
) )?
.wait(None) .wait(None)?;
.unwrap();
let view = ImageView::new_default(texture).unwrap(); let view = ImageView::new_default(texture)?;
LinePool { Ok(LinePool {
lines: IdMap::new(), lines: IdMap::new(),
view, view,
colors: [ colors: [
@@ -54,7 +54,7 @@ impl LinePool {
Vec4::new(0.375, 0., 0.5, 1.), Vec4::new(0.375, 0., 0.5, 1.),
Vec4::new(1., 0., 0., 1.), Vec4::new(1., 0., 0., 1.),
], ],
} })
} }
pub fn allocate(&mut self) -> usize { pub fn allocate(&mut self) -> usize {
@@ -140,9 +140,13 @@ impl LinePool {
} }
} }
pub fn update(&mut self, overlay: &mut OverlayManager, app: &mut AppState) { pub fn update(
&mut self,
overlay: &mut OverlayManager,
app: &mut AppState,
) -> anyhow::Result<()> {
for data in self.lines.values_mut() { for data in self.lines.values_mut() {
data.after_input(overlay, app); data.after_input(overlay, app)?;
if data.state.want_visible { if data.state.want_visible {
if data.state.dirty { if data.state.dirty {
data.upload_texture(overlay, &app.graphics); data.upload_texture(overlay, &app.graphics);
@@ -153,6 +157,7 @@ impl LinePool {
data.upload_color(overlay); data.upload_color(overlay);
} }
} }
Ok(())
} }
} }
@@ -161,10 +166,18 @@ struct StaticRenderer {
} }
impl OverlayRenderer for StaticRenderer { impl OverlayRenderer for StaticRenderer {
fn init(&mut self, _app: &mut AppState) {} fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
fn pause(&mut self, _app: &mut AppState) {} Ok(())
fn resume(&mut self, _app: &mut AppState) {} }
fn render(&mut self, _app: &mut AppState) {} fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
Ok(())
}
fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
Ok(())
}
fn render(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
Ok(())
}
fn view(&mut self) -> Option<Arc<ImageView>> { fn view(&mut self) -> Option<Arc<ImageView>> {
Some(self.view.clone()) Some(self.view.clone())
} }

View File

@@ -83,7 +83,7 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
}; };
let mut state = { let mut state = {
let graphics = WlxGraphics::new_openvr(instance_extensions, device_extensions_fn); let graphics = WlxGraphics::new_openvr(instance_extensions, device_extensions_fn)?;
AppState::from_graphics(graphics)? AppState::from_graphics(graphics)?
}; };
@@ -119,7 +119,7 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
let mut next_device_update = Instant::now(); let mut next_device_update = Instant::now();
let mut due_tasks = VecDeque::with_capacity(4); let mut due_tasks = VecDeque::with_capacity(4);
let mut lines = LinePool::new(state.graphics.clone()); let mut lines = LinePool::new(state.graphics.clone())?;
let pointer_lines = [lines.allocate(), lines.allocate()]; let pointer_lines = [lines.allocate(), lines.allocate()];
'main_loop: loop { 'main_loop: loop {
@@ -198,11 +198,11 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
} }
} }
lines.update(&mut overlay_mngr, &mut state); lines.update(&mut overlay_mngr, &mut state)?;
overlays for o in overlays.iter_mut() {
.iter_mut() o.after_input(&mut overlay_mngr, &mut state)?;
.for_each(|o| o.after_input(&mut overlay_mngr, &mut state)); }
#[cfg(feature = "osc")] #[cfg(feature = "osc")]
if let Some(ref mut sender) = osc_sender { if let Some(ref mut sender) = osc_sender {
@@ -211,10 +211,11 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
log::debug!("Rendering frame"); log::debug!("Rendering frame");
overlays for o in overlays.iter_mut() {
.iter_mut() if o.state.want_visible {
.filter(|o| o.state.want_visible) o.render(&mut state)?;
.for_each(|o| o.render(&mut state)); }
}
log::debug!("Rendering overlays"); log::debug!("Rendering overlays");

View File

@@ -32,7 +32,7 @@ impl OverlayData<OpenVrOverlayData> {
&mut self, &mut self,
overlay: &mut OverlayManager, overlay: &mut OverlayManager,
app: &mut AppState, app: &mut AppState,
) -> OverlayHandle { ) -> anyhow::Result<OverlayHandle> {
let key = format!("wlx-{}", self.state.name); let key = format!("wlx-{}", self.state.name);
log::debug!("Create overlay with key: {}", &key); log::debug!("Create overlay with key: {}", &key);
let handle = match overlay.create_overlay(&key, &key) { let handle = match overlay.create_overlay(&key, &key) {
@@ -51,7 +51,7 @@ impl OverlayData<OpenVrOverlayData> {
self.data.handle = Some(handle); self.data.handle = Some(handle);
self.data.color = Vec4::ONE; self.data.color = Vec4::ONE;
self.init(app); self.init(app)?;
if self.data.width < f32::EPSILON { if self.data.width < f32::EPSILON {
self.data.width = 1.0; self.data.width = 1.0;
@@ -63,15 +63,20 @@ impl OverlayData<OpenVrOverlayData> {
self.upload_curvature(overlay); self.upload_curvature(overlay);
self.upload_sort_order(overlay); self.upload_sort_order(overlay);
handle Ok(handle)
} }
pub(super) fn after_input(&mut self, overlay: &mut OverlayManager, app: &mut AppState) { pub(super) fn after_input(
&mut self,
overlay: &mut OverlayManager,
app: &mut AppState,
) -> anyhow::Result<()> {
if self.state.want_visible && !self.data.visible { if self.state.want_visible && !self.data.visible {
self.show_internal(overlay, app); self.show_internal(overlay, app)?;
} else if !self.state.want_visible && self.data.visible { } else if !self.state.want_visible && self.data.visible {
self.hide_internal(overlay, app); self.hide_internal(overlay, app)?;
} }
Ok(())
} }
pub(super) fn after_render(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) { pub(super) fn after_render(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) {
@@ -85,29 +90,37 @@ impl OverlayData<OpenVrOverlayData> {
} }
} }
fn show_internal(&mut self, overlay: &mut OverlayManager, app: &mut AppState) { fn show_internal(
&mut self,
overlay: &mut OverlayManager,
app: &mut AppState,
) -> anyhow::Result<()> {
let handle = match self.data.handle { let handle = match self.data.handle {
Some(handle) => handle, Some(handle) => handle,
None => self.initialize(overlay, app), None => self.initialize(overlay, app)?,
}; };
log::debug!("{}: show", self.state.name); log::debug!("{}: show", self.state.name);
if let Err(e) = overlay.set_visibility(handle, true) { if let Err(e) = overlay.set_visibility(handle, true) {
log::error!("{}: Failed to show overlay: {}", self.state.name, e); log::error!("{}: Failed to show overlay: {}", self.state.name, e);
} }
self.data.visible = true; self.data.visible = true;
self.backend.resume(app); self.backend.resume(app)
} }
fn hide_internal(&mut self, overlay: &mut OverlayManager, app: &mut AppState) { fn hide_internal(
&mut self,
overlay: &mut OverlayManager,
app: &mut AppState,
) -> anyhow::Result<()> {
let Some(handle) = self.data.handle else { let Some(handle) = self.data.handle else {
return; return Ok(());
}; };
log::debug!("{}: hide", self.state.name); log::debug!("{}: hide", self.state.name);
if let Err(e) = overlay.set_visibility(handle, false) { if let Err(e) = overlay.set_visibility(handle, false) {
log::error!("{}: Failed to hide overlay: {}", self.state.name, e); log::error!("{}: Failed to hide overlay: {}", self.state.name, e);
} }
self.data.visible = false; self.data.visible = false;
self.backend.pause(app); self.backend.pause(app)
} }
pub(super) fn upload_alpha(&self, overlay: &mut OverlayManager) { pub(super) fn upload_alpha(&self, overlay: &mut OverlayManager) {

View File

@@ -31,8 +31,9 @@ pub(super) struct LinePool {
} }
impl LinePool { impl LinePool {
pub(super) fn new(graphics: Arc<WlxGraphics>) -> Self { pub(super) fn new(graphics: Arc<WlxGraphics>) -> anyhow::Result<Self> {
let mut command_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit); let mut command_buffer =
graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
// TODO customizable colors // TODO customizable colors
let colors = [ let colors = [
@@ -43,20 +44,22 @@ impl LinePool {
[0xff, 0x00, 0x00, 0xff], [0xff, 0x00, 0x00, 0xff],
]; ];
let views = colors let views: anyhow::Result<Vec<Arc<ImageView>>> = colors
.into_iter() .into_iter()
.map(|color| { .map(
let tex = command_buffer.texture2d(1, 1, Format::R8G8B8A8_UNORM, &color); |color| match command_buffer.texture2d(1, 1, Format::R8G8B8A8_UNORM, &color) {
ImageView::new_default(tex).unwrap() Ok(tex) => ImageView::new_default(tex).map_err(|e| anyhow::anyhow!(e)),
}) Err(e) => Err(e),
},
)
.collect(); .collect();
command_buffer.build_and_execute_now(); command_buffer.build_and_execute_now()?;
LinePool { Ok(LinePool {
lines: IdMap::new(), lines: IdMap::new(),
colors: views, colors: views?,
} })
} }
pub(super) fn allocate( pub(super) fn allocate(
@@ -132,7 +135,7 @@ impl LinePool {
&'a mut self, &'a mut self,
xr: &'a XrState, xr: &'a XrState,
command_buffer: &mut WlxCommandBuffer, command_buffer: &mut WlxCommandBuffer,
) -> Result<Vec<xr::CompositionLayerQuad<xr::Vulkan>>, xr::sys::Result> { ) -> anyhow::Result<Vec<xr::CompositionLayerQuad<xr::Vulkan>>> {
let mut quads = Vec::new(); let mut quads = Vec::new();
for line in self.lines.values_mut() { for line in self.lines.values_mut() {

View File

@@ -55,12 +55,12 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
log::info!("Using environment blend mode: {:?}", environment_blend_mode); log::info!("Using environment blend mode: {:?}", environment_blend_mode);
let mut app_state = { let mut app_state = {
let graphics = WlxGraphics::new_openxr(xr_instance.clone(), system); let graphics = WlxGraphics::new_openxr(xr_instance.clone(), system)?;
AppState::from_graphics(graphics)? AppState::from_graphics(graphics)?
}; };
let mut overlays = OverlayContainer::<OpenXrOverlayData>::new(&mut app_state)?; let mut overlays = OverlayContainer::<OpenXrOverlayData>::new(&mut app_state)?;
let mut lines = LinePool::new(app_state.graphics.clone()); let mut lines = LinePool::new(app_state.graphics.clone())?;
#[cfg(feature = "osc")] #[cfg(feature = "osc")]
let mut osc_sender = let mut osc_sender =
@@ -211,9 +211,9 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
watch_fade(&mut app_state, overlays.mut_by_id(watch_id).unwrap()); // want panic watch_fade(&mut app_state, overlays.mut_by_id(watch_id).unwrap()); // want panic
overlays for o in overlays.iter_mut() {
.iter_mut() o.after_input(&mut app_state)?;
.for_each(|o| o.after_input(&mut app_state)); }
#[cfg(feature = "osc")] #[cfg(feature = "osc")]
if let Some(ref mut sender) = osc_sender { if let Some(ref mut sender) = osc_sender {
@@ -260,7 +260,7 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
let mut layers = vec![]; let mut layers = vec![];
let mut command_buffer = app_state let mut command_buffer = app_state
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit); .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
for o in overlays.iter_mut() { for o in overlays.iter_mut() {
if !o.state.want_visible { if !o.state.want_visible {
@@ -268,11 +268,11 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
} }
if !o.data.init { if !o.data.init {
o.init(&mut app_state); o.init(&mut app_state)?;
o.data.init = true; o.data.init = true;
} }
o.render(&mut app_state); o.render(&mut app_state)?;
let dist_sq = (app_state.input_state.hmd.translation - o.state.transform.translation) let dist_sq = (app_state.input_state.hmd.translation - o.state.transform.translation)
.length_squared(); .length_squared();
@@ -290,7 +290,7 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
layers.push((0.0, quad)); layers.push((0.0, quad));
} }
command_buffer.build_and_execute_now(); command_buffer.build_and_execute_now()?;
layers.sort_by(|a, b| b.0.total_cmp(&a.0)); layers.sort_by(|a, b| b.0.total_cmp(&a.0));

View File

@@ -77,14 +77,15 @@ impl OverlayData<OpenXrOverlayData> {
Ok(Some(quad)) Ok(Some(quad))
} }
pub(super) fn after_input(&mut self, app: &mut AppState) { pub(super) fn after_input(&mut self, app: &mut AppState) -> anyhow::Result<()> {
if self.data.last_visible != self.state.want_visible { if self.data.last_visible != self.state.want_visible {
if self.state.want_visible { if self.state.want_visible {
self.backend.resume(app); self.backend.resume(app)?;
} else { } else {
self.backend.pause(app); self.backend.pause(app)?;
} }
} }
self.data.last_visible = self.state.want_visible; self.data.last_visible = self.state.want_visible;
Ok(())
} }
} }

View File

@@ -1,5 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use anyhow::bail;
use ash::vk; use ash::vk;
use openxr as xr; use openxr as xr;
@@ -30,16 +31,17 @@ pub(super) fn create_swapchain_render_data(
mip_count: 1, mip_count: 1,
})?; })?;
let shaders = graphics.shared_shaders.read().unwrap(); let Ok(shaders) = graphics.shared_shaders.read() else {
bail!("Failed to lock shared shaders for reading");
};
let pipeline = graphics.create_pipeline_dynamic( let pipeline = graphics.create_pipeline_dynamic(
shaders.get("vert_common").unwrap().clone(), shaders.get("vert_common").unwrap().clone(), // want panic
shaders.get("frag_srgb").unwrap().clone(), shaders.get("frag_srgb").unwrap().clone(), // want panic
graphics.native_format, graphics.native_format,
); )?;
let images = swapchain let images = swapchain
.enumerate_images() .enumerate_images()?
.unwrap()
.into_iter() .into_iter()
.map(|handle| { .map(|handle| {
let vk_image = vk::Image::from_raw(handle); let vk_image = vk::Image::from_raw(handle);
@@ -83,29 +85,29 @@ impl SwapchainRenderData {
command_buffer: &mut WlxCommandBuffer, command_buffer: &mut WlxCommandBuffer,
view: Arc<ImageView>, view: Arc<ImageView>,
alpha: f32, alpha: f32,
) -> Result<xr::SwapchainSubImage<xr::Vulkan>, xr::sys::Result> { ) -> anyhow::Result<xr::SwapchainSubImage<xr::Vulkan>> {
let idx = self.swapchain.acquire_image()? as usize; let idx = self.swapchain.acquire_image()? as usize;
self.swapchain.wait_image(xr::Duration::INFINITE)?; self.swapchain.wait_image(xr::Duration::INFINITE)?;
let render_target = &mut self.images[idx]; let render_target = &mut self.images[idx];
command_buffer.begin_rendering(render_target.clone()); command_buffer.begin_rendering(render_target.clone())?;
let target_extent = render_target.image().extent(); let target_extent = render_target.image().extent();
let set0 = self let set0 = self
.pipeline .pipeline
.uniform_sampler(0, view.clone(), Filter::Linear); .uniform_sampler(0, view.clone(), Filter::Linear)?;
let set1 = self.pipeline.uniform_buffer(1, vec![alpha]); let set1 = self.pipeline.uniform_buffer(1, vec![alpha])?;
let pass = self.pipeline.create_pass( let pass = self.pipeline.create_pass(
[target_extent[0] as _, target_extent[1] as _], [target_extent[0] as _, target_extent[1] as _],
command_buffer.graphics.quad_verts.clone(), command_buffer.graphics.quad_verts.clone(),
command_buffer.graphics.quad_indices.clone(), command_buffer.graphics.quad_indices.clone(),
vec![set0, set1], vec![set0, set1],
); )?;
command_buffer.run_ref(&pass); command_buffer.run_ref(&pass)?;
command_buffer.end_rendering(); command_buffer.end_rendering()?;
self.swapchain.release_image()?; self.swapchain.release_image()?;

View File

@@ -6,6 +6,7 @@ use std::{
}, },
}; };
use anyhow::Ok;
use glam::{Affine2, Affine3A, Mat3A, Quat, Vec3, Vec3A}; use glam::{Affine2, Affine3A, Mat3A, Quat, Vec3, Vec3A};
use vulkano::image::view::ImageView; use vulkano::image::view::ImageView;
@@ -177,34 +178,35 @@ impl<T> OverlayData<T>
where where
T: Default, T: Default,
{ {
pub fn init(&mut self, app: &mut AppState) { pub fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
self.state.reset(app, true); self.state.reset(app, true);
self.backend.init(app); self.backend.init(app)
} }
pub fn render(&mut self, app: &mut AppState) { pub fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> {
self.backend.render(app); self.backend.render(app)
} }
pub fn view(&mut self) -> Option<Arc<ImageView>> { pub fn view(&mut self) -> Option<Arc<ImageView>> {
self.backend.view() self.backend.view()
} }
pub fn set_visible(&mut self, app: &mut AppState, visible: bool) { pub fn set_visible(&mut self, app: &mut AppState, visible: bool) -> anyhow::Result<()> {
let old_visible = self.state.want_visible; let old_visible = self.state.want_visible;
self.state.want_visible = visible; self.state.want_visible = visible;
if visible != old_visible { if visible != old_visible {
if visible { if visible {
self.backend.resume(app); self.backend.resume(app)?;
} else { } else {
self.backend.pause(app); self.backend.pause(app)?;
} }
} }
Ok(())
} }
} }
pub trait OverlayRenderer { pub trait OverlayRenderer {
fn init(&mut self, app: &mut AppState); fn init(&mut self, app: &mut AppState) -> anyhow::Result<()>;
fn pause(&mut self, app: &mut AppState); fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()>;
fn resume(&mut self, app: &mut AppState); fn resume(&mut self, app: &mut AppState) -> anyhow::Result<()>;
fn render(&mut self, app: &mut AppState); fn render(&mut self, app: &mut AppState) -> anyhow::Result<()>;
fn view(&mut self) -> Option<Arc<ImageView>>; fn view(&mut self) -> Option<Arc<ImageView>>;
fn extent(&self) -> [u32; 3]; fn extent(&self) -> [u32; 3];
} }
@@ -212,10 +214,18 @@ pub trait OverlayRenderer {
pub struct FallbackRenderer; pub struct FallbackRenderer;
impl OverlayRenderer for FallbackRenderer { impl OverlayRenderer for FallbackRenderer {
fn init(&mut self, _app: &mut AppState) {} fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
fn pause(&mut self, _app: &mut AppState) {} Ok(())
fn resume(&mut self, _app: &mut AppState) {} }
fn render(&mut self, _app: &mut AppState) {} fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
Ok(())
}
fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
Ok(())
}
fn render(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
Ok(())
}
fn view(&mut self) -> Option<Arc<ImageView>> { fn view(&mut self) -> Option<Arc<ImageView>> {
None None
} }
@@ -249,17 +259,17 @@ impl Default for SplitOverlayBackend {
impl OverlayBackend for SplitOverlayBackend {} impl OverlayBackend for SplitOverlayBackend {}
impl OverlayRenderer for SplitOverlayBackend { impl OverlayRenderer for SplitOverlayBackend {
fn init(&mut self, app: &mut AppState) { fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
self.renderer.init(app); self.renderer.init(app)
} }
fn pause(&mut self, app: &mut AppState) { fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()> {
self.renderer.pause(app); self.renderer.pause(app)
} }
fn resume(&mut self, app: &mut AppState) { fn resume(&mut self, app: &mut AppState) -> anyhow::Result<()> {
self.renderer.resume(app); self.renderer.resume(app)
} }
fn render(&mut self, app: &mut AppState) { fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> {
self.renderer.render(app); self.renderer.render(app)
} }
fn view(&mut self) -> Option<Arc<ImageView>> { fn view(&mut self) -> Option<Arc<ImageView>> {
self.renderer.view() self.renderer.view()

View File

@@ -1,6 +1,5 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
error::Error,
io::Cursor, io::Cursor,
os::{ os::{
fd::{FromRawFd, IntoRawFd}, fd::{FromRawFd, IntoRawFd},
@@ -10,6 +9,7 @@ use std::{
sync::{Arc, OnceLock, RwLock}, sync::{Arc, OnceLock, RwLock},
}; };
use anyhow::{anyhow, bail};
use ash::vk::{self, SubmitInfo}; use ash::vk::{self, SubmitInfo};
use smallvec::smallvec; use smallvec::smallvec;
use vulkano::{ use vulkano::{
@@ -118,7 +118,7 @@ pub struct WlxGraphics {
static VULKAN_LIBRARY: OnceLock<Arc<vulkano::VulkanLibrary>> = OnceLock::new(); static VULKAN_LIBRARY: OnceLock<Arc<vulkano::VulkanLibrary>> = OnceLock::new();
fn get_vulkan_library() -> &'static Arc<vulkano::VulkanLibrary> { fn get_vulkan_library() -> &'static Arc<vulkano::VulkanLibrary> {
VULKAN_LIBRARY.get_or_init(|| vulkano::VulkanLibrary::new().unwrap()) VULKAN_LIBRARY.get_or_init(|| vulkano::VulkanLibrary::new().unwrap()) // want panic
} }
#[cfg(feature = "openxr")] #[cfg(feature = "openxr")]
@@ -134,15 +134,18 @@ unsafe extern "system" fn get_instance_proc_addr(
impl WlxGraphics { impl WlxGraphics {
#[cfg(feature = "openxr")] #[cfg(feature = "openxr")]
pub fn new_openxr(xr_instance: openxr::Instance, system: openxr::SystemId) -> Arc<Self> { pub fn new_openxr(
xr_instance: openxr::Instance,
system: openxr::SystemId,
) -> anyhow::Result<Arc<Self>> {
use std::ffi::{self, c_char, CString}; use std::ffi::{self, c_char, CString};
use ash::vk::PhysicalDeviceDynamicRenderingFeatures; use ash::vk::PhysicalDeviceDynamicRenderingFeatures;
use vulkano::{Handle, Version}; use vulkano::{Handle, Version};
use winit::event_loop::EventLoop; use winit::event_loop::EventLoop;
let event_loop = EventLoop::new().unwrap(); let event_loop = EventLoop::new()?;
let mut instance_extensions = Surface::required_extensions(&event_loop).unwrap(); let mut instance_extensions = Surface::required_extensions(&event_loop)?;
instance_extensions.khr_get_physical_device_properties2 = true; instance_extensions.khr_get_physical_device_properties2 = true;
@@ -152,6 +155,7 @@ impl WlxGraphics {
.filter_map(|(name, enabled)| { .filter_map(|(name, enabled)| {
if enabled { if enabled {
Some(ffi::CString::new(name).unwrap().into_raw() as *const c_char) Some(ffi::CString::new(name).unwrap().into_raw() as *const c_char)
// want panic
} else { } else {
None None
} }
@@ -198,13 +202,11 @@ impl WlxGraphics {
PhysicalDevice::from_handle( PhysicalDevice::from_handle(
instance.clone(), instance.clone(),
vk::PhysicalDevice::from_raw( vk::PhysicalDevice::from_raw(
xr_instance xr_instance.vulkan_graphics_device(system, instance.handle().as_raw() as _)?
.vulkan_graphics_device(system, instance.handle().as_raw() as _) as _,
.unwrap() as _,
), ),
) )
} }?;
.unwrap();
let vk_device_properties = physical_device.properties(); let vk_device_properties = physical_device.properties();
if vk_device_properties.api_version < target_version { if vk_device_properties.api_version < target_version {
@@ -241,6 +243,7 @@ impl WlxGraphics {
.filter_map(|(name, enabled)| { .filter_map(|(name, enabled)| {
if enabled { if enabled {
Some(ffi::CString::new(name).unwrap().into_raw() as *const c_char) Some(ffi::CString::new(name).unwrap().into_raw() as *const c_char)
// want panic
} else { } else {
None None
} }
@@ -306,7 +309,9 @@ impl WlxGraphics {
let _ = CString::from_raw(c_string as _); let _ = CString::from_raw(c_string as _);
}); });
let queue = queues.next().unwrap(); let queue = queues
.next()
.ok_or_else(|| anyhow::anyhow!("no GPU queues available"))?;
let memory_allocator = memory_allocator(device.clone()); let memory_allocator = memory_allocator(device.clone());
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
@@ -321,7 +326,7 @@ impl WlxGraphics {
Default::default(), Default::default(),
)); ));
let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone()); let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?;
let me = Self { let me = Self {
instance, instance,
@@ -336,14 +341,14 @@ impl WlxGraphics {
shared_shaders: RwLock::new(HashMap::new()), shared_shaders: RwLock::new(HashMap::new()),
}; };
Arc::new(me) Ok(Arc::new(me))
} }
#[cfg(feature = "openvr")] #[cfg(feature = "openvr")]
pub fn new_openvr( pub fn new_openvr(
mut vk_instance_extensions: InstanceExtensions, mut vk_instance_extensions: InstanceExtensions,
mut vk_device_extensions_fn: impl FnMut(&PhysicalDevice) -> DeviceExtensions, mut vk_device_extensions_fn: impl FnMut(&PhysicalDevice) -> DeviceExtensions,
) -> Arc<Self> { ) -> anyhow::Result<Arc<Self>> {
//#[cfg(debug_assertions)] //#[cfg(debug_assertions)]
//let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()]; //let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()];
//#[cfg(not(debug_assertions))] //#[cfg(not(debug_assertions))]
@@ -361,8 +366,7 @@ impl WlxGraphics {
enabled_layers: layers, enabled_layers: layers,
..Default::default() ..Default::default()
}, },
) )?;
.unwrap();
let device_extensions = DeviceExtensions { let device_extensions = DeviceExtensions {
khr_external_memory: true, khr_external_memory: true,
@@ -375,8 +379,7 @@ impl WlxGraphics {
log::debug!("Device exts for app: {:?}", &device_extensions); log::debug!("Device exts for app: {:?}", &device_extensions);
let (physical_device, my_extensions, queue_family_index) = instance let (physical_device, my_extensions, queue_family_index) = instance
.enumerate_physical_devices() .enumerate_physical_devices()?
.unwrap()
.filter_map(|p| { .filter_map(|p| {
let runtime_extensions = vk_device_extensions_fn(&p); let runtime_extensions = vk_device_extensions_fn(&p);
log::debug!( log::debug!(
@@ -427,10 +430,11 @@ impl WlxGraphics {
}], }],
..Default::default() ..Default::default()
}, },
) )?;
.unwrap();
let queue = queues.next().unwrap(); let queue = queues
.next()
.ok_or_else(|| anyhow::anyhow!("no GPU queues available"))?;
let memory_allocator = memory_allocator(device.clone()); let memory_allocator = memory_allocator(device.clone());
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
@@ -445,7 +449,7 @@ impl WlxGraphics {
Default::default(), Default::default(),
)); ));
let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone()); let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?;
let me = Self { let me = Self {
instance, instance,
@@ -460,12 +464,12 @@ impl WlxGraphics {
shared_shaders: RwLock::new(HashMap::new()), shared_shaders: RwLock::new(HashMap::new()),
}; };
Arc::new(me) Ok(Arc::new(me))
} }
fn default_quad( fn default_quad(
memory_allocator: Arc<StandardMemoryAllocator>, memory_allocator: Arc<StandardMemoryAllocator>,
) -> (Subbuffer<[Vert2Uv]>, Subbuffer<[u16]>) { ) -> anyhow::Result<(Subbuffer<[Vert2Uv]>, Subbuffer<[u16]>)> {
let vertices = [ let vertices = [
Vert2Uv { Vert2Uv {
in_pos: [0., 0.], in_pos: [0., 0.],
@@ -496,8 +500,7 @@ impl WlxGraphics {
..Default::default() ..Default::default()
}, },
vertices.into_iter(), vertices.into_iter(),
) )?;
.unwrap();
let quad_indices = Buffer::from_iter( let quad_indices = Buffer::from_iter(
memory_allocator, memory_allocator,
@@ -511,10 +514,9 @@ impl WlxGraphics {
..Default::default() ..Default::default()
}, },
INDICES.iter().cloned(), INDICES.iter().cloned(),
) )?;
.unwrap();
(quad_verts, quad_indices) Ok((quad_verts, quad_indices))
} }
pub fn upload_verts( pub fn upload_verts(
@@ -525,7 +527,7 @@ impl WlxGraphics {
y: f32, y: f32,
w: f32, w: f32,
h: f32, h: f32,
) -> Subbuffer<[Vert2Uv]> { ) -> anyhow::Result<Subbuffer<[Vert2Uv]>> {
let rw = width; let rw = width;
let rh = height; let rh = height;
@@ -556,11 +558,15 @@ impl WlxGraphics {
self.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter()) self.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter())
} }
pub fn upload_buffer<T>(&self, usage: BufferUsage, contents: Iter<'_, T>) -> Subbuffer<[T]> pub fn upload_buffer<T>(
&self,
usage: BufferUsage,
contents: Iter<'_, T>,
) -> anyhow::Result<Subbuffer<[T]>>
where where
T: BufferContents + Clone, T: BufferContents + Clone,
{ {
Buffer::from_iter( Ok(Buffer::from_iter(
self.memory_allocator.clone(), self.memory_allocator.clone(),
BufferCreateInfo { BufferCreateInfo {
usage, usage,
@@ -572,14 +578,13 @@ impl WlxGraphics {
..Default::default() ..Default::default()
}, },
contents.cloned(), contents.cloned(),
) )?)
.unwrap()
} }
pub fn dmabuf_texture(&self, frame: DmabufFrame) -> Option<Arc<Image>> { pub fn dmabuf_texture(&self, frame: DmabufFrame) -> anyhow::Result<Arc<Image>> {
let extent = [frame.format.width, frame.format.height, 1]; let extent = [frame.format.width, frame.format.height, 1];
let format = fourcc_to_vk(frame.format.fourcc); let format = fourcc_to_vk(frame.format.fourcc)?;
let layouts: Vec<SubresourceLayout> = (0..frame.num_planes) let layouts: Vec<SubresourceLayout> = (0..frame.num_planes)
.into_iter() .into_iter()
@@ -608,8 +613,7 @@ impl WlxGraphics {
drm_format_modifier_plane_layouts: layouts, drm_format_modifier_plane_layouts: layouts,
..Default::default() ..Default::default()
}, },
) )?
.unwrap()
}; };
let requirements = image.memory_requirements()[0]; let requirements = image.memory_requirements()[0];
@@ -622,7 +626,7 @@ impl WlxGraphics {
..Default::default() ..Default::default()
}, },
) )
.unwrap(); .ok_or_else(|| anyhow!("failed to get memory type index"))?;
debug_assert!(self.device.enabled_extensions().khr_external_memory_fd); debug_assert!(self.device.enabled_extensions().khr_external_memory_fd);
debug_assert!(self.device.enabled_extensions().khr_external_memory); debug_assert!(self.device.enabled_extensions().khr_external_memory);
@@ -631,12 +635,11 @@ impl WlxGraphics {
// only do the 1st // only do the 1st
unsafe { unsafe {
let Some(fd) = frame.planes[0].fd else { let Some(fd) = frame.planes[0].fd else {
log::error!("DMA-buf plane has no FD"); bail!("DMA-buf plane has no FD");
return None;
}; };
let file = std::fs::File::from_raw_fd(fd); let file = std::fs::File::from_raw_fd(fd);
let new_file = file.try_clone().unwrap(); let new_file = file.try_clone()?;
file.into_raw_fd(); file.into_raw_fd();
let memory = DeviceMemory::allocate_unchecked( let memory = DeviceMemory::allocate_unchecked(
@@ -651,28 +654,31 @@ impl WlxGraphics {
file: new_file, file: new_file,
handle_type: ExternalMemoryHandleType::DmaBuf, handle_type: ExternalMemoryHandleType::DmaBuf,
}), }),
) )?;
.unwrap();
let mem_alloc = ResourceMemory::new_dedicated(memory); let mem_alloc = ResourceMemory::new_dedicated(memory);
match image.bind_memory_unchecked([mem_alloc]) { match image.bind_memory_unchecked([mem_alloc]) {
Ok(image) => Some(Arc::new(image)), Ok(image) => Ok(Arc::new(image)),
Err(e) => { Err(e) => {
log::error!("Failed to bind memory to image: {}", e.0); bail!("Failed to bind memory to image: {}", e.0);
return None;
} }
} }
} }
} }
pub fn render_texture(&self, width: u32, height: u32, format: Format) -> Arc<Image> { pub fn render_texture(
&self,
width: u32,
height: u32,
format: Format,
) -> anyhow::Result<Arc<Image>> {
log::debug!( log::debug!(
"Render texture: {}x{} {}MB", "Render texture: {}x{} {}MB",
width, width,
height, height,
(width * height * 4) / (1024 * 1024) (width * height * 4) / (1024 * 1024)
); );
Image::new( Ok(Image::new(
self.memory_allocator.clone(), self.memory_allocator.clone(),
ImageCreateInfo { ImageCreateInfo {
image_type: ImageType::Dim2d, image_type: ImageType::Dim2d,
@@ -684,8 +690,7 @@ impl WlxGraphics {
..Default::default() ..Default::default()
}, },
AllocationCreateInfo::default(), AllocationCreateInfo::default(),
) )?)
.unwrap()
} }
pub fn create_pipeline( pub fn create_pipeline(
@@ -694,14 +699,14 @@ impl WlxGraphics {
vert: Arc<ShaderModule>, vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>, frag: Arc<ShaderModule>,
format: Format, format: Format,
) -> Arc<WlxPipeline<WlxPipelineLegacy>> { ) -> anyhow::Result<Arc<WlxPipeline<WlxPipelineLegacy>>> {
Arc::new(WlxPipeline::<WlxPipelineLegacy>::new( Ok(Arc::new(WlxPipeline::<WlxPipelineLegacy>::new(
render_target, render_target,
self.clone(), self.clone(),
vert, vert,
frag, frag,
format, format,
)) )?))
} }
pub fn create_pipeline_with_layouts( pub fn create_pipeline_with_layouts(
@@ -712,8 +717,8 @@ impl WlxGraphics {
format: Format, format: Format,
initial_layout: ImageLayout, initial_layout: ImageLayout,
final_layout: ImageLayout, final_layout: ImageLayout,
) -> Arc<WlxPipeline<WlxPipelineLegacy>> { ) -> anyhow::Result<Arc<WlxPipeline<WlxPipelineLegacy>>> {
Arc::new(WlxPipeline::<WlxPipelineLegacy>::new_with_layout( Ok(Arc::new(WlxPipeline::<WlxPipelineLegacy>::new_with_layout(
render_target, render_target,
self.clone(), self.clone(),
vert, vert,
@@ -721,7 +726,7 @@ impl WlxGraphics {
format, format,
initial_layout, initial_layout,
final_layout, final_layout,
)) )?))
} }
pub fn create_pipeline_dynamic( pub fn create_pipeline_dynamic(
@@ -729,16 +734,19 @@ impl WlxGraphics {
vert: Arc<ShaderModule>, vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>, frag: Arc<ShaderModule>,
format: Format, format: Format,
) -> Arc<WlxPipeline<WlxPipelineDynamic>> { ) -> anyhow::Result<Arc<WlxPipeline<WlxPipelineDynamic>>> {
Arc::new(WlxPipeline::<WlxPipelineDynamic>::new( Ok(Arc::new(WlxPipeline::<WlxPipelineDynamic>::new(
self.clone(), self.clone(),
vert, vert,
frag, frag,
format, format,
)) )?))
} }
pub fn create_command_buffer(self: &Arc<Self>, usage: CommandBufferUsage) -> WlxCommandBuffer { pub fn create_command_buffer(
self: &Arc<Self>,
usage: CommandBufferUsage,
) -> anyhow::Result<WlxCommandBuffer> {
let command_buffer = RecordingCommandBuffer::new( let command_buffer = RecordingCommandBuffer::new(
self.command_buffer_allocator.clone(), self.command_buffer_allocator.clone(),
self.queue.queue_family_index(), self.queue.queue_family_index(),
@@ -748,12 +756,11 @@ impl WlxGraphics {
inheritance_info: None, inheritance_info: None,
..Default::default() ..Default::default()
}, },
) )?;
.unwrap(); Ok(WlxCommandBuffer {
WlxCommandBuffer {
graphics: self.clone(), graphics: self.clone(),
command_buffer, command_buffer,
} })
} }
pub fn transition_layout( pub fn transition_layout(
@@ -761,7 +768,7 @@ impl WlxGraphics {
image: Arc<Image>, image: Arc<Image>,
old_layout: ImageLayout, old_layout: ImageLayout,
new_layout: ImageLayout, new_layout: ImageLayout,
) -> Fence { ) -> anyhow::Result<Fence> {
let barrier = ImageMemoryBarrier { let barrier = ImageMemoryBarrier {
src_stages: PipelineStages::ALL_TRANSFER, src_stages: PipelineStages::ALL_TRANSFER,
src_access: AccessFlags::TRANSFER_WRITE, src_access: AccessFlags::TRANSFER_WRITE,
@@ -783,23 +790,19 @@ impl WlxGraphics {
inheritance_info: None, inheritance_info: None,
..Default::default() ..Default::default()
}, },
) )?;
.unwrap();
builder builder.pipeline_barrier(&DependencyInfo {
.pipeline_barrier(&DependencyInfo { image_memory_barriers: smallvec![barrier],
image_memory_barriers: smallvec![barrier], ..Default::default()
..Default::default() })?;
}) builder.end()?
.unwrap();
builder.end().unwrap()
}; };
let fence = vulkano::sync::fence::Fence::new( let fence = vulkano::sync::fence::Fence::new(
self.device.clone(), self.device.clone(),
vulkano::sync::fence::FenceCreateInfo::default(), vulkano::sync::fence::FenceCreateInfo::default(),
) )?;
.unwrap();
let fns = self.device.fns(); let fns = self.device.fns();
unsafe { unsafe {
@@ -813,10 +816,9 @@ impl WlxGraphics {
fence.handle(), fence.handle(),
) )
} }
.result() .result()?;
.unwrap();
fence Ok(fence)
} }
} }
@@ -826,42 +828,41 @@ pub struct WlxCommandBuffer {
} }
impl WlxCommandBuffer { impl WlxCommandBuffer {
pub fn begin_render_pass(&mut self, pipeline: &WlxPipeline<WlxPipelineLegacy>) { pub fn begin_render_pass(
self.command_buffer &mut self,
.begin_render_pass( pipeline: &WlxPipeline<WlxPipelineLegacy>,
RenderPassBeginInfo { ) -> anyhow::Result<()> {
clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())], self.command_buffer.begin_render_pass(
..RenderPassBeginInfo::framebuffer(pipeline.data.framebuffer.clone()) RenderPassBeginInfo {
}, clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
SubpassBeginInfo { ..RenderPassBeginInfo::framebuffer(pipeline.data.framebuffer.clone())
contents: SubpassContents::SecondaryCommandBuffers, },
..Default::default() SubpassBeginInfo {
},
)
.unwrap();
}
pub fn begin_rendering(&mut self, render_target: Arc<ImageView>) {
self.command_buffer
.begin_rendering(RenderingInfo {
contents: SubpassContents::SecondaryCommandBuffers, contents: SubpassContents::SecondaryCommandBuffers,
color_attachments: vec![Some(RenderingAttachmentInfo {
load_op: AttachmentLoadOp::Clear,
store_op: AttachmentStoreOp::Store,
clear_value: Some([0.0, 0.0, 0.0, 1.0].into()),
..RenderingAttachmentInfo::image_view(render_target.clone())
})],
..Default::default() ..Default::default()
}) },
.unwrap(); )?;
Ok(())
} }
pub fn run_ref<D>(&mut self, pass: &WlxPass<D>) -> &mut Self { pub fn begin_rendering(&mut self, render_target: Arc<ImageView>) -> anyhow::Result<()> {
let _ = self self.command_buffer.begin_rendering(RenderingInfo {
.command_buffer contents: SubpassContents::SecondaryCommandBuffers,
.execute_commands(pass.command_buffer.clone()) color_attachments: vec![Some(RenderingAttachmentInfo {
.unwrap(); load_op: AttachmentLoadOp::Clear,
self store_op: AttachmentStoreOp::Store,
clear_value: Some([0.0, 0.0, 0.0, 1.0].into()),
..RenderingAttachmentInfo::image_view(render_target.clone())
})],
..Default::default()
})?;
Ok(())
}
pub fn run_ref<D>(&mut self, pass: &WlxPass<D>) -> anyhow::Result<()> {
self.command_buffer
.execute_commands(pass.command_buffer.clone())?;
Ok(())
} }
pub fn texture2d( pub fn texture2d(
@@ -870,7 +871,7 @@ impl WlxCommandBuffer {
height: u32, height: u32,
format: Format, format: Format,
data: &[u8], data: &[u8],
) -> Arc<Image> { ) -> anyhow::Result<Arc<Image>> {
log::debug!( log::debug!(
"Texture2D: {}x{} {}MB", "Texture2D: {}x{} {}MB",
width, width,
@@ -887,8 +888,7 @@ impl WlxCommandBuffer {
..Default::default() ..Default::default()
}, },
AllocationCreateInfo::default(), AllocationCreateInfo::default(),
) )?;
.unwrap();
let buffer: Subbuffer<[u8]> = Buffer::new_slice( let buffer: Subbuffer<[u8]> = Buffer::new_slice(
self.graphics.memory_allocator.clone(), self.graphics.memory_allocator.clone(),
@@ -902,57 +902,57 @@ impl WlxCommandBuffer {
..Default::default() ..Default::default()
}, },
data.len() as DeviceSize, data.len() as DeviceSize,
) )?;
.unwrap();
buffer.write().unwrap().copy_from_slice(data); buffer.write()?.copy_from_slice(data);
self.command_buffer self.command_buffer
.copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(buffer, image.clone())) .copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(buffer, image.clone()))?;
.unwrap();
image Ok(image)
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn texture2d_png(&mut self, bytes: Vec<u8>) -> Arc<Image> { pub fn texture2d_png(&mut self, bytes: Vec<u8>) -> anyhow::Result<Arc<Image>> {
let cursor = Cursor::new(bytes); let cursor = Cursor::new(bytes);
let decoder = png::Decoder::new(cursor); let decoder = png::Decoder::new(cursor);
let mut reader = decoder.read_info().unwrap(); let mut reader = decoder.read_info()?;
let info = reader.info(); let info = reader.info();
let width = info.width; let width = info.width;
let height = info.height; let height = info.height;
let mut image_data = Vec::new(); let mut image_data = Vec::new();
image_data.resize((info.width * info.height * 4) as usize, 0); image_data.resize((info.width * info.height * 4) as usize, 0);
reader.next_frame(&mut image_data).unwrap(); reader.next_frame(&mut image_data)?;
self.texture2d(width, height, Format::R8G8B8A8_UNORM, &image_data) self.texture2d(width, height, Format::R8G8B8A8_UNORM, &image_data)
} }
} }
impl WlxCommandBuffer { impl WlxCommandBuffer {
pub fn end_render_pass(&mut self) { pub fn end_render_pass(&mut self) -> anyhow::Result<()> {
self.command_buffer self.command_buffer
.end_render_pass(SubpassEndInfo::default()) .end_render_pass(SubpassEndInfo::default())?;
.unwrap(); Ok(())
} }
pub fn end_rendering(&mut self) { pub fn end_rendering(&mut self) -> anyhow::Result<()> {
self.command_buffer.end_rendering().unwrap(); self.command_buffer.end_rendering()?;
Ok(())
} }
pub fn build(self) -> Arc<CommandBuffer> { pub fn build(self) -> anyhow::Result<Arc<CommandBuffer>> {
self.command_buffer.end().unwrap() Ok(self.command_buffer.end()?)
} }
pub fn build_and_execute(self) -> CommandBufferExecFuture<NowFuture> { pub fn build_and_execute(self) -> anyhow::Result<CommandBufferExecFuture<NowFuture>> {
let queue = self.graphics.queue.clone(); let queue = self.graphics.queue.clone();
self.build().execute(queue).unwrap() Ok(self.build()?.execute(queue)?)
} }
pub fn build_and_execute_now(self) { pub fn build_and_execute_now(self) -> anyhow::Result<()> {
let mut exec = self.build_and_execute(); let mut exec = self.build_and_execute()?;
exec.flush().unwrap(); exec.flush()?;
exec.cleanup_finished(); exec.cleanup_finished();
Ok(())
} }
} }
@@ -977,13 +977,11 @@ impl WlxPipeline<WlxPipelineDynamic> {
vert: Arc<ShaderModule>, vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>, frag: Arc<ShaderModule>,
format: Format, format: Format,
) -> Self { ) -> anyhow::Result<Self> {
let vep = vert.entry_point("main").unwrap(); let vep = vert.entry_point("main").unwrap(); // want panic
let fep = frag.entry_point("main").unwrap(); let fep = frag.entry_point("main").unwrap(); // want panic
let vertex_input_state = Vert2Uv::per_vertex() let vertex_input_state = Vert2Uv::per_vertex().definition(&vep.info().input_interface)?;
.definition(&vep.info().input_interface)
.unwrap();
let stages = smallvec![ let stages = smallvec![
vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep), vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep),
@@ -993,10 +991,8 @@ impl WlxPipeline<WlxPipelineDynamic> {
let layout = PipelineLayout::new( let layout = PipelineLayout::new(
graphics.device.clone(), graphics.device.clone(),
PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages)
.into_pipeline_layout_create_info(graphics.device.clone()) .into_pipeline_layout_create_info(graphics.device.clone())?,
.unwrap(), )?;
)
.unwrap();
let subpass = PipelineRenderingCreateInfo { let subpass = PipelineRenderingCreateInfo {
color_attachment_formats: vec![Some(format)], color_attachment_formats: vec![Some(format)],
@@ -1024,15 +1020,14 @@ impl WlxPipeline<WlxPipelineDynamic> {
subpass: Some(subpass.into()), subpass: Some(subpass.into()),
..GraphicsPipelineCreateInfo::layout(layout) ..GraphicsPipelineCreateInfo::layout(layout)
}, },
) )?;
.unwrap();
Self { Ok(Self {
graphics, graphics,
pipeline, pipeline,
format, format,
data: WlxPipelineDynamic {}, data: WlxPipelineDynamic {},
} })
} }
pub fn create_pass( pub fn create_pass(
self: &Arc<Self>, self: &Arc<Self>,
@@ -1040,7 +1035,7 @@ impl WlxPipeline<WlxPipelineDynamic> {
vertex_buffer: Subbuffer<[Vert2Uv]>, vertex_buffer: Subbuffer<[Vert2Uv]>,
index_buffer: Subbuffer<[u16]>, index_buffer: Subbuffer<[u16]>,
descriptor_sets: Vec<Arc<DescriptorSet>>, descriptor_sets: Vec<Arc<DescriptorSet>>,
) -> WlxPass<WlxPipelineDynamic> { ) -> anyhow::Result<WlxPass<WlxPipelineDynamic>> {
WlxPass::<WlxPipelineDynamic>::new( WlxPass::<WlxPipelineDynamic>::new(
self.clone(), self.clone(),
dimensions, dimensions,
@@ -1058,7 +1053,7 @@ impl WlxPipeline<WlxPipelineLegacy> {
vert: Arc<ShaderModule>, vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>, frag: Arc<ShaderModule>,
format: Format, format: Format,
) -> Self { ) -> anyhow::Result<Self> {
let render_pass = vulkano::single_pass_renderpass!( let render_pass = vulkano::single_pass_renderpass!(
graphics.device.clone(), graphics.device.clone(),
attachments: { attachments: {
@@ -1073,8 +1068,7 @@ impl WlxPipeline<WlxPipelineLegacy> {
color: [color], color: [color],
depth_stencil: {}, depth_stencil: {},
}, },
) )?;
.unwrap();
Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format) Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format)
} }
@@ -1087,7 +1081,7 @@ impl WlxPipeline<WlxPipelineLegacy> {
format: Format, format: Format,
initial_layout: ImageLayout, initial_layout: ImageLayout,
final_layout: ImageLayout, final_layout: ImageLayout,
) -> Self { ) -> anyhow::Result<Self> {
let render_pass_description = RenderPassCreateInfo { let render_pass_description = RenderPassCreateInfo {
attachments: vec![AttachmentDescription { attachments: vec![AttachmentDescription {
format, format,
@@ -1109,8 +1103,7 @@ impl WlxPipeline<WlxPipelineLegacy> {
..Default::default() ..Default::default()
}; };
let render_pass = let render_pass = RenderPass::new(graphics.device.clone(), render_pass_description)?;
RenderPass::new(graphics.device.clone(), render_pass_description).unwrap();
Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format) Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format)
} }
@@ -1122,13 +1115,11 @@ impl WlxPipeline<WlxPipelineLegacy> {
vert: Arc<ShaderModule>, vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>, frag: Arc<ShaderModule>,
format: Format, format: Format,
) -> Self { ) -> anyhow::Result<Self> {
let vep = vert.entry_point("main").unwrap(); let vep = vert.entry_point("main").unwrap(); // want panic
let fep = frag.entry_point("main").unwrap(); let fep = frag.entry_point("main").unwrap(); // want panic
let vertex_input_state = Vert2Uv::per_vertex() let vertex_input_state = Vert2Uv::per_vertex().definition(&vep.info().input_interface)?;
.definition(&vep.info().input_interface)
.unwrap();
let stages = smallvec![ let stages = smallvec![
vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep), vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep),
@@ -1138,10 +1129,8 @@ impl WlxPipeline<WlxPipelineLegacy> {
let layout = PipelineLayout::new( let layout = PipelineLayout::new(
graphics.device.clone(), graphics.device.clone(),
PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages)
.into_pipeline_layout_create_info(graphics.device.clone()) .into_pipeline_layout_create_info(graphics.device.clone())?,
.unwrap(), )?;
)
.unwrap();
let framebuffer = Framebuffer::new( let framebuffer = Framebuffer::new(
render_pass.clone(), render_pass.clone(),
@@ -1149,8 +1138,7 @@ impl WlxPipeline<WlxPipelineLegacy> {
attachments: vec![render_target.clone()], attachments: vec![render_target.clone()],
..Default::default() ..Default::default()
}, },
) )?;
.unwrap();
let pipeline = GraphicsPipeline::new( let pipeline = GraphicsPipeline::new(
graphics.device.clone(), graphics.device.clone(),
@@ -1170,13 +1158,16 @@ impl WlxPipeline<WlxPipelineLegacy> {
rasterization_state: Some(RasterizationState::default()), rasterization_state: Some(RasterizationState::default()),
multisample_state: Some(MultisampleState::default()), multisample_state: Some(MultisampleState::default()),
dynamic_state: [DynamicState::Viewport].into_iter().collect(), dynamic_state: [DynamicState::Viewport].into_iter().collect(),
subpass: Some(Subpass::from(render_pass.clone(), 0).unwrap().into()), subpass: Some(
Subpass::from(render_pass.clone(), 0)
.ok_or_else(|| anyhow!("Failed to create subpass"))?
.into(),
),
..GraphicsPipelineCreateInfo::layout(layout) ..GraphicsPipelineCreateInfo::layout(layout)
}, },
) )?;
.unwrap();
Self { Ok(Self {
graphics, graphics,
pipeline, pipeline,
format, format,
@@ -1185,7 +1176,7 @@ impl WlxPipeline<WlxPipelineLegacy> {
framebuffer, framebuffer,
view: render_target, view: render_target,
}, },
} })
} }
pub fn create_pass( pub fn create_pass(
@@ -1194,7 +1185,7 @@ impl WlxPipeline<WlxPipelineLegacy> {
vertex_buffer: Subbuffer<[Vert2Uv]>, vertex_buffer: Subbuffer<[Vert2Uv]>,
index_buffer: Subbuffer<[u16]>, index_buffer: Subbuffer<[u16]>,
descriptor_sets: Vec<Arc<DescriptorSet>>, descriptor_sets: Vec<Arc<DescriptorSet>>,
) -> WlxPass<WlxPipelineLegacy> { ) -> anyhow::Result<WlxPass<WlxPipelineLegacy>> {
WlxPass::<WlxPipelineLegacy>::new( WlxPass::<WlxPipelineLegacy>::new(
self.clone(), self.clone(),
dimensions, dimensions,
@@ -1215,7 +1206,7 @@ impl<D> WlxPipeline<D> {
set: usize, set: usize,
texture: Arc<ImageView>, texture: Arc<ImageView>,
filter: Filter, filter: Filter,
) -> Arc<DescriptorSet> { ) -> anyhow::Result<Arc<DescriptorSet>> {
let sampler = Sampler::new( let sampler = Sampler::new(
self.graphics.device.clone(), self.graphics.device.clone(),
SamplerCreateInfo { SamplerCreateInfo {
@@ -1224,21 +1215,19 @@ impl<D> WlxPipeline<D> {
address_mode: [SamplerAddressMode::Repeat; 3], address_mode: [SamplerAddressMode::Repeat; 3],
..Default::default() ..Default::default()
}, },
) )?;
.unwrap();
let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); // want panic
DescriptorSet::new( Ok(DescriptorSet::new(
self.graphics.descriptor_set_allocator.clone(), self.graphics.descriptor_set_allocator.clone(),
layout.clone(), layout.clone(),
[WriteDescriptorSet::image_view_sampler(0, texture, sampler)], [WriteDescriptorSet::image_view_sampler(0, texture, sampler)],
[], [],
) )?)
.unwrap()
} }
pub fn uniform_buffer<T>(&self, set: usize, data: Vec<T>) -> Arc<DescriptorSet> pub fn uniform_buffer<T>(&self, set: usize, data: Vec<T>) -> anyhow::Result<Arc<DescriptorSet>>
where where
T: BufferContents + Copy, T: BufferContents + Copy,
{ {
@@ -1253,19 +1242,18 @@ impl<D> WlxPipeline<D> {
); );
let uniform_buffer_subbuffer = { let uniform_buffer_subbuffer = {
let subbuffer = uniform_buffer.allocate_slice(data.len() as _).unwrap(); let subbuffer = uniform_buffer.allocate_slice(data.len() as _)?;
subbuffer.write().unwrap().copy_from_slice(data.as_slice()); subbuffer.write()?.copy_from_slice(data.as_slice());
subbuffer subbuffer
}; };
let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); // want panic
DescriptorSet::new( Ok(DescriptorSet::new(
self.graphics.descriptor_set_allocator.clone(), self.graphics.descriptor_set_allocator.clone(),
layout.clone(), layout.clone(),
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)], [WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
[], [],
) )?)
.unwrap()
} }
} }
@@ -1285,7 +1273,7 @@ impl WlxPass<WlxPipelineLegacy> {
vertex_buffer: Subbuffer<[Vert2Uv]>, vertex_buffer: Subbuffer<[Vert2Uv]>,
index_buffer: Subbuffer<[u16]>, index_buffer: Subbuffer<[u16]>,
descriptor_sets: Vec<Arc<DescriptorSet>>, descriptor_sets: Vec<Arc<DescriptorSet>>,
) -> Self { ) -> anyhow::Result<Self> {
let viewport = Viewport { let viewport = Viewport {
offset: [0.0, 0.0], offset: [0.0, 0.0],
extent: dimensions, extent: dimensions,
@@ -1302,7 +1290,8 @@ impl WlxPass<WlxPipelineLegacy> {
inheritance_info: Some(CommandBufferInheritanceInfo { inheritance_info: Some(CommandBufferInheritanceInfo {
render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRenderPass( render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRenderPass(
CommandBufferInheritanceRenderPassInfo { CommandBufferInheritanceRenderPassInfo {
subpass: Subpass::from(pipeline.data.render_pass.clone(), 0).unwrap(), subpass: Subpass::from(pipeline.data.render_pass.clone(), 0)
.ok_or_else(|| anyhow!("Failed to get subpass"))?,
framebuffer: None, framebuffer: None,
}, },
)), )),
@@ -1310,43 +1299,30 @@ impl WlxPass<WlxPipelineLegacy> {
}), }),
..Default::default() ..Default::default()
}, },
) )?;
.unwrap();
unsafe { unsafe {
command_buffer command_buffer
.set_viewport(0, smallvec![viewport]) .set_viewport(0, smallvec![viewport])?
.unwrap() .bind_pipeline_graphics(pipeline_inner)?
.bind_pipeline_graphics(pipeline_inner)
.unwrap()
.bind_descriptor_sets( .bind_descriptor_sets(
PipelineBindPoint::Graphics, PipelineBindPoint::Graphics,
pipeline.inner().layout().clone(), pipeline.inner().layout().clone(),
0, 0,
descriptor_sets.clone(), descriptor_sets.clone(),
) )?
.unwrap() .bind_vertex_buffers(0, vertex_buffer.clone())?
.bind_vertex_buffers(0, vertex_buffer.clone()) .bind_index_buffer(index_buffer.clone())?
.unwrap() .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)?
.bind_index_buffer(index_buffer.clone())
.unwrap()
.draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)
.or_else(|err| {
if let Some(source) = err.source() {
log::error!("Failed to draw: {}", source);
}
Err(err)
})
.unwrap()
}; };
Self { Ok(Self {
pipeline, pipeline,
vertex_buffer, vertex_buffer,
index_buffer, index_buffer,
descriptor_sets, descriptor_sets,
command_buffer: command_buffer.end().unwrap(), command_buffer: command_buffer.end()?,
} })
} }
} }
@@ -1357,7 +1333,7 @@ impl WlxPass<WlxPipelineDynamic> {
vertex_buffer: Subbuffer<[Vert2Uv]>, vertex_buffer: Subbuffer<[Vert2Uv]>,
index_buffer: Subbuffer<[u16]>, index_buffer: Subbuffer<[u16]>,
descriptor_sets: Vec<Arc<DescriptorSet>>, descriptor_sets: Vec<Arc<DescriptorSet>>,
) -> Self { ) -> anyhow::Result<Self> {
let viewport = Viewport { let viewport = Viewport {
offset: [0.0, 0.0], offset: [0.0, 0.0],
extent: dimensions, extent: dimensions,
@@ -1381,53 +1357,40 @@ impl WlxPass<WlxPipelineDynamic> {
}), }),
..Default::default() ..Default::default()
}, },
) )?;
.unwrap();
unsafe { unsafe {
command_buffer command_buffer
.set_viewport(0, smallvec![viewport]) .set_viewport(0, smallvec![viewport])?
.unwrap() .bind_pipeline_graphics(pipeline_inner)?
.bind_pipeline_graphics(pipeline_inner)
.unwrap()
.bind_descriptor_sets( .bind_descriptor_sets(
PipelineBindPoint::Graphics, PipelineBindPoint::Graphics,
pipeline.inner().layout().clone(), pipeline.inner().layout().clone(),
0, 0,
descriptor_sets.clone(), descriptor_sets.clone(),
) )?
.unwrap() .bind_vertex_buffers(0, vertex_buffer.clone())?
.bind_vertex_buffers(0, vertex_buffer.clone()) .bind_index_buffer(index_buffer.clone())?
.unwrap() .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)?
.bind_index_buffer(index_buffer.clone())
.unwrap()
.draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)
.or_else(|err| {
if let Some(source) = err.source() {
log::error!("Failed to draw: {}", source);
}
Err(err)
})
.unwrap()
}; };
Self { Ok(Self {
pipeline, pipeline,
vertex_buffer, vertex_buffer,
index_buffer, index_buffer,
descriptor_sets, descriptor_sets,
command_buffer: command_buffer.end().unwrap(), command_buffer: command_buffer.end()?,
} })
} }
} }
pub fn fourcc_to_vk(fourcc: FourCC) -> Format { pub fn fourcc_to_vk(fourcc: FourCC) -> anyhow::Result<Format> {
match fourcc.value { match fourcc.value {
DRM_FORMAT_ABGR8888 => Format::R8G8B8A8_UNORM, DRM_FORMAT_ABGR8888 => Ok(Format::R8G8B8A8_UNORM),
DRM_FORMAT_XBGR8888 => Format::R8G8B8A8_UNORM, DRM_FORMAT_XBGR8888 => Ok(Format::R8G8B8A8_UNORM),
DRM_FORMAT_ARGB8888 => Format::B8G8R8A8_UNORM, DRM_FORMAT_ARGB8888 => Ok(Format::B8G8R8A8_UNORM),
DRM_FORMAT_XRGB8888 => Format::B8G8R8A8_UNORM, DRM_FORMAT_XRGB8888 => Ok(Format::B8G8R8A8_UNORM),
_ => panic!("Unsupported memfd format {}", fourcc), _ => bail!("Unsupported format {}", fourcc),
} }
} }

View File

@@ -35,15 +35,15 @@ pub struct Glyph {
} }
impl FontCache { impl FontCache {
pub fn new() -> Self { pub fn new() -> anyhow::Result<Self> {
let ft = Library::init().expect("Failed to initialize freetype"); let ft = Library::init()?;
let fc = FontConfig::default(); let fc = FontConfig::default();
FontCache { Ok(FontCache {
fc, fc,
ft, ft,
collections: IdMap::new(), collections: IdMap::new(),
} })
} }
pub fn get_text_size( pub fn get_text_size(
@@ -51,7 +51,7 @@ impl FontCache {
text: &str, text: &str,
size: isize, size: isize,
graphics: Arc<WlxGraphics>, graphics: Arc<WlxGraphics>,
) -> (f32, f32) { ) -> anyhow::Result<(f32, f32)> {
let sizef = size as f32; let sizef = size as f32;
let height = sizef + ((text.lines().count() as f32) - 1f32) * (sizef * 1.5); let height = sizef + ((text.lines().count() as f32) - 1f32) * (sizef * 1.5);
@@ -60,9 +60,10 @@ impl FontCache {
for line in text.lines() { for line in text.lines() {
let w: f32 = line let w: f32 = line
.chars() .chars()
.map(|c| { .filter_map(|c| {
self.get_glyph_for_cp(c as usize, size, graphics.clone()) self.get_glyph_for_cp(c as usize, size, graphics.clone())
.advance .map(|glyph| glyph.advance)
.ok()
}) })
.sum(); .sum();
@@ -70,7 +71,7 @@ impl FontCache {
max_w = w; max_w = w;
} }
} }
(max_w, height) Ok((max_w, height))
} }
pub fn get_glyphs( pub fn get_glyphs(
@@ -78,14 +79,14 @@ impl FontCache {
text: &str, text: &str,
size: isize, size: isize,
graphics: Arc<WlxGraphics>, graphics: Arc<WlxGraphics>,
) -> Vec<Rc<Glyph>> { ) -> anyhow::Result<Vec<Rc<Glyph>>> {
let mut glyphs = Vec::new(); let mut glyphs = Vec::new();
for line in text.lines() { for line in text.lines() {
for c in line.chars() { for c in line.chars() {
glyphs.push(self.get_glyph_for_cp(c as usize, size, graphics.clone())); glyphs.push(self.get_glyph_for_cp(c as usize, size, graphics.clone())?);
} }
} }
glyphs Ok(glyphs)
} }
fn get_font_for_cp(&mut self, cp: usize, size: isize) -> usize { fn get_font_for_cp(&mut self, cp: usize, size: isize) -> usize {
@@ -98,7 +99,7 @@ impl FontCache {
}, },
); );
} }
let coll = self.collections.get_mut(size).unwrap(); let coll = self.collections.get_mut(size).unwrap(); // safe because of the insert above
if let Some(font) = coll.cp_map.get(cp) { if let Some(font) = coll.cp_map.get(cp) {
return *font; return *font;
@@ -167,28 +168,28 @@ impl FontCache {
cp: usize, cp: usize,
size: isize, size: isize,
graphics: Arc<WlxGraphics>, graphics: Arc<WlxGraphics>,
) -> Rc<Glyph> { ) -> anyhow::Result<Rc<Glyph>> {
let key = self.get_font_for_cp(cp, size); let key = self.get_font_for_cp(cp, size);
let font = &mut self.collections[size].fonts[key]; let font = &mut self.collections[size].fonts[key];
if let Some(glyph) = font.glyphs.get(cp) { if let Some(glyph) = font.glyphs.get(cp) {
return glyph.clone(); return Ok(glyph.clone());
} }
if font.face.load_char(cp, LoadFlag::DEFAULT).is_err() { if font.face.load_char(cp, LoadFlag::DEFAULT).is_err() {
return font.glyphs[0].clone(); return Ok(font.glyphs[0].clone());
} }
let glyph = font.face.glyph(); let glyph = font.face.glyph();
if glyph.render_glyph(freetype::RenderMode::Normal).is_err() { if glyph.render_glyph(freetype::RenderMode::Normal).is_err() {
return font.glyphs[0].clone(); return Ok(font.glyphs[0].clone());
} }
let bmp = glyph.bitmap(); let bmp = glyph.bitmap();
let buf = bmp.buffer().to_vec(); let buf = bmp.buffer().to_vec();
if buf.len() == 0 { if buf.len() == 0 {
return font.glyphs[0].clone(); return Ok(font.glyphs[0].clone());
} }
let metrics = glyph.metrics(); let metrics = glyph.metrics();
@@ -197,12 +198,12 @@ impl FontCache {
Ok(PixelMode::Gray) => Format::R8_UNORM, Ok(PixelMode::Gray) => Format::R8_UNORM,
Ok(PixelMode::Gray2) => Format::R16_SFLOAT, Ok(PixelMode::Gray2) => Format::R16_SFLOAT,
Ok(PixelMode::Gray4) => Format::R32_SFLOAT, Ok(PixelMode::Gray4) => Format::R32_SFLOAT,
_ => return font.glyphs[0].clone(), _ => return Ok(font.glyphs[0].clone()),
}; };
let mut cmd_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit); let mut cmd_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
let texture = cmd_buffer.texture2d(bmp.width() as _, bmp.rows() as _, format, &buf); let texture = cmd_buffer.texture2d(bmp.width() as _, bmp.rows() as _, format, &buf)?;
cmd_buffer.build_and_execute_now(); cmd_buffer.build_and_execute_now()?;
let g = Glyph { let g = Glyph {
tex: Some(texture), tex: Some(texture),
@@ -214,6 +215,6 @@ impl FontCache {
}; };
font.glyphs.insert(cp, Rc::new(g)); font.glyphs.insert(cp, Rc::new(g));
font.glyphs[cp].clone() Ok(font.glyphs[cp].clone())
} }
} }

View File

@@ -60,13 +60,13 @@ impl<D, S> CanvasBuilder<D, S> {
graphics: Arc<WlxGraphics>, graphics: Arc<WlxGraphics>,
format: Format, format: Format,
data: D, data: D,
) -> Self { ) -> anyhow::Result<Self> {
Self { Ok(Self {
canvas: Canvas::new(width, height, graphics, format, data), canvas: Canvas::new(width, height, graphics, format, data)?,
bg_color: Vec3::ZERO, bg_color: Vec3::ZERO,
fg_color: Vec3::ONE, fg_color: Vec3::ONE,
font_size: 16, font_size: 16,
} })
} }
pub fn build(self) -> Canvas<D, S> { pub fn build(self) -> Canvas<D, S> {
@@ -225,62 +225,64 @@ impl<D, S> Canvas<D, S> {
graphics: Arc<WlxGraphics>, graphics: Arc<WlxGraphics>,
format: Format, format: Format,
data: D, data: D,
) -> Self { ) -> anyhow::Result<Self> {
let tex_fg = graphics.render_texture(width as _, height as _, format); let tex_fg = graphics.render_texture(width as _, height as _, format)?;
let tex_bg = graphics.render_texture(width as _, height as _, format); let tex_bg = graphics.render_texture(width as _, height as _, format)?;
let tex_final = graphics.render_texture(width as _, height as _, format); let tex_final = graphics.render_texture(width as _, height as _, format)?;
let view_fg = ImageView::new_default(tex_fg.clone()).unwrap(); let view_fg = ImageView::new_default(tex_fg.clone())?;
let view_bg = ImageView::new_default(tex_bg.clone()).unwrap(); let view_bg = ImageView::new_default(tex_bg.clone())?;
let view_final = ImageView::new_default(tex_final.clone()).unwrap(); let view_final = ImageView::new_default(tex_final.clone())?;
let shaders = graphics.shared_shaders.read().unwrap(); let Ok(shaders) = graphics.shared_shaders.read() else {
bail!("Failed to lock shared shaders for reading");
};
let pipeline_bg_color = graphics.create_pipeline( let pipeline_bg_color = graphics.create_pipeline(
view_bg.clone(), view_bg.clone(),
shaders.get("vert_common").unwrap().clone(), shaders.get("vert_common").unwrap().clone(), // want panic
shaders.get("frag_color").unwrap().clone(), shaders.get("frag_color").unwrap().clone(), // want panic
format, format,
); )?;
let pipeline_fg_glyph = graphics.create_pipeline( let pipeline_fg_glyph = graphics.create_pipeline(
view_fg.clone(), view_fg.clone(),
shaders.get("vert_common").unwrap().clone(), shaders.get("vert_common").unwrap().clone(), // want panic
shaders.get("frag_glyph").unwrap().clone(), shaders.get("frag_glyph").unwrap().clone(), // want panic
format, format,
); )?;
let vertex_buffer = let vertex_buffer =
graphics.upload_verts(width as _, height as _, 0., 0., width as _, height as _); graphics.upload_verts(width as _, height as _, 0., 0., width as _, height as _)?;
let pipeline_final = graphics.create_pipeline_with_layouts( let pipeline_final = graphics.create_pipeline_with_layouts(
view_final.clone(), view_final.clone(),
shaders.get("vert_common").unwrap().clone(), shaders.get("vert_common").unwrap().clone(), // want panic
shaders.get("frag_sprite").unwrap().clone(), shaders.get("frag_sprite").unwrap().clone(), // want panic
format, format,
ImageLayout::TransferSrcOptimal, ImageLayout::TransferSrcOptimal,
ImageLayout::TransferSrcOptimal, ImageLayout::TransferSrcOptimal,
); )?;
let set_fg = pipeline_final.uniform_sampler(0, view_fg.clone(), Filter::Linear); let set_fg = pipeline_final.uniform_sampler(0, view_fg.clone(), Filter::Linear)?;
let set_bg = pipeline_final.uniform_sampler(0, view_bg.clone(), Filter::Linear); let set_bg = pipeline_final.uniform_sampler(0, view_bg.clone(), Filter::Linear)?;
let pass_fg = pipeline_final.create_pass( let pass_fg = pipeline_final.create_pass(
[width as _, height as _], [width as _, height as _],
vertex_buffer.clone(), vertex_buffer.clone(),
graphics.quad_indices.clone(), graphics.quad_indices.clone(),
vec![set_fg], vec![set_fg],
); )?;
let pass_bg = pipeline_final.create_pass( let pass_bg = pipeline_final.create_pass(
[width as _, height as _], [width as _, height as _],
vertex_buffer.clone(), vertex_buffer.clone(),
graphics.quad_indices.clone(), graphics.quad_indices.clone(),
vec![set_bg], vec![set_bg],
); )?;
let stride = width / RES_DIVIDER; let stride = width / RES_DIVIDER;
let rows = height / RES_DIVIDER; let rows = height / RES_DIVIDER;
Self { Ok(Self {
canvas: CanvasData { canvas: CanvasData {
data, data,
width, width,
@@ -299,7 +301,7 @@ impl<D, S> Canvas<D, S> {
view_final, view_final,
pass_fg, pass_fg,
pass_bg, pass_bg,
} })
} }
fn interactive_set_idx(&mut self, x: f32, y: f32, w: f32, h: f32, idx: usize) { fn interactive_set_idx(&mut self, x: f32, y: f32, w: f32, h: f32, idx: usize) {
@@ -325,34 +327,34 @@ impl<D, S> Canvas<D, S> {
self.interact_map[y * self.interact_stride + x].map(|x| x as usize) self.interact_map[y * self.interact_stride + x].map(|x| x as usize)
} }
fn render_bg(&mut self, app: &mut AppState) { fn render_bg(&mut self, app: &mut AppState) -> anyhow::Result<()> {
let mut cmd_buffer = self let mut cmd_buffer = self
.canvas .canvas
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit); .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
cmd_buffer.begin_render_pass(&self.canvas.pipeline_bg_color); cmd_buffer.begin_render_pass(&self.canvas.pipeline_bg_color)?;
for c in self.controls.iter_mut() { for c in self.controls.iter_mut() {
if let Some(fun) = c.on_render_bg { if let Some(fun) = c.on_render_bg {
fun(c, &self.canvas, app, &mut cmd_buffer); fun(c, &self.canvas, app, &mut cmd_buffer)?;
} }
} }
cmd_buffer.end_render_pass(); cmd_buffer.end_render_pass()?;
cmd_buffer.build_and_execute_now(); cmd_buffer.build_and_execute_now()
} }
fn render_fg(&mut self, app: &mut AppState) { fn render_fg(&mut self, app: &mut AppState) -> anyhow::Result<()> {
let mut cmd_buffer = self let mut cmd_buffer = self
.canvas .canvas
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit); .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
cmd_buffer.begin_render_pass(&self.canvas.pipeline_fg_glyph); cmd_buffer.begin_render_pass(&self.canvas.pipeline_fg_glyph)?;
for c in self.controls.iter_mut() { for c in self.controls.iter_mut() {
if let Some(fun) = c.on_render_fg { if let Some(fun) = c.on_render_fg {
fun(c, &self.canvas, app, &mut cmd_buffer); fun(c, &self.canvas, app, &mut cmd_buffer)?;
} }
} }
cmd_buffer.end_render_pass(); cmd_buffer.end_render_pass()?;
cmd_buffer.build_and_execute_now(); cmd_buffer.build_and_execute_now()
} }
} }
@@ -410,13 +412,17 @@ impl<D, S> InteractionHandler for Canvas<D, S> {
} }
impl<D, S> OverlayRenderer for Canvas<D, S> { impl<D, S> OverlayRenderer for Canvas<D, S> {
fn init(&mut self, app: &mut AppState) { fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
self.render_bg(app); self.render_bg(app)?;
self.render_fg(app); self.render_fg(app)
} }
fn pause(&mut self, _app: &mut AppState) {} fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
fn resume(&mut self, _app: &mut AppState) {} Ok(())
fn render(&mut self, app: &mut AppState) { }
fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
Ok(())
}
fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> {
let mut dirty = false; let mut dirty = false;
for c in self.controls.iter_mut() { for c in self.controls.iter_mut() {
@@ -430,8 +436,8 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
} }
if dirty { if dirty {
self.render_bg(app); self.render_bg(app)?;
self.render_fg(app); self.render_fg(app)?;
} }
/* /*
@@ -454,17 +460,17 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
let mut cmd_buffer = self let mut cmd_buffer = self
.canvas .canvas
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit); .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
cmd_buffer.begin_render_pass(&self.canvas.pipeline_final); cmd_buffer.begin_render_pass(&self.canvas.pipeline_final)?;
// static background // static background
cmd_buffer.run_ref(&self.pass_bg); cmd_buffer.run_ref(&self.pass_bg)?;
for (i, c) in self.controls.iter_mut().enumerate() { for (i, c) in self.controls.iter_mut().enumerate() {
if let Some(render) = c.on_render_hl { if let Some(render) = c.on_render_hl {
if let Some(test) = c.test_highlight { if let Some(test) = c.test_highlight {
if let Some(hl_color) = test(c, &mut self.canvas.data, app) { if let Some(hl_color) = test(c, &mut self.canvas.data, app) {
render(c, &self.canvas, app, &mut cmd_buffer, hl_color); render(c, &self.canvas, app, &mut cmd_buffer, hl_color)?;
} }
} }
if self.hover_controls.contains(&Some(i)) { if self.hover_controls.contains(&Some(i)) {
@@ -474,16 +480,16 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
app, app,
&mut cmd_buffer, &mut cmd_buffer,
Vec4::new(1., 1., 1., 0.3), Vec4::new(1., 1., 1., 0.3),
); )?;
} }
} }
} }
// mostly static text // mostly static text
cmd_buffer.run_ref(&self.pass_fg); cmd_buffer.run_ref(&self.pass_fg)?;
cmd_buffer.end_render_pass(); cmd_buffer.end_render_pass()?;
cmd_buffer.build_and_execute_now(); cmd_buffer.build_and_execute_now()
/* /*
self.canvas self.canvas
@@ -523,9 +529,15 @@ pub struct Control<D, S> {
pub on_scroll: Option<fn(&mut Self, &mut D, &mut AppState, f32)>, pub on_scroll: Option<fn(&mut Self, &mut D, &mut AppState, f32)>,
pub test_highlight: Option<fn(&Self, &mut D, &mut AppState) -> Option<Vec4>>, pub test_highlight: Option<fn(&Self, &mut D, &mut AppState) -> Option<Vec4>>,
on_render_bg: Option<fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer)>, on_render_bg: Option<
on_render_hl: Option<fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer, Vec4)>, fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer) -> anyhow::Result<()>,
on_render_fg: Option<fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer)>, >,
on_render_hl: Option<
fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer, Vec4) -> anyhow::Result<()>,
>,
on_render_fg: Option<
fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer) -> anyhow::Result<()>,
>,
} }
impl<D, S> Control<D, S> { impl<D, S> Control<D, S> {
@@ -577,7 +589,7 @@ impl<D, S> Control<D, S> {
canvas: &CanvasData<D>, canvas: &CanvasData<D>,
_: &mut AppState, _: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer, cmd_buffer: &mut WlxCommandBuffer,
) { ) -> anyhow::Result<()> {
let pass = { let pass = {
let vertex_buffer = canvas.graphics.upload_verts( let vertex_buffer = canvas.graphics.upload_verts(
canvas.width as _, canvas.width as _,
@@ -586,20 +598,20 @@ impl<D, S> Control<D, S> {
self.rect.y, self.rect.y,
self.rect.w, self.rect.w,
self.rect.h, self.rect.h,
); )?;
let set0 = canvas.pipeline_bg_color.uniform_buffer( let set0 = canvas.pipeline_bg_color.uniform_buffer(
0, 0,
vec![self.bg_color.x, self.bg_color.y, self.bg_color.z, 1.], vec![self.bg_color.x, self.bg_color.y, self.bg_color.z, 1.],
); )?;
canvas.pipeline_bg_color.create_pass( canvas.pipeline_bg_color.create_pass(
[canvas.width as _, canvas.height as _], [canvas.width as _, canvas.height as _],
vertex_buffer, vertex_buffer,
canvas.graphics.quad_indices.clone(), canvas.graphics.quad_indices.clone(),
vec![set0], vec![set0],
) )?
}; };
cmd_buffer.run_ref(&pass); cmd_buffer.run_ref(&pass)
} }
fn render_highlight( fn render_highlight(
@@ -608,7 +620,7 @@ impl<D, S> Control<D, S> {
_: &mut AppState, _: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer, cmd_buffer: &mut WlxCommandBuffer,
color: Vec4, color: Vec4,
) { ) -> anyhow::Result<()> {
let vertex_buffer = canvas.graphics.upload_verts( let vertex_buffer = canvas.graphics.upload_verts(
canvas.width as _, canvas.width as _,
canvas.height as _, canvas.height as _,
@@ -616,20 +628,20 @@ impl<D, S> Control<D, S> {
self.rect.y, self.rect.y,
self.rect.w, self.rect.w,
self.rect.h, self.rect.h,
); )?;
let set0 = canvas let set0 = canvas
.pipeline_bg_color .pipeline_bg_color
.uniform_buffer(0, color.to_array().to_vec()); .uniform_buffer(0, color.to_array().to_vec())?;
let pass = canvas.pipeline_bg_color.create_pass( let pass = canvas.pipeline_bg_color.create_pass(
[canvas.width as _, canvas.height as _], [canvas.width as _, canvas.height as _],
vertex_buffer.clone(), vertex_buffer.clone(),
canvas.graphics.quad_indices.clone(), canvas.graphics.quad_indices.clone(),
vec![set0], vec![set0],
); )?;
cmd_buffer.run_ref(&pass); cmd_buffer.run_ref(&pass)
} }
fn render_text( fn render_text(
@@ -637,11 +649,14 @@ impl<D, S> Control<D, S> {
canvas: &CanvasData<D>, canvas: &CanvasData<D>,
app: &mut AppState, app: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer, cmd_buffer: &mut WlxCommandBuffer,
) { ) -> anyhow::Result<()> {
let mut cur_y = self.rect.y; let mut cur_y = self.rect.y;
for line in self.text.lines() { for line in self.text.lines() {
let mut cur_x = self.rect.x; let mut cur_x = self.rect.x;
for glyph in app.fc.get_glyphs(line, self.size, canvas.graphics.clone()) { for glyph in app
.fc
.get_glyphs(line, self.size, canvas.graphics.clone())?
{
if let Some(tex) = glyph.tex.clone() { if let Some(tex) = glyph.tex.clone() {
let vertex_buffer = canvas.graphics.upload_verts( let vertex_buffer = canvas.graphics.upload_verts(
canvas.width as _, canvas.width as _,
@@ -650,43 +665,47 @@ impl<D, S> Control<D, S> {
cur_y - glyph.top, cur_y - glyph.top,
glyph.width, glyph.width,
glyph.height, glyph.height,
); )?;
let set0 = canvas.pipeline_fg_glyph.uniform_sampler( let set0 = canvas.pipeline_fg_glyph.uniform_sampler(
0, 0,
ImageView::new_default(tex).unwrap(), ImageView::new_default(tex).unwrap(),
Filter::Linear, Filter::Linear,
); )?;
let set1 = canvas.pipeline_fg_glyph.uniform_buffer( let set1 = canvas.pipeline_fg_glyph.uniform_buffer(
1, 1,
vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.], vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.],
); )?;
let pass = canvas.pipeline_fg_glyph.create_pass( let pass = canvas.pipeline_fg_glyph.create_pass(
[canvas.width as _, canvas.height as _], [canvas.width as _, canvas.height as _],
vertex_buffer, vertex_buffer,
canvas.graphics.quad_indices.clone(), canvas.graphics.quad_indices.clone(),
vec![set0, set1], vec![set0, set1],
); )?;
cmd_buffer.run_ref(&pass); cmd_buffer.run_ref(&pass)?;
} }
cur_x += glyph.advance; cur_x += glyph.advance;
} }
cur_y += (self.size as f32) * 1.5; cur_y += (self.size as f32) * 1.5;
} }
Ok(())
} }
fn render_text_centered( fn render_text_centered(
&self, &self,
canvas: &CanvasData<D>, canvas: &CanvasData<D>,
app: &mut AppState, app: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer, cmd_buffer: &mut WlxCommandBuffer,
) { ) -> anyhow::Result<()> {
let (w, h) = app let (w, h) = app
.fc .fc
.get_text_size(&self.text, self.size, canvas.graphics.clone()); .get_text_size(&self.text, self.size, canvas.graphics.clone())?;
let mut cur_y = self.rect.y + (self.rect.h) - (h * 0.5); let mut cur_y = self.rect.y + (self.rect.h) - (h * 0.5);
for line in self.text.lines() { for line in self.text.lines() {
let mut cur_x = self.rect.x + (self.rect.w * 0.5) - (w * 0.5); let mut cur_x = self.rect.x + (self.rect.w * 0.5) - (w * 0.5);
for glyph in app.fc.get_glyphs(line, self.size, canvas.graphics.clone()) { for glyph in app
.fc
.get_glyphs(line, self.size, canvas.graphics.clone())?
{
if let Some(tex) = glyph.tex.clone() { if let Some(tex) = glyph.tex.clone() {
let vertex_buffer = canvas.graphics.upload_verts( let vertex_buffer = canvas.graphics.upload_verts(
canvas.width as _, canvas.width as _,
@@ -695,27 +714,28 @@ impl<D, S> Control<D, S> {
cur_y - glyph.top, cur_y - glyph.top,
glyph.width, glyph.width,
glyph.height, glyph.height,
); )?;
let set0 = canvas.pipeline_fg_glyph.uniform_sampler( let set0 = canvas.pipeline_fg_glyph.uniform_sampler(
0, 0,
ImageView::new_default(tex).unwrap(), ImageView::new_default(tex).unwrap(),
Filter::Linear, Filter::Linear,
); )?;
let set1 = canvas.pipeline_fg_glyph.uniform_buffer( let set1 = canvas.pipeline_fg_glyph.uniform_buffer(
1, 1,
vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.], vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.],
); )?;
let pass = canvas.pipeline_fg_glyph.create_pass( let pass = canvas.pipeline_fg_glyph.create_pass(
[canvas.width as _, canvas.height as _], [canvas.width as _, canvas.height as _],
vertex_buffer, vertex_buffer,
canvas.graphics.quad_indices.clone(), canvas.graphics.quad_indices.clone(),
vec![set0, set1], vec![set0, set1],
); )?;
cmd_buffer.run_ref(&pass); cmd_buffer.run_ref(&pass)?;
} }
cur_x += glyph.advance; cur_x += glyph.advance;
} }
cur_y += (self.size as f32) * 1.5; cur_y += (self.size as f32) * 1.5;
} }
Ok(())
} }
} }

View File

@@ -27,7 +27,7 @@ const AUTO_RELEASE_MODS: [KeyModifier; 5] = [SHIFT, CTRL, ALT, SUPER, META];
pub const KEYBOARD_NAME: &str = "kbd"; pub const KEYBOARD_NAME: &str = "kbd";
pub fn create_keyboard<O>(app: &AppState) -> OverlayData<O> pub fn create_keyboard<O>(app: &AppState) -> anyhow::Result<OverlayData<O>>
where where
O: Default, O: Default,
{ {
@@ -50,7 +50,7 @@ where
app.graphics.clone(), app.graphics.clone(),
app.format, app.format,
data, data,
); )?;
canvas.bg_color = color_parse("#101010").unwrap(); //safe canvas.bg_color = color_parse("#101010").unwrap(); //safe
canvas.panel(0., 0., size.x, size.y); canvas.panel(0., 0., size.x, size.y);
@@ -118,7 +118,7 @@ where
let width = LAYOUT.row_size * 0.05 * app.session.config.keyboard_scale; let width = LAYOUT.row_size * 0.05 * app.session.config.keyboard_scale;
OverlayData { Ok(OverlayData {
state: OverlayState { state: OverlayState {
name: KEYBOARD_NAME.into(), name: KEYBOARD_NAME.into(),
size: (size.x as _, size.y as _), size: (size.x as _, size.y as _),
@@ -132,7 +132,7 @@ where
}, },
backend: Box::new(canvas), backend: Box::new(canvas),
..Default::default() ..Default::default()
} })
} }
fn key_press( fn key_press(

View File

@@ -129,9 +129,9 @@ struct ScreenPipeline {
impl ScreenPipeline { impl ScreenPipeline {
fn new(extent: &[u32; 3], app: &mut AppState) -> anyhow::Result<ScreenPipeline> { fn new(extent: &[u32; 3], app: &mut AppState) -> anyhow::Result<ScreenPipeline> {
let texture = app let texture =
.graphics app.graphics
.render_texture(extent[0], extent[1], app.graphics.native_format); .render_texture(extent[0], extent[1], app.graphics.native_format)?;
let view = ImageView::new_default(texture)?; let view = ImageView::new_default(texture)?;
@@ -144,7 +144,7 @@ impl ScreenPipeline {
shaders.get("vert_common").unwrap().clone(), // want panic shaders.get("vert_common").unwrap().clone(), // want panic
shaders.get("frag_sprite").unwrap().clone(), // want panic shaders.get("frag_sprite").unwrap().clone(), // want panic
app.graphics.native_format, app.graphics.native_format,
); )?;
let extentf = [extent[0] as f32, extent[1] as f32]; let extentf = [extent[0] as f32, extent[1] as f32];
@@ -156,9 +156,9 @@ impl ScreenPipeline {
}) })
} }
fn ensure_mouse_initialized(&mut self, uploads: &mut WlxCommandBuffer) { fn ensure_mouse_initialized(&mut self, uploads: &mut WlxCommandBuffer) -> anyhow::Result<()> {
if self.mouse.is_some() { if self.mouse.is_some() {
return; return Ok(());
} }
#[rustfmt::skip] #[rustfmt::skip]
@@ -170,26 +170,32 @@ impl ScreenPipeline {
]; ];
let mouse_tex = let mouse_tex =
uploads.texture2d(4, 4, vulkano::format::Format::R8G8B8A8_UNORM, &mouse_bytes); uploads.texture2d(4, 4, vulkano::format::Format::R8G8B8A8_UNORM, &mouse_bytes)?;
self.mouse = Some(ImageView::new_default(mouse_tex).unwrap()); self.mouse = Some(ImageView::new_default(mouse_tex)?);
Ok(())
} }
fn render(&mut self, image: Arc<Image>, mouse: Option<&MouseMeta>, app: &mut AppState) { fn render(
&mut self,
image: Arc<Image>,
mouse: Option<&MouseMeta>,
app: &mut AppState,
) -> anyhow::Result<()> {
let mut cmd = app let mut cmd = app
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit); .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
let view = ImageView::new_default(image).unwrap(); let view = ImageView::new_default(image)?;
let set0 = self.pipeline.uniform_sampler(0, view, Filter::Linear); let set0 = self.pipeline.uniform_sampler(0, view, Filter::Linear)?;
let pass = self.pipeline.create_pass( let pass = self.pipeline.create_pass(
self.extentf, self.extentf,
app.graphics.quad_verts.clone(), app.graphics.quad_verts.clone(),
app.graphics.quad_indices.clone(), app.graphics.quad_indices.clone(),
vec![set0], vec![set0],
); )?;
cmd.begin_render_pass(&self.pipeline); cmd.begin_render_pass(&self.pipeline)?;
cmd.run_ref(&pass); cmd.run_ref(&pass)?;
if let (Some(mouse), Some(mouse_view)) = (mouse, self.mouse.clone()) { if let (Some(mouse), Some(mouse_view)) = (mouse, self.mouse.clone()) {
let vertex_buffer = app.graphics.upload_verts( let vertex_buffer = app.graphics.upload_verts(
@@ -199,25 +205,24 @@ impl ScreenPipeline {
mouse.y * self.extentf[1] - 2., mouse.y * self.extentf[1] - 2.,
4.0, 4.0,
4.0, 4.0,
); )?;
let set0 = self let set0 = self
.pipeline .pipeline
.uniform_sampler(0, mouse_view.clone(), Filter::Linear); .uniform_sampler(0, mouse_view.clone(), Filter::Linear)?;
let pass = self.pipeline.create_pass( let pass = self.pipeline.create_pass(
self.extentf, self.extentf,
vertex_buffer, vertex_buffer,
app.graphics.quad_indices.clone(), app.graphics.quad_indices.clone(),
vec![set0], vec![set0],
); )?;
cmd.run_ref(&pass); cmd.run_ref(&pass)?;
} }
cmd.end_render_pass(); cmd.end_render_pass()?;
cmd.build_and_execute_now()
cmd.build_and_execute_now();
} }
} }
@@ -289,8 +294,10 @@ impl ScreenRenderer {
} }
impl OverlayRenderer for ScreenRenderer { impl OverlayRenderer for ScreenRenderer {
fn init(&mut self, _app: &mut AppState) {} fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
fn render(&mut self, app: &mut AppState) { Ok(())
}
fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> {
let receiver = self.receiver.get_or_insert_with(|| { let receiver = self.receiver.get_or_insert_with(|| {
let allow_dmabuf = &*app.session.config.capture_method != "pw_fallback"; let allow_dmabuf = &*app.session.config.capture_method != "pw_fallback";
@@ -313,7 +320,9 @@ impl OverlayRenderer for ScreenRenderer {
let mut final_formats = vec![]; let mut final_formats = vec![];
for &f in &possible_formats { for &f in &possible_formats {
let vk_fmt = fourcc_to_vk(f); let Ok(vk_fmt) = fourcc_to_vk(f) else {
continue;
};
let Ok(props) = graphics.device.physical_device().format_properties(vk_fmt) let Ok(props) = graphics.device.physical_device().format_properties(vk_fmt)
else { else {
continue; continue;
@@ -347,8 +356,8 @@ impl OverlayRenderer for ScreenRenderer {
log::error!("Invalid frame"); log::error!("Invalid frame");
continue; continue;
} }
if let Some(new) = app.graphics.dmabuf_texture(frame) { if let Ok(new) = app.graphics.dmabuf_texture(frame) {
let view = ImageView::new_default(new.clone()).unwrap(); let view = ImageView::new_default(new.clone())?;
self.last_view = Some(view); self.last_view = Some(view);
} else { } else {
@@ -358,14 +367,14 @@ impl OverlayRenderer for ScreenRenderer {
WlxFrame::MemFd(frame) => { WlxFrame::MemFd(frame) => {
let mut upload = app let mut upload = app
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit); .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
let Some(fd) = frame.plane.fd else { let Some(fd) = frame.plane.fd else {
log::error!("No fd"); log::error!("No fd");
continue; continue;
}; };
log::debug!("{}: New MemFd frame", self.name); 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;
let offset = frame.plane.offset as i64; let offset = frame.plane.offset as i64;
@@ -384,42 +393,42 @@ impl OverlayRenderer for ScreenRenderer {
let data = unsafe { slice::from_raw_parts(map, len) }; let data = unsafe { slice::from_raw_parts(map, len) };
let image = let image =
upload.texture2d(frame.format.width, frame.format.height, format, &data); upload.texture2d(frame.format.width, frame.format.height, format, &data)?;
upload.build_and_execute_now(); upload.build_and_execute_now()?;
unsafe { libc::munmap(map as *mut _, len) }; unsafe { libc::munmap(map as *mut _, len) };
self.last_view = Some(ImageView::new_default(image).unwrap()); self.last_view = Some(ImageView::new_default(image)?);
self.capture.request_new_frame(); self.capture.request_new_frame();
} }
WlxFrame::MemPtr(frame) => { WlxFrame::MemPtr(frame) => {
log::debug!("{}: New MemPtr frame", self.name); 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)?;
let format = fourcc_to_vk(frame.format.fourcc); let format = fourcc_to_vk(frame.format.fourcc)?;
let data = unsafe { slice::from_raw_parts(frame.ptr as *const u8, frame.size) }; let data = unsafe { slice::from_raw_parts(frame.ptr as *const u8, frame.size) };
let image = let image =
upload.texture2d(frame.format.width, frame.format.height, format, &data); upload.texture2d(frame.format.width, frame.format.height, format, &data)?;
let mut pipeline = None; let mut pipeline = None;
if mouse.is_some() { if mouse.is_some() {
let new_pipeline = self.pipeline.get_or_insert_with(|| { let new_pipeline = self.pipeline.get_or_insert_with(|| {
let mut pipeline = ScreenPipeline::new(&self.extent, app).unwrap(); let mut pipeline = ScreenPipeline::new(&self.extent, app).unwrap();
self.last_view = Some(pipeline.view.clone()); self.last_view = Some(pipeline.view.clone());
pipeline.ensure_mouse_initialized(&mut upload); pipeline.ensure_mouse_initialized(&mut upload).unwrap(); // TODO
pipeline pipeline
}); });
pipeline = Some(new_pipeline); pipeline = Some(new_pipeline);
} }
upload.build_and_execute_now(); upload.build_and_execute_now()?;
if let Some(pipeline) = pipeline { if let Some(pipeline) = pipeline {
pipeline.render(image, mouse.as_ref(), app); pipeline.render(image, mouse.as_ref(), app)?;
} else { } else {
let view = ImageView::new_default(image).unwrap(); let view = ImageView::new_default(image).unwrap();
self.last_view = Some(view); self.last_view = Some(view);
@@ -431,12 +440,15 @@ impl OverlayRenderer for ScreenRenderer {
} }
}; };
} }
Ok(())
} }
fn pause(&mut self, _app: &mut AppState) { fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
self.capture.pause(); self.capture.pause();
Ok(())
} }
fn resume(&mut self, _app: &mut AppState) { fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
self.capture.resume(); self.capture.resume();
Ok(())
} }
fn view(&mut self) -> Option<Arc<ImageView>> { fn view(&mut self) -> Option<Arc<ImageView>> {
self.last_view.clone() self.last_view.clone()

View File

@@ -33,7 +33,10 @@ const FALLBACK_COLOR: Vec3 = Vec3 {
pub const WATCH_NAME: &str = "watch"; pub const WATCH_NAME: &str = "watch";
pub const WATCH_SCALE: f32 = 0.11; pub const WATCH_SCALE: f32 = 0.11;
pub fn create_watch<O>(state: &AppState, screens: &[OverlayData<O>]) -> OverlayData<O> pub fn create_watch<O>(
state: &AppState,
screens: &[OverlayData<O>],
) -> anyhow::Result<OverlayData<O>>
where where
O: Default, O: Default,
{ {
@@ -45,7 +48,7 @@ where
state.graphics.clone(), state.graphics.clone(),
state.format, state.format,
(), (),
); )?;
let empty_str: Arc<str> = Arc::from(""); let empty_str: Arc<str> = Arc::from("");
for elem in config.watch_elements.into_iter() { for elem in config.watch_elements.into_iter() {
@@ -275,7 +278,7 @@ where
let relative_to = RelativeTo::Hand(state.session.watch_hand); let relative_to = RelativeTo::Hand(state.session.watch_hand);
OverlayData { Ok(OverlayData {
state: OverlayState { state: OverlayState {
name: WATCH_NAME.into(), name: WATCH_NAME.into(),
size: (400, 200), size: (400, 200),
@@ -290,7 +293,7 @@ where
}, },
backend: Box::new(canvas.build()), backend: Box::new(canvas.build()),
..Default::default() ..Default::default()
} })
} }
enum ElemState { enum ElemState {

View File

@@ -52,7 +52,7 @@ impl AppState {
} }
Ok(AppState { Ok(AppState {
fc: FontCache::new(), fc: FontCache::new()?,
session: AppSession::load(), session: AppSession::load(),
tasks: TaskContainer::new(), tasks: TaskContainer::new(),
graphics, graphics,