diff --git a/src/backend/common.rs b/src/backend/common.rs index 3eb5974..4877c04 100644 --- a/src/backend/common.rs +++ b/src/backend/common.rs @@ -229,7 +229,7 @@ where has_wlr_dmabuf, has_wlr_screencopy, pw_token_store, - &app.session, + &app, ) { overlay.backend.set_renderer(Box::new(renderer)); } diff --git a/src/backend/openvr/lines.rs b/src/backend/openvr/lines.rs index 3eaf12c..61d6000 100644 --- a/src/backend/openvr/lines.rs +++ b/src/backend/openvr/lines.rs @@ -30,8 +30,10 @@ pub(super) struct LinePool { impl LinePool { pub fn new(graphics: Arc) -> anyhow::Result { - let mut command_buffer = - graphics.create_uploads_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + let mut command_buffer = graphics.create_uploads_command_buffer( + graphics.transfer_queue.clone(), + CommandBufferUsage::OneTimeSubmit, + )?; let buf = vec![255; 16]; diff --git a/src/backend/openxr/skybox.rs b/src/backend/openxr/skybox.rs index d8c4014..5e1c5c0 100644 --- a/src/backend/openxr/skybox.rs +++ b/src/backend/openxr/skybox.rs @@ -31,9 +31,10 @@ pub(super) struct Skybox { impl Skybox { pub fn new(app: &AppState) -> anyhow::Result { - let mut command_buffer = app - .graphics - .create_uploads_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + let mut command_buffer = app.graphics.create_uploads_command_buffer( + app.graphics.transfer_queue.clone(), + CommandBufferUsage::OneTimeSubmit, + )?; let mut maybe_image = None; diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index 02c0782..244de25 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -117,7 +117,7 @@ pub struct WlxGraphics { pub device: Arc, pub graphics_queue: Arc, pub transfer_queue: Arc, - pub capture_queue: Arc, + pub capture_queue: Option>, pub native_format: Format, pub texture_filtering: Filter, @@ -247,21 +247,8 @@ impl WlxGraphics { physical_device.properties().device_name, ); - let queue_family_index_gfx = physical_device - .queue_family_properties() - .iter() - .enumerate() - .position(|(_, q)| q.queue_flags.intersects(QueueFlags::GRAPHICS)) - .expect("Vulkan device has no graphics queue") - as u32; - - let queue_family_index_xfer = physical_device - .queue_family_properties() - .iter() - .enumerate() - .position(|(_, q)| q.queue_flags.intersects(QueueFlags::TRANSFER)) - .expect("Vulkan device has no transfer queue") - as u32; + let queue_families = try_all_queue_families(physical_device.as_ref()) + .expect("vkPhysicalDevice does not have a GRAPHICS / TRANSFER queue."); let mut device_extensions = DeviceExtensions::empty(); let dmabuf_extensions = get_dmabuf_extensions(); @@ -276,9 +263,12 @@ impl WlxGraphics { .ext_image_drm_format_modifier; } - if physical_device.supported_extensions().ext_filter_cubic { + let texture_filtering = if physical_device.supported_extensions().ext_filter_cubic { device_extensions.ext_filter_cubic = true; - } + Filter::Cubic + } else { + Filter::Linear + }; let device_extensions_raw = device_extensions .into_iter() @@ -297,19 +287,14 @@ impl WlxGraphics { ..Default::default() }; - let queue_priorities = vec![1.0]; - - let queue_create_infos = [ - vk::DeviceQueueCreateInfo::default() - .queue_family_index(queue_family_index_gfx) - .queue_priorities(&queue_priorities), - vk::DeviceQueueCreateInfo::default() - .queue_family_index(queue_family_index_xfer) - .queue_priorities(&queue_priorities), - vk::DeviceQueueCreateInfo::default() - .queue_family_index(queue_family_index_xfer) - .queue_priorities(&queue_priorities), - ]; + let queue_create_infos = queue_families + .iter() + .map(|fam| { + vk::DeviceQueueCreateInfo::default() + .queue_family_index(fam.queue_family_index) + .queue_priorities(&fam.priorities) + }) + .collect::>(); let mut device_create_info = vk::DeviceCreateInfo::default() .queue_create_infos(&queue_create_infos) @@ -321,13 +306,7 @@ impl WlxGraphics { dynamic_rendering.p_next = device_create_info.p_next.cast_mut(); device_create_info.p_next = &raw mut dynamic_rendering as *const c_void; - let texture_filtering = if physical_device.supported_extensions().ext_filter_cubic { - Filter::Cubic - } else { - Filter::Linear - }; - - let (device, mut queues) = unsafe { + let (device, queues) = unsafe { let vk_device = xr_instance .create_vulkan_device( system, @@ -343,23 +322,14 @@ impl WlxGraphics { physical_device, vk::Device::from_raw(vk_device as _), DeviceCreateInfo { - queue_create_infos: vec![ - QueueCreateInfo { - queue_family_index: queue_family_index_gfx, - queues: queue_priorities.clone(), + queue_create_infos: queue_families + .iter() + .map(|fam| QueueCreateInfo { + queue_family_index: fam.queue_family_index, + queues: fam.priorities.clone(), ..Default::default() - }, - QueueCreateInfo { - queue_family_index: queue_family_index_xfer, - queues: queue_priorities.clone(), - ..Default::default() - }, - QueueCreateInfo { - queue_family_index: queue_family_index_xfer, - queues: queue_priorities, - ..Default::default() - }, - ], + }) + .collect::>(), enabled_extensions: device_extensions, enabled_features: features, ..Default::default() @@ -383,15 +353,7 @@ impl WlxGraphics { let _ = CString::from_raw(c_string.cast_mut()); }); - let graphics_queue = queues - .next() - .ok_or_else(|| anyhow::anyhow!("no graphics queues available"))?; - let transfer_queue = queues - .next() - .ok_or_else(|| anyhow::anyhow!("no transfer queues available"))?; - let capture_queue = queues - .next() - .ok_or_else(|| anyhow::anyhow!("not enough transfer queues available"))?; + let (graphics_queue, transfer_queue, capture_queue) = unwrap_queues(queues.collect()); let memory_allocator = memory_allocator(device.clone()); let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( @@ -459,65 +421,48 @@ impl WlxGraphics { let dmabuf_extensions = get_dmabuf_extensions(); - let (physical_device, my_extensions, queue_family_index_gfx, queue_family_index_xfer) = - instance - .enumerate_physical_devices()? - .filter_map(|p| { - let mut my_extensions = vk_device_extensions_fn(&p); - - if !p.supported_extensions().contains(&my_extensions) { - log::debug!( - "Not using {} due to missing extensions:", - p.properties().device_name, - ); - for (ext, missing) in p.supported_extensions().difference(&my_extensions) { - if missing { - log::debug!(" {ext}"); - } - } - return None; - } - - if p.supported_extensions().contains(&dmabuf_extensions) { - my_extensions = my_extensions.union(&dmabuf_extensions); - my_extensions.ext_image_drm_format_modifier = - p.supported_extensions().ext_image_drm_format_modifier; - } - - if p.supported_extensions().ext_filter_cubic { - my_extensions.ext_filter_cubic = true; - } + let (physical_device, my_extensions, queue_families) = instance + .enumerate_physical_devices()? + .filter_map(|p| { + let mut my_extensions = vk_device_extensions_fn(&p); + if !p.supported_extensions().contains(&my_extensions) { log::debug!( - "Device exts for {}: {:?}", + "Not using {} due to missing extensions:", p.properties().device_name, - &my_extensions ); - Some((p, my_extensions)) - }) - .filter_map(|(p, my_extensions)| { - p.queue_family_properties() - .iter() - .enumerate() - .position(|(_, q)| q.queue_flags.intersects(QueueFlags::GRAPHICS)) - .map(|i| (p, my_extensions, i as u32)) - }) - .filter_map(|(p, my_extensions, queue_family_index)| { - p.queue_family_properties() - .iter() - .enumerate() - .position(|(_, q)| q.queue_flags.intersects(QueueFlags::TRANSFER)) - .map(|i| (p, my_extensions, queue_family_index, i as u32)) - }) - .min_by_key(|(p, _, _, _)| match p.properties().device_type { - PhysicalDeviceType::DiscreteGpu => 0, - PhysicalDeviceType::IntegratedGpu => 1, - PhysicalDeviceType::VirtualGpu => 2, - PhysicalDeviceType::Cpu => 3, - PhysicalDeviceType::Other => 4, - _ => 5, - }) - .expect("no suitable physical device found"); + for (ext, missing) in p.supported_extensions().difference(&my_extensions) { + if missing { + log::debug!(" {ext}"); + } + } + return None; + } + + if p.supported_extensions().contains(&dmabuf_extensions) { + my_extensions = my_extensions.union(&dmabuf_extensions); + my_extensions.ext_image_drm_format_modifier = + p.supported_extensions().ext_image_drm_format_modifier; + } + + if p.supported_extensions().ext_filter_cubic { + my_extensions.ext_filter_cubic = true; + } + + log::debug!( + "Device exts for {}: {:?}", + p.properties().device_name, + &my_extensions + ); + Some((p, my_extensions)) + }) + .filter_map(|(p, my_extensions)| { + try_all_queue_families(p.as_ref()).map(|families| (p, my_extensions, families)) + }) + .min_by_key(|(p, _, families)| { + prio_from_device_type(p) * 10 + prio_from_families(families) + }) + .expect("no suitable physical device found"); log::info!( "Using vkPhysicalDevice: {}", @@ -530,7 +475,7 @@ impl WlxGraphics { Filter::Linear }; - let (device, mut queues) = Device::new( + let (device, queues) = Device::new( physical_device, DeviceCreateInfo { enabled_extensions: my_extensions, @@ -538,23 +483,14 @@ impl WlxGraphics { dynamic_rendering: true, ..DeviceFeatures::empty() }, - queue_create_infos: vec![ - QueueCreateInfo { - queue_family_index: queue_family_index_gfx, - queues: vec![1.0], + queue_create_infos: queue_families + .iter() + .map(|fam| QueueCreateInfo { + queue_family_index: fam.queue_family_index, + queues: fam.priorities.clone(), ..Default::default() - }, - QueueCreateInfo { - queue_family_index: queue_family_index_xfer, - queues: vec![1.0], - ..Default::default() - }, - QueueCreateInfo { - queue_family_index: queue_family_index_xfer, - queues: vec![1.0], - ..Default::default() - }, - ], + }) + .collect::>(), ..Default::default() }, )?; @@ -568,15 +504,7 @@ impl WlxGraphics { device.enabled_extensions().ext_image_drm_format_modifier ); - let graphics_queue = queues - .next() - .ok_or_else(|| anyhow::anyhow!("no graphics queues available"))?; - let transfer_queue = queues - .next() - .ok_or_else(|| anyhow::anyhow!("no transfer queues available"))?; - let capture_queue = queues - .next() - .ok_or_else(|| anyhow::anyhow!("no transfer queues available"))?; + let (graphics_queue, transfer_queue, capture_queue) = unwrap_queues(queues.collect()); let memory_allocator = memory_allocator(device.clone()); let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( @@ -624,7 +552,6 @@ impl WlxGraphics { )> { use vulkano::{ descriptor_set::allocator::StandardDescriptorSetAllocatorCreateInfo, - device::physical::PhysicalDeviceType, instance::InstanceCreateFlags, swapchain::{Surface, SurfaceInfo}, }; @@ -657,7 +584,7 @@ impl WlxGraphics { log::debug!("Device exts for app: {:?}", &device_extensions); - let (physical_device, my_extensions, queue_family_index) = instance + let (physical_device, my_extensions, queue_families) = instance .enumerate_physical_devices()? .filter_map(|p| { if p.supported_extensions().contains(&device_extensions) { @@ -675,22 +602,11 @@ impl WlxGraphics { None } }) - .filter_map(|(p, my_extensions)| { - p.queue_family_properties() - .iter() - .enumerate() - .position(|(i, q)| q.queue_flags.intersects(QueueFlags::GRAPHICS) - && p.surface_support(i as u32, &surface).unwrap_or(false)) - .map(|i| (p, my_extensions, i as u32)) - }) - .min_by_key(|(p, _, _)| match p.properties().device_type { - PhysicalDeviceType::DiscreteGpu => 0, - PhysicalDeviceType::IntegratedGpu => 1, - PhysicalDeviceType::VirtualGpu => 2, - PhysicalDeviceType::Cpu => 3, - PhysicalDeviceType::Other => 4, - _ => 5, - }) + .filter_map(|(p, my_extensions)| + try_all_queue_families(p.as_ref()).map(|families| (p, my_extensions, families)) + ) + .min_by_key(|(p, _, _)| prio_from_device_type(p) + ) .expect("no suitable physical device found"); log::info!( @@ -698,7 +614,7 @@ impl WlxGraphics { physical_device.properties().device_name, ); - let (device, mut queues) = Device::new( + let (device, queues) = Device::new( physical_device, DeviceCreateInfo { enabled_extensions: my_extensions, @@ -706,14 +622,20 @@ impl WlxGraphics { dynamic_rendering: true, ..DeviceFeatures::empty() }, - queue_create_infos: vec![QueueCreateInfo { - queue_family_index, - ..Default::default() - }], + queue_create_infos: queue_families + .iter() + .map(|fam| QueueCreateInfo { + queue_family_index: fam.queue_family_index, + queues: fam.priorities.clone(), + ..Default::default() + }) + .collect::>(), ..Default::default() }, )?; + let (graphics_queue, transfer_queue, capture_queue) = unwrap_queues(queues.collect()); + let native_format = device .physical_device() .surface_formats(&surface, SurfaceInfo::default()) @@ -721,10 +643,6 @@ impl WlxGraphics { .0; log::info!("Using surface format: {native_format:?}"); - 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( device.clone(), @@ -744,9 +662,9 @@ impl WlxGraphics { let me = Self { instance, device, - graphics_queue: queue.clone(), - transfer_queue: queue.clone(), // what could go wrong! - capture_queue: queue, + graphics_queue, + transfer_queue, + capture_queue, memory_allocator, native_format, texture_filtering: Filter::Linear, @@ -1076,34 +994,17 @@ impl WlxGraphics { /// Creates a CommandBuffer to be used for texture uploads on the main thread. pub fn create_uploads_command_buffer( self: &Arc, + queue: Arc, usage: CommandBufferUsage, ) -> anyhow::Result { let command_buffer = AutoCommandBufferBuilder::primary( self.command_buffer_allocator.clone(), - self.transfer_queue.queue_family_index(), + queue.queue_family_index(), usage, )?; Ok(WlxUploadsBuffer { graphics: self.clone(), - queue: self.transfer_queue.clone(), - command_buffer, - dummy: None, - }) - } - - /// Creates a CommandBuffer to be used for texture uploads on the capture thread. - pub fn create_capture_command_buffer( - self: &Arc, - usage: CommandBufferUsage, - ) -> anyhow::Result { - let command_buffer = AutoCommandBufferBuilder::primary( - self.command_buffer_allocator.clone(), - self.capture_queue.queue_family_index(), - usage, - )?; - Ok(WlxUploadsBuffer { - graphics: self.clone(), - queue: self.capture_queue.clone(), + queue, command_buffer, dummy: None, }) @@ -1577,3 +1478,103 @@ fn memory_allocator(device: Arc) -> Arc { Arc::new(StandardMemoryAllocator::new(device, create_info)) } + +#[derive(Debug)] +struct QueueFamilyLayout { + queue_family_index: u32, + priorities: Vec, +} + +fn prio_from_device_type(physical_device: &PhysicalDevice) -> u32 { + match physical_device.properties().device_type { + PhysicalDeviceType::DiscreteGpu => 0, + PhysicalDeviceType::IntegratedGpu => 1, + PhysicalDeviceType::VirtualGpu => 2, + PhysicalDeviceType::Cpu => 3, + _ => 4, + } +} + +const fn prio_from_families(families: &[QueueFamilyLayout]) -> u32 { + match families.len() { + 2 | 3 => 0, + _ => 1, + } +} + +fn unwrap_queues(queues: Vec>) -> (Arc, Arc, Option>) { + match queues[..] { + [ref g, ref t, ref c] => (g.clone(), t.clone(), Some(c.clone())), + [ref gt, ref c] => (gt.clone(), gt.clone(), Some(c.clone())), + [ref gt] => (gt.clone(), gt.clone(), None), + _ => unreachable!(), + } +} + +fn try_all_queue_families(physical_device: &PhysicalDevice) -> Option> { + queue_families_priorities( + physical_device, + vec![ + // main-thread graphics + uploads + QueueFlags::GRAPHICS | QueueFlags::TRANSFER, + // capture-thread uploads + QueueFlags::TRANSFER, + ], + ) + .or_else(|| { + queue_families_priorities( + physical_device, + vec![ + // main thread graphics + QueueFlags::GRAPHICS, + // main thread uploads + QueueFlags::TRANSFER, + // capture thread uploads + QueueFlags::TRANSFER, + ], + ) + }) + .or_else(|| { + queue_families_priorities( + physical_device, + // main thread-only. software capture not supported. + vec![QueueFlags::GRAPHICS | QueueFlags::TRANSFER], + ) + }) +} + +fn queue_families_priorities( + physical_device: &PhysicalDevice, + mut requested_queues: Vec, +) -> Option> { + let mut result = Vec::with_capacity(3); + + for (idx, props) in physical_device.queue_family_properties().iter().enumerate() { + let mut remaining = props.queue_count; + let mut want = 0usize; + + requested_queues.retain(|requested| { + if props.queue_flags.intersects(*requested) && remaining > 0 { + remaining -= 1; + want += 1; + false + } else { + true + } + }); + + if want > 0 { + result.push(QueueFamilyLayout { + queue_family_index: idx as u32, + priorities: std::iter::repeat_n(1.0, want).collect(), + }); + } + } + + if requested_queues.is_empty() { + log::debug!("Selected GPU queue families: {result:?}"); + Some(result) + } else { + None + } +} diff --git a/src/gui/font.rs b/src/gui/font.rs index 77e6a36..3bb24d9 100644 --- a/src/gui/font.rs +++ b/src/gui/font.rs @@ -240,8 +240,10 @@ impl FontCache { }; if cmd_buffer.is_none() { - *cmd_buffer = - Some(graphics.create_uploads_command_buffer(CommandBufferUsage::OneTimeSubmit)?); + *cmd_buffer = Some(graphics.create_uploads_command_buffer( + graphics.transfer_queue.clone(), + CommandBufferUsage::OneTimeSubmit, + )?); } let texture = cmd_buffer.as_mut().unwrap().texture2d_raw( diff --git a/src/gui/modular/mod.rs b/src/gui/modular/mod.rs index fddb720..3763580 100644 --- a/src/gui/modular/mod.rs +++ b/src/gui/modular/mod.rs @@ -552,9 +552,10 @@ fn sprite_from_path(path: Arc, app: &mut AppState) -> anyhow::Result { diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs index 03c5ac7..e4cbc96 100644 --- a/src/overlays/screen.rs +++ b/src/overlays/screen.rs @@ -8,6 +8,7 @@ use std::{ }; use vulkano::{ command_buffer::CommandBufferUsage, + device::Queue, format::Format, image::{sampler::Filter, view::ImageView, Image}, pipeline::graphics::color_blend::AttachmentBlend, @@ -258,6 +259,16 @@ impl ScreenPipeline { } } +macro_rules! new_wlx_capture { + ($capture_queue:expr, $capture:expr) => { + if $capture_queue.is_none() { + Box::new(MainThreadWlxCapture::new($capture)) as Box> + } else { + Box::new($capture) as Box> + } + }; +} + pub struct ScreenRenderer { name: Arc, capture: Box>, @@ -282,41 +293,33 @@ impl ScreenRenderer { } #[cfg(feature = "wayland")] - pub fn new_wlr_dmabuf(output: &WlxOutput) -> Option { + pub fn new_wlr_dmabuf(output: &WlxOutput, app: &AppState) -> Option { let client = WlxClient::new()?; - let capture = WlrDmabufCapture::new(client, output.id); - - Some(Self { - name: output.name.clone(), - capture: Box::new(capture), - pipeline: None, - cur_frame: None, - meta: None, - }) + let capture = new_wlx_capture!( + app.graphics.capture_queue, + WlrDmabufCapture::new(client, output.id) + ); + Some(Self::new_raw(output.name.clone(), capture)) } #[cfg(feature = "wayland")] - pub fn new_wlr_screencopy(output: &WlxOutput) -> Option { + pub fn new_wlr_screencopy(output: &WlxOutput, app: &AppState) -> Option { let client = WlxClient::new()?; - let capture = WlrScreencopyCapture::new(client, output.id); - - Some(Self { - name: output.name.clone(), - capture: Box::new(capture), - pipeline: None, - cur_frame: None, - meta: None, - }) + let capture = new_wlx_capture!( + app.graphics.capture_queue, + WlrScreencopyCapture::new(client, output.id) + ); + Some(Self::new_raw(output.name.clone(), capture)) } #[cfg(feature = "wayland")] pub fn new_pw( output: &WlxOutput, token: Option<&str>, - session: &AppSession, + app: &AppState, ) -> anyhow::Result<(Self, Option /* pipewire restore token */)> { let name = output.name.clone(); - let embed_mouse = !session.config.double_cursor_fix; + let embed_mouse = !app.session.config.double_cursor_fix; let select_screen_result = select_pw_screen( &format!( @@ -336,31 +339,21 @@ impl ScreenRenderer { let node_id = select_screen_result.streams.first().unwrap().node_id; // streams guaranteed to have at least one element - let capture = PipewireCapture::new(name, node_id); - + let capture = new_wlx_capture!( + app.graphics.capture_queue, + PipewireCapture::new(name, node_id) + ); Ok(( - Self { - name: output.name.clone(), - capture: Box::new(capture), - pipeline: None, - cur_frame: None, - meta: None, - }, + Self::new_raw(output.name.clone(), capture), select_screen_result.restore_token, )) } #[cfg(feature = "x11")] - pub fn new_xshm(screen: Arc) -> Self { - let capture = XshmCapture::new(screen.clone()); - - Self { - name: screen.name.clone(), - capture: Box::new(capture), - pipeline: None, - cur_frame: None, - meta: None, - } + pub fn new_xshm(screen: Arc, app: &AppState) -> Self { + let capture = + new_wlx_capture!(app.graphics.capture_queue, XshmCapture::new(screen.clone())); + Self::new_raw(screen.name.clone(), capture) } } @@ -368,6 +361,7 @@ impl ScreenRenderer { pub struct WlxCaptureIn { name: Arc, graphics: Arc, + queue: Arc, } #[derive(Clone)] @@ -386,7 +380,7 @@ fn upload_image( ) -> Option> { let mut upload = match me .graphics - .create_capture_command_buffer(CommandBufferUsage::OneTimeSubmit) + .create_uploads_command_buffer(me.queue.clone(), CommandBufferUsage::OneTimeSubmit) { Ok(x) => x, Err(e) => { @@ -518,9 +512,15 @@ impl OverlayRenderer for ScreenRenderer { let dmabuf_formats = if !supports_dmabuf { log::info!("Capture method does not support DMA-buf"); + if app.graphics.capture_queue.is_none() { + log::warn!("Current GPU does not support multiple queues. Software capture will take place on the main thread. Expect degraded performance."); + } &Vec::new() } else if !allow_dmabuf { log::info!("Not using DMA-buf capture due to {capture_method}"); + if app.graphics.capture_queue.is_none() { + log::warn!("Current GPU does not support multiple queues. Software capture will take place on the main thread. Expect degraded performance."); + } &Vec::new() } else { log::warn!( @@ -534,6 +534,12 @@ impl OverlayRenderer for ScreenRenderer { let user_data = WlxCaptureIn { name: self.name.clone(), graphics: app.graphics.clone(), + queue: app + .graphics + .capture_queue + .as_ref() + .unwrap_or_else(|| &app.graphics.transfer_queue) + .clone(), }; self.capture @@ -554,9 +560,10 @@ impl OverlayRenderer for ScreenRenderer { }); self.pipeline = Some({ let mut pipeline = ScreenPipeline::new(&capture.image.extent(), app)?; - let mut upload = app - .graphics - .create_uploads_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + let mut upload = app.graphics.create_uploads_command_buffer( + app.graphics.transfer_queue.clone(), + CommandBufferUsage::OneTimeSubmit, + )?; pipeline.ensure_mouse_initialized(&mut upload)?; upload.build_and_execute_now()?; pipeline @@ -613,17 +620,17 @@ pub fn create_screen_renderer_wl( has_wlr_dmabuf: bool, has_wlr_screencopy: bool, pw_token_store: &mut PwTokenMap, - session: &AppSession, + app: &AppState, ) -> Option { let mut capture: Option = None; - if (&*session.config.capture_method == "wlr-dmabuf") && has_wlr_dmabuf { + if (&*app.session.config.capture_method == "wlr-dmabuf") && has_wlr_dmabuf { log::info!("{}: Using Wlr DMA-Buf", &output.name); - capture = ScreenRenderer::new_wlr_dmabuf(output); + capture = ScreenRenderer::new_wlr_dmabuf(output, app); } - if &*session.config.capture_method == "screencopy" && has_wlr_screencopy { + if &*app.session.config.capture_method == "screencopy" && has_wlr_screencopy { log::info!("{}: Using Wlr Screencopy Wl-SHM", &output.name); - capture = ScreenRenderer::new_wlr_screencopy(output); + capture = ScreenRenderer::new_wlr_screencopy(output, app); } if capture.is_none() { @@ -640,7 +647,7 @@ pub fn create_screen_renderer_wl( log::info!("Found existing Pipewire token for display {display_name}: {t}"); } - match ScreenRenderer::new_pw(output, token, session) { + match ScreenRenderer::new_pw(output, token, app) { Ok((renderer, restore_token)) => { capture = Some(renderer); @@ -793,7 +800,7 @@ pub fn create_screens_wayland(wl: &mut WlxClientAlias, app: &mut AppState) -> Sc has_wlr_dmabuf, has_wlr_screencopy, &mut pw_tokens, - &app.session, + app, ) { let logical_pos = vec2(output.logical_pos.0 as f32, output.logical_pos.1 as f32); let logical_size = vec2(output.logical_size.0 as f32, output.logical_size.1 as f32); @@ -910,13 +917,13 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result anyhow::Result +where + T: WlxCapture<(), WlxFrame>, +{ + inner: T, + data: Option, +} + +impl MainThreadWlxCapture +where + T: WlxCapture<(), WlxFrame>, +{ + pub const fn new(inner: T) -> Self { + Self { inner, data: None } + } +} + +impl WlxCapture for MainThreadWlxCapture +where + T: WlxCapture<(), WlxFrame>, +{ + fn init( + &mut self, + dmabuf_formats: &[wlx_frame::DrmFormat], + user_data: WlxCaptureIn, + _: fn(&WlxCaptureIn, WlxFrame) -> Option, + ) { + self.data = Some(user_data); + self.inner.init(dmabuf_formats, (), receive_callback_dummy); + } + fn is_ready(&self) -> bool { + self.inner.is_ready() + } + fn request_new_frame(&mut self) { + self.inner.request_new_frame(); + } + fn pause(&mut self) { + self.inner.pause(); + } + fn resume(&mut self) { + self.inner.resume(); + } + fn receive(&mut self) -> Option { + self.inner + .receive() + .and_then(|frame| receive_callback(self.data.as_ref().unwrap(), frame)) + } + fn supports_dmbuf(&self) -> bool { + self.inner.supports_dmbuf() + } +} + +#[allow(clippy::trivially_copy_pass_by_ref, clippy::unnecessary_wraps)] +const fn receive_callback_dummy(_: &(), frame: wlx_frame::WlxFrame) -> Option { + Some(frame) +} diff --git a/src/overlays/wayvr.rs b/src/overlays/wayvr.rs index 8ff7a78..c449d0e 100644 --- a/src/overlays/wayvr.rs +++ b/src/overlays/wayvr.rs @@ -565,9 +565,10 @@ impl WayVRRenderer { &mut self, data: &wayvr::egl_data::RenderSoftwarePixelsData, ) -> anyhow::Result<()> { - let mut upload = self - .graphics - .create_uploads_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + let mut upload = self.graphics.create_uploads_command_buffer( + self.graphics.transfer_queue.clone(), + CommandBufferUsage::OneTimeSubmit, + )?; let tex = upload.texture2d_raw( u32::from(data.width), @@ -702,7 +703,6 @@ impl OverlayRenderer for WayVRRenderer { drop(ctx); match data { - //TODO: render to _tgt_ wayvr::egl_data::RenderData::Dmabuf(data) => { self.ensure_dmabuf_data(&data)?; }