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)?
};
let mut watch = create_watch::<T>(&app, &screens);
let mut watch = create_watch::<T>(&app, &screens)?;
watch.state.want_visible = true;
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.want_visible = false;
overlays.insert(keyboard.state.id, keyboard);

View File

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

View File

@@ -83,7 +83,7 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
};
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)?
};
@@ -119,7 +119,7 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
let mut next_device_update = Instant::now();
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()];
'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
.iter_mut()
.for_each(|o| o.after_input(&mut overlay_mngr, &mut state));
for o in overlays.iter_mut() {
o.after_input(&mut overlay_mngr, &mut state)?;
}
#[cfg(feature = "osc")]
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");
overlays
.iter_mut()
.filter(|o| o.state.want_visible)
.for_each(|o| o.render(&mut state));
for o in overlays.iter_mut() {
if o.state.want_visible {
o.render(&mut state)?;
}
}
log::debug!("Rendering overlays");

View File

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

View File

@@ -31,8 +31,9 @@ pub(super) struct LinePool {
}
impl LinePool {
pub(super) fn new(graphics: Arc<WlxGraphics>) -> Self {
let mut command_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit);
pub(super) fn new(graphics: Arc<WlxGraphics>) -> anyhow::Result<Self> {
let mut command_buffer =
graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
// TODO customizable colors
let colors = [
@@ -43,20 +44,22 @@ impl LinePool {
[0xff, 0x00, 0x00, 0xff],
];
let views = colors
let views: anyhow::Result<Vec<Arc<ImageView>>> = colors
.into_iter()
.map(|color| {
let tex = command_buffer.texture2d(1, 1, Format::R8G8B8A8_UNORM, &color);
ImageView::new_default(tex).unwrap()
})
.map(
|color| match command_buffer.texture2d(1, 1, Format::R8G8B8A8_UNORM, &color) {
Ok(tex) => ImageView::new_default(tex).map_err(|e| anyhow::anyhow!(e)),
Err(e) => Err(e),
},
)
.collect();
command_buffer.build_and_execute_now();
command_buffer.build_and_execute_now()?;
LinePool {
Ok(LinePool {
lines: IdMap::new(),
colors: views,
}
colors: views?,
})
}
pub(super) fn allocate(
@@ -132,7 +135,7 @@ impl LinePool {
&'a mut self,
xr: &'a XrState,
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();
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);
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)?
};
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")]
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
overlays
.iter_mut()
.for_each(|o| o.after_input(&mut app_state));
for o in overlays.iter_mut() {
o.after_input(&mut app_state)?;
}
#[cfg(feature = "osc")]
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 command_buffer = app_state
.graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit);
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
for o in overlays.iter_mut() {
if !o.state.want_visible {
@@ -268,11 +268,11 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
}
if !o.data.init {
o.init(&mut app_state);
o.init(&mut app_state)?;
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)
.length_squared();
@@ -290,7 +290,7 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
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));

View File

@@ -77,14 +77,15 @@ impl OverlayData<OpenXrOverlayData> {
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.state.want_visible {
self.backend.resume(app);
self.backend.resume(app)?;
} else {
self.backend.pause(app);
self.backend.pause(app)?;
}
}
self.data.last_visible = self.state.want_visible;
Ok(())
}
}

View File

@@ -1,5 +1,6 @@
use std::sync::Arc;
use anyhow::bail;
use ash::vk;
use openxr as xr;
@@ -30,16 +31,17 @@ pub(super) fn create_swapchain_render_data(
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(
shaders.get("vert_common").unwrap().clone(),
shaders.get("frag_srgb").unwrap().clone(),
shaders.get("vert_common").unwrap().clone(), // want panic
shaders.get("frag_srgb").unwrap().clone(), // want panic
graphics.native_format,
);
)?;
let images = swapchain
.enumerate_images()
.unwrap()
.enumerate_images()?
.into_iter()
.map(|handle| {
let vk_image = vk::Image::from_raw(handle);
@@ -83,29 +85,29 @@ impl SwapchainRenderData {
command_buffer: &mut WlxCommandBuffer,
view: Arc<ImageView>,
alpha: f32,
) -> Result<xr::SwapchainSubImage<xr::Vulkan>, xr::sys::Result> {
) -> anyhow::Result<xr::SwapchainSubImage<xr::Vulkan>> {
let idx = self.swapchain.acquire_image()? as usize;
self.swapchain.wait_image(xr::Duration::INFINITE)?;
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 set0 = self
.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(
[target_extent[0] as _, target_extent[1] as _],
command_buffer.graphics.quad_verts.clone(),
command_buffer.graphics.quad_indices.clone(),
vec![set0, set1],
);
command_buffer.run_ref(&pass);
command_buffer.end_rendering();
)?;
command_buffer.run_ref(&pass)?;
command_buffer.end_rendering()?;
self.swapchain.release_image()?;

View File

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

View File

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

View File

@@ -35,15 +35,15 @@ pub struct Glyph {
}
impl FontCache {
pub fn new() -> Self {
let ft = Library::init().expect("Failed to initialize freetype");
pub fn new() -> anyhow::Result<Self> {
let ft = Library::init()?;
let fc = FontConfig::default();
FontCache {
Ok(FontCache {
fc,
ft,
collections: IdMap::new(),
}
})
}
pub fn get_text_size(
@@ -51,7 +51,7 @@ impl FontCache {
text: &str,
size: isize,
graphics: Arc<WlxGraphics>,
) -> (f32, f32) {
) -> anyhow::Result<(f32, f32)> {
let sizef = size as f32;
let height = sizef + ((text.lines().count() as f32) - 1f32) * (sizef * 1.5);
@@ -60,9 +60,10 @@ impl FontCache {
for line in text.lines() {
let w: f32 = line
.chars()
.map(|c| {
.filter_map(|c| {
self.get_glyph_for_cp(c as usize, size, graphics.clone())
.advance
.map(|glyph| glyph.advance)
.ok()
})
.sum();
@@ -70,7 +71,7 @@ impl FontCache {
max_w = w;
}
}
(max_w, height)
Ok((max_w, height))
}
pub fn get_glyphs(
@@ -78,14 +79,14 @@ impl FontCache {
text: &str,
size: isize,
graphics: Arc<WlxGraphics>,
) -> Vec<Rc<Glyph>> {
) -> anyhow::Result<Vec<Rc<Glyph>>> {
let mut glyphs = Vec::new();
for line in text.lines() {
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 {
@@ -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) {
return *font;
@@ -167,28 +168,28 @@ impl FontCache {
cp: usize,
size: isize,
graphics: Arc<WlxGraphics>,
) -> Rc<Glyph> {
) -> anyhow::Result<Rc<Glyph>> {
let key = self.get_font_for_cp(cp, size);
let font = &mut self.collections[size].fonts[key];
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() {
return font.glyphs[0].clone();
return Ok(font.glyphs[0].clone());
}
let glyph = font.face.glyph();
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 buf = bmp.buffer().to_vec();
if buf.len() == 0 {
return font.glyphs[0].clone();
return Ok(font.glyphs[0].clone());
}
let metrics = glyph.metrics();
@@ -197,12 +198,12 @@ impl FontCache {
Ok(PixelMode::Gray) => Format::R8_UNORM,
Ok(PixelMode::Gray2) => Format::R16_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 texture = cmd_buffer.texture2d(bmp.width() as _, bmp.rows() as _, format, &buf);
cmd_buffer.build_and_execute_now();
let mut cmd_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
let texture = cmd_buffer.texture2d(bmp.width() as _, bmp.rows() as _, format, &buf)?;
cmd_buffer.build_and_execute_now()?;
let g = Glyph {
tex: Some(texture),
@@ -214,6 +215,6 @@ impl FontCache {
};
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>,
format: Format,
data: D,
) -> Self {
Self {
canvas: Canvas::new(width, height, graphics, format, data),
) -> anyhow::Result<Self> {
Ok(Self {
canvas: Canvas::new(width, height, graphics, format, data)?,
bg_color: Vec3::ZERO,
fg_color: Vec3::ONE,
font_size: 16,
}
})
}
pub fn build(self) -> Canvas<D, S> {
@@ -225,62 +225,64 @@ impl<D, S> Canvas<D, S> {
graphics: Arc<WlxGraphics>,
format: Format,
data: D,
) -> Self {
let tex_fg = 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);
) -> anyhow::Result<Self> {
let tex_fg = 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 view_fg = ImageView::new_default(tex_fg.clone()).unwrap();
let view_bg = ImageView::new_default(tex_bg.clone()).unwrap();
let view_final = ImageView::new_default(tex_final.clone()).unwrap();
let view_fg = ImageView::new_default(tex_fg.clone())?;
let view_bg = ImageView::new_default(tex_bg.clone())?;
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(
view_bg.clone(),
shaders.get("vert_common").unwrap().clone(),
shaders.get("frag_color").unwrap().clone(),
shaders.get("vert_common").unwrap().clone(), // want panic
shaders.get("frag_color").unwrap().clone(), // want panic
format,
);
)?;
let pipeline_fg_glyph = graphics.create_pipeline(
view_fg.clone(),
shaders.get("vert_common").unwrap().clone(),
shaders.get("frag_glyph").unwrap().clone(),
shaders.get("vert_common").unwrap().clone(), // want panic
shaders.get("frag_glyph").unwrap().clone(), // want panic
format,
);
)?;
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(
view_final.clone(),
shaders.get("vert_common").unwrap().clone(),
shaders.get("frag_sprite").unwrap().clone(),
shaders.get("vert_common").unwrap().clone(), // want panic
shaders.get("frag_sprite").unwrap().clone(), // want panic
format,
ImageLayout::TransferSrcOptimal,
ImageLayout::TransferSrcOptimal,
);
)?;
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_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 pass_fg = pipeline_final.create_pass(
[width as _, height as _],
vertex_buffer.clone(),
graphics.quad_indices.clone(),
vec![set_fg],
);
)?;
let pass_bg = pipeline_final.create_pass(
[width as _, height as _],
vertex_buffer.clone(),
graphics.quad_indices.clone(),
vec![set_bg],
);
)?;
let stride = width / RES_DIVIDER;
let rows = height / RES_DIVIDER;
Self {
Ok(Self {
canvas: CanvasData {
data,
width,
@@ -299,7 +301,7 @@ impl<D, S> Canvas<D, S> {
view_final,
pass_fg,
pass_bg,
}
})
}
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)
}
fn render_bg(&mut self, app: &mut AppState) {
fn render_bg(&mut self, app: &mut AppState) -> anyhow::Result<()> {
let mut cmd_buffer = self
.canvas
.graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit);
cmd_buffer.begin_render_pass(&self.canvas.pipeline_bg_color);
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
cmd_buffer.begin_render_pass(&self.canvas.pipeline_bg_color)?;
for c in self.controls.iter_mut() {
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.build_and_execute_now();
cmd_buffer.end_render_pass()?;
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
.canvas
.graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit);
cmd_buffer.begin_render_pass(&self.canvas.pipeline_fg_glyph);
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
cmd_buffer.begin_render_pass(&self.canvas.pipeline_fg_glyph)?;
for c in self.controls.iter_mut() {
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.build_and_execute_now();
cmd_buffer.end_render_pass()?;
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> {
fn init(&mut self, app: &mut AppState) {
self.render_bg(app);
self.render_fg(app);
fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
self.render_bg(app)?;
self.render_fg(app)
}
fn pause(&mut self, _app: &mut AppState) {}
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<()> {
let mut dirty = false;
for c in self.controls.iter_mut() {
@@ -430,8 +436,8 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
}
if dirty {
self.render_bg(app);
self.render_fg(app);
self.render_bg(app)?;
self.render_fg(app)?;
}
/*
@@ -454,17 +460,17 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
let mut cmd_buffer = self
.canvas
.graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit);
cmd_buffer.begin_render_pass(&self.canvas.pipeline_final);
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
cmd_buffer.begin_render_pass(&self.canvas.pipeline_final)?;
// 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() {
if let Some(render) = c.on_render_hl {
if let Some(test) = c.test_highlight {
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)) {
@@ -474,16 +480,16 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
app,
&mut cmd_buffer,
Vec4::new(1., 1., 1., 0.3),
);
)?;
}
}
}
// mostly static text
cmd_buffer.run_ref(&self.pass_fg);
cmd_buffer.run_ref(&self.pass_fg)?;
cmd_buffer.end_render_pass();
cmd_buffer.build_and_execute_now();
cmd_buffer.end_render_pass()?;
cmd_buffer.build_and_execute_now()
/*
self.canvas
@@ -523,9 +529,15 @@ pub struct Control<D, S> {
pub on_scroll: Option<fn(&mut Self, &mut D, &mut AppState, f32)>,
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_hl: Option<fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer, Vec4)>,
on_render_fg: Option<fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer)>,
on_render_bg: Option<
fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer) -> anyhow::Result<()>,
>,
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> {
@@ -577,7 +589,7 @@ impl<D, S> Control<D, S> {
canvas: &CanvasData<D>,
_: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer,
) {
) -> anyhow::Result<()> {
let pass = {
let vertex_buffer = canvas.graphics.upload_verts(
canvas.width as _,
@@ -586,20 +598,20 @@ impl<D, S> Control<D, S> {
self.rect.y,
self.rect.w,
self.rect.h,
);
)?;
let set0 = canvas.pipeline_bg_color.uniform_buffer(
0,
vec![self.bg_color.x, self.bg_color.y, self.bg_color.z, 1.],
);
)?;
canvas.pipeline_bg_color.create_pass(
[canvas.width as _, canvas.height as _],
vertex_buffer,
canvas.graphics.quad_indices.clone(),
vec![set0],
)
)?
};
cmd_buffer.run_ref(&pass);
cmd_buffer.run_ref(&pass)
}
fn render_highlight(
@@ -608,7 +620,7 @@ impl<D, S> Control<D, S> {
_: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer,
color: Vec4,
) {
) -> anyhow::Result<()> {
let vertex_buffer = canvas.graphics.upload_verts(
canvas.width as _,
canvas.height as _,
@@ -616,20 +628,20 @@ impl<D, S> Control<D, S> {
self.rect.y,
self.rect.w,
self.rect.h,
);
)?;
let set0 = canvas
.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(
[canvas.width as _, canvas.height as _],
vertex_buffer.clone(),
canvas.graphics.quad_indices.clone(),
vec![set0],
);
)?;
cmd_buffer.run_ref(&pass);
cmd_buffer.run_ref(&pass)
}
fn render_text(
@@ -637,11 +649,14 @@ impl<D, S> Control<D, S> {
canvas: &CanvasData<D>,
app: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer,
) {
) -> anyhow::Result<()> {
let mut cur_y = self.rect.y;
for line in self.text.lines() {
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() {
let vertex_buffer = canvas.graphics.upload_verts(
canvas.width as _,
@@ -650,43 +665,47 @@ impl<D, S> Control<D, S> {
cur_y - glyph.top,
glyph.width,
glyph.height,
);
)?;
let set0 = canvas.pipeline_fg_glyph.uniform_sampler(
0,
ImageView::new_default(tex).unwrap(),
Filter::Linear,
);
)?;
let set1 = canvas.pipeline_fg_glyph.uniform_buffer(
1,
vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.],
);
)?;
let pass = canvas.pipeline_fg_glyph.create_pass(
[canvas.width as _, canvas.height as _],
vertex_buffer,
canvas.graphics.quad_indices.clone(),
vec![set0, set1],
);
cmd_buffer.run_ref(&pass);
)?;
cmd_buffer.run_ref(&pass)?;
}
cur_x += glyph.advance;
}
cur_y += (self.size as f32) * 1.5;
}
Ok(())
}
fn render_text_centered(
&self,
canvas: &CanvasData<D>,
app: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer,
) {
) -> anyhow::Result<()> {
let (w, h) = app
.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);
for line in self.text.lines() {
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() {
let vertex_buffer = canvas.graphics.upload_verts(
canvas.width as _,
@@ -695,27 +714,28 @@ impl<D, S> Control<D, S> {
cur_y - glyph.top,
glyph.width,
glyph.height,
);
)?;
let set0 = canvas.pipeline_fg_glyph.uniform_sampler(
0,
ImageView::new_default(tex).unwrap(),
Filter::Linear,
);
)?;
let set1 = canvas.pipeline_fg_glyph.uniform_buffer(
1,
vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.],
);
)?;
let pass = canvas.pipeline_fg_glyph.create_pass(
[canvas.width as _, canvas.height as _],
vertex_buffer,
canvas.graphics.quad_indices.clone(),
vec![set0, set1],
);
cmd_buffer.run_ref(&pass);
)?;
cmd_buffer.run_ref(&pass)?;
}
cur_x += glyph.advance;
}
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 fn create_keyboard<O>(app: &AppState) -> OverlayData<O>
pub fn create_keyboard<O>(app: &AppState) -> anyhow::Result<OverlayData<O>>
where
O: Default,
{
@@ -50,7 +50,7 @@ where
app.graphics.clone(),
app.format,
data,
);
)?;
canvas.bg_color = color_parse("#101010").unwrap(); //safe
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;
OverlayData {
Ok(OverlayData {
state: OverlayState {
name: KEYBOARD_NAME.into(),
size: (size.x as _, size.y as _),
@@ -132,7 +132,7 @@ where
},
backend: Box::new(canvas),
..Default::default()
}
})
}
fn key_press(

View File

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

View File

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

View File

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