even more error handling
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()?;
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
451
src/graphics.rs
451
src/graphics.rs
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
188
src/gui/mod.rs
188
src/gui/mod.rs
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -52,7 +52,7 @@ impl AppState {
|
||||
}
|
||||
|
||||
Ok(AppState {
|
||||
fc: FontCache::new(),
|
||||
fc: FontCache::new()?,
|
||||
session: AppSession::load(),
|
||||
tasks: TaskContainer::new(),
|
||||
graphics,
|
||||
|
||||
Reference in New Issue
Block a user