zwlr_screencopy v3 support
This commit is contained in:
@@ -69,12 +69,7 @@
|
|||||||
"CAPTURE_METHOD": "Wayland-Bildschirmaufnahme",
|
"CAPTURE_METHOD": "Wayland-Bildschirmaufnahme",
|
||||||
"CAPTURE_METHOD_HELP": "Versuchen Sie, dies zu ändern, wenn Sie\nschwarze oder fehlerhafte Bildschirme erleben",
|
"CAPTURE_METHOD_HELP": "Versuchen Sie, dies zu ändern, wenn Sie\nschwarze oder fehlerhafte Bildschirme erleben",
|
||||||
"KEYBOARD_MIDDLE_CLICK": "Keyboard-Mittelklick",
|
"KEYBOARD_MIDDLE_CLICK": "Keyboard-Mittelklick",
|
||||||
"KEYBOARD_MIDDLE_CLICK_HELP": "Modifikator bei Eingabe mit violettem Laser",
|
"KEYBOARD_MIDDLE_CLICK_HELP": "Modifikator bei Eingabe mit violettem Laser"
|
||||||
"OPTION": {
|
|
||||||
"PIPEWIRE_HELP": "Schnelle GPU-Aufnahme. Empfohlen",
|
|
||||||
"PW_FALLBACK_HELP": "Langsam. Versuchen Sie dies, falls PipeWire GPU nicht funktioniert.",
|
|
||||||
"SCREENCOPY_HELP": "Langsam. Funktioniert mit: Hyprland, Niri, River, Sway"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"HELLO": "Hallo!",
|
"HELLO": "Hallo!",
|
||||||
"AUDIO": {
|
"AUDIO": {
|
||||||
|
|||||||
@@ -67,9 +67,12 @@
|
|||||||
"NOTIFICATIONS_SOUND_ENABLED": "Notification sounds",
|
"NOTIFICATIONS_SOUND_ENABLED": "Notification sounds",
|
||||||
"OPAQUE_BACKGROUND": "Opaque background",
|
"OPAQUE_BACKGROUND": "Opaque background",
|
||||||
"OPTION": {
|
"OPTION": {
|
||||||
"PIPEWIRE_HELP": "Fast GPU capture. Recommended",
|
"AUTO": "Automatic",
|
||||||
"PW_FALLBACK_HELP": "Slow. Try in case PipeWire GPU doesn't work",
|
"AUTO_HELP": "ScreenCopy GPU if supported,\notherwise PipeWire GPU.",
|
||||||
"SCREENCOPY_HELP": "Slow. Works on: Hyprland, Niri, River, Sway"
|
"PIPEWIRE_HELP": "Fast GPU capture,\nstandard on all desktops.",
|
||||||
|
"PW_FALLBACK_HELP": "Slow method with high CPU usage.\nTry in case PipeWire GPU doesn't work",
|
||||||
|
"SCREENCOPY_GPU_HELP": "Fast, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway",
|
||||||
|
"SCREENCOPY_HELP": "Slow, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway"
|
||||||
},
|
},
|
||||||
"POINTER_LERP_FACTOR": "Pointer smoothing",
|
"POINTER_LERP_FACTOR": "Pointer smoothing",
|
||||||
"RESTART_SOFTWARE": "Restart software",
|
"RESTART_SOFTWARE": "Restart software",
|
||||||
|
|||||||
@@ -69,12 +69,7 @@
|
|||||||
"CAPTURE_METHOD": "Captura de pantalla de Wayland",
|
"CAPTURE_METHOD": "Captura de pantalla de Wayland",
|
||||||
"CAPTURE_METHOD_HELP": "Intente cambiar esta opción si\nexperimenta pantallas negras o con fallos",
|
"CAPTURE_METHOD_HELP": "Intente cambiar esta opción si\nexperimenta pantallas negras o con fallos",
|
||||||
"KEYBOARD_MIDDLE_CLICK": "Clic del botón central del teclado",
|
"KEYBOARD_MIDDLE_CLICK": "Clic del botón central del teclado",
|
||||||
"KEYBOARD_MIDDLE_CLICK_HELP": "Modificador para usar al escribir\ncon láser púrpura",
|
"KEYBOARD_MIDDLE_CLICK_HELP": "Modificador para usar al escribir\ncon láser púrpura"
|
||||||
"OPTION": {
|
|
||||||
"PIPEWIRE_HELP": "Captura de GPU rápida. Recomendado",
|
|
||||||
"PW_FALLBACK_HELP": "Lento. Intente si GPU de PipeWire no funciona",
|
|
||||||
"SCREENCOPY_HELP": "Lento. Funciona en: Hyprland, Niri, River, Sway"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"HELLO": "¡Hola!",
|
"HELLO": "¡Hola!",
|
||||||
"AUDIO": {
|
"AUDIO": {
|
||||||
|
|||||||
@@ -69,12 +69,7 @@
|
|||||||
"CAPTURE_METHOD": "Waylandスクリーンキャプチャ",
|
"CAPTURE_METHOD": "Waylandスクリーンキャプチャ",
|
||||||
"CAPTURE_METHOD_HELP": "画面が黒くなる、または乱れる場合は、\nこの設定を変更してみてください。",
|
"CAPTURE_METHOD_HELP": "画面が黒くなる、または乱れる場合は、\nこの設定を変更してみてください。",
|
||||||
"KEYBOARD_MIDDLE_CLICK": "キーボードの中ボタンクリック",
|
"KEYBOARD_MIDDLE_CLICK": "キーボードの中ボタンクリック",
|
||||||
"KEYBOARD_MIDDLE_CLICK_HELP": "紫色のレーザーで入力する際の修飾キー",
|
"KEYBOARD_MIDDLE_CLICK_HELP": "紫色のレーザーで入力する際の修飾キー"
|
||||||
"OPTION": {
|
|
||||||
"PIPEWIRE_HELP": "高速なGPUキャプチャ。推奨",
|
|
||||||
"PW_FALLBACK_HELP": "低速です。PipeWire GPU が動作しない場合に試してください。",
|
|
||||||
"SCREENCOPY_HELP": "遅い。動作する環境: Hyprland, Niri, River, Sway"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"HELLO": "こんにちは!",
|
"HELLO": "こんにちは!",
|
||||||
"AUDIO": {
|
"AUDIO": {
|
||||||
|
|||||||
@@ -63,12 +63,7 @@
|
|||||||
"CAPTURE_METHOD": "Przechwytywanie ekranu Wayland",
|
"CAPTURE_METHOD": "Przechwytywanie ekranu Wayland",
|
||||||
"CAPTURE_METHOD_HELP": "Spróbuj zmienić tę opcję, jeśli masz\nproblemy z czarnym lub migoczącym ekranem",
|
"CAPTURE_METHOD_HELP": "Spróbuj zmienić tę opcję, jeśli masz\nproblemy z czarnym lub migoczącym ekranem",
|
||||||
"KEYBOARD_MIDDLE_CLICK": "Środkowy przycisk myszy na klawiaturze",
|
"KEYBOARD_MIDDLE_CLICK": "Środkowy przycisk myszy na klawiaturze",
|
||||||
"KEYBOARD_MIDDLE_CLICK_HELP": "Modyfikator, który ma zostać użyty podczas pisania\nfioletową wiązką lasera",
|
"KEYBOARD_MIDDLE_CLICK_HELP": "Modyfikator, który ma zostać użyty podczas pisania\nfioletową wiązką lasera"
|
||||||
"OPTION": {
|
|
||||||
"PIPEWIRE_HELP": "Szybkie przechwytywanie GPU. Zalecane",
|
|
||||||
"PW_FALLBACK_HELP": "Wolno. Wypróbuj w przypadku, gdy PipeWire GPU nie działa.",
|
|
||||||
"SCREENCOPY_HELP": "Wolne. Działa na: Hyprland, Niri, River, Sway"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"APPLICATION_LAUNCHER": "Uruchamiacz aplikacji",
|
"APPLICATION_LAUNCHER": "Uruchamiacz aplikacji",
|
||||||
"APPLICATIONS": "Aplikacje",
|
"APPLICATIONS": "Aplikacje",
|
||||||
|
|||||||
@@ -7,26 +7,26 @@ use std::{marker::PhantomData, slice::Iter, sync::Arc};
|
|||||||
use cmd::{GfxCommandBuffer, XferCommandBuffer};
|
use cmd::{GfxCommandBuffer, XferCommandBuffer};
|
||||||
use pipeline::WGfxPipeline;
|
use pipeline::WGfxPipeline;
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
DeviceSize,
|
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, IndexBuffer, Subbuffer},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, IndexBuffer, Subbuffer},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
AutoCommandBufferBuilder, CommandBufferUsage,
|
|
||||||
allocator::{StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo},
|
allocator::{StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo},
|
||||||
|
AutoCommandBufferBuilder, CommandBufferUsage,
|
||||||
},
|
},
|
||||||
descriptor_set::allocator::{StandardDescriptorSetAllocator, StandardDescriptorSetAllocatorCreateInfo},
|
descriptor_set::allocator::{StandardDescriptorSetAllocator, StandardDescriptorSetAllocatorCreateInfo},
|
||||||
device::{Device, Queue},
|
device::{Device, Queue},
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{Image, ImageCreateInfo, ImageType, ImageUsage, sampler::Filter},
|
image::{sampler::Filter, Image, ImageCreateInfo, ImageType, ImageUsage},
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
memory::{
|
memory::{
|
||||||
MemoryPropertyFlags,
|
|
||||||
allocator::{AllocationCreateInfo, GenericMemoryAllocatorCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
|
allocator::{AllocationCreateInfo, GenericMemoryAllocatorCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
|
||||||
|
ExternalMemoryHandleTypes, MemoryPropertyFlags,
|
||||||
},
|
},
|
||||||
pipeline::graphics::{
|
pipeline::graphics::{
|
||||||
color_blend::{AttachmentBlend, BlendFactor, BlendOp},
|
color_blend::{AttachmentBlend, BlendFactor, BlendOp},
|
||||||
vertex_input::Vertex,
|
vertex_input::Vertex,
|
||||||
},
|
},
|
||||||
shader::ShaderModule,
|
shader::ShaderModule,
|
||||||
|
DeviceSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::gfx::pipeline::WPipelineCreateInfo;
|
use crate::gfx::pipeline::WPipelineCreateInfo;
|
||||||
@@ -81,7 +81,7 @@ impl WGfx {
|
|||||||
queue_xfer: Arc<Queue>,
|
queue_xfer: Arc<Queue>,
|
||||||
surface_format: Format,
|
surface_format: Format,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
let memory_allocator = memory_allocator(device.clone());
|
let memory_allocator = memory_allocator(device.clone(), None);
|
||||||
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
|
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
StandardCommandBufferAllocatorCreateInfo {
|
StandardCommandBufferAllocatorCreateInfo {
|
||||||
@@ -222,10 +222,14 @@ impl WGfx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn memory_allocator(device: Arc<Device>) -> Arc<StandardMemoryAllocator> {
|
pub fn memory_allocator(
|
||||||
|
device: Arc<Device>,
|
||||||
|
export_handle_types: Option<ExternalMemoryHandleTypes>,
|
||||||
|
) -> Arc<StandardMemoryAllocator> {
|
||||||
let props = device.physical_device().memory_properties();
|
let props = device.physical_device().memory_properties();
|
||||||
|
|
||||||
let mut block_sizes = vec![0; props.memory_types.len()];
|
let mut block_sizes = vec![0; props.memory_types.len()];
|
||||||
|
|
||||||
let mut memory_type_bits = u32::MAX;
|
let mut memory_type_bits = u32::MAX;
|
||||||
|
|
||||||
for (index, memory_type) in props.memory_types.iter().enumerate() {
|
for (index, memory_type) in props.memory_types.iter().enumerate() {
|
||||||
@@ -252,9 +256,16 @@ fn memory_allocator(device: Arc<Device>) -> Arc<StandardMemoryAllocator> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let export_handle_types = if let Some(val) = export_handle_types {
|
||||||
|
vec![val; props.memory_types.len()]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
let create_info = GenericMemoryAllocatorCreateInfo {
|
let create_info = GenericMemoryAllocatorCreateInfo {
|
||||||
block_sizes: &block_sizes,
|
block_sizes: &block_sizes,
|
||||||
memory_type_bits,
|
memory_type_bits,
|
||||||
|
export_handle_types: &export_handle_types,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ pub enum WlxFrame {
|
|||||||
Dmabuf(DmabufFrame),
|
Dmabuf(DmabufFrame),
|
||||||
MemFd(MemFdFrame),
|
MemFd(MemFdFrame),
|
||||||
MemPtr(MemPtrFrame),
|
MemPtr(MemPtrFrame),
|
||||||
|
Implicit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default, PartialEq)]
|
#[derive(Debug, Clone, Copy, Default, PartialEq)]
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ use wayland_client::{
|
|||||||
wl_shm::WlShm,
|
wl_shm::WlShm,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use wayland_protocols::wp::linux_dmabuf::zv1::client::{
|
||||||
|
zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::frame;
|
use crate::frame;
|
||||||
|
|
||||||
@@ -61,6 +64,7 @@ pub struct WlxClient {
|
|||||||
pub xdg_output_mgr: ZxdgOutputManagerV1,
|
pub xdg_output_mgr: ZxdgOutputManagerV1,
|
||||||
pub maybe_wlr_dmabuf_mgr: Option<ZwlrExportDmabufManagerV1>,
|
pub maybe_wlr_dmabuf_mgr: Option<ZwlrExportDmabufManagerV1>,
|
||||||
pub maybe_wlr_screencopy_mgr: Option<ZwlrScreencopyManagerV1>,
|
pub maybe_wlr_screencopy_mgr: Option<ZwlrScreencopyManagerV1>,
|
||||||
|
pub maybe_zwp_linux_dmabuf: Option<ZwpLinuxDmabufV1>,
|
||||||
pub wl_seat: WlSeat,
|
pub wl_seat: WlSeat,
|
||||||
pub wl_shm: WlShm,
|
pub wl_shm: WlShm,
|
||||||
pub outputs: IdMap<u32, WlxOutput>,
|
pub outputs: IdMap<u32, WlxOutput>,
|
||||||
@@ -91,7 +95,8 @@ impl WlxClient {
|
|||||||
.expect(WlSeat::interface().name),
|
.expect(WlSeat::interface().name),
|
||||||
wl_shm: globals.bind(&qh, 1..=1, ()).expect(WlShm::interface().name),
|
wl_shm: globals.bind(&qh, 1..=1, ()).expect(WlShm::interface().name),
|
||||||
maybe_wlr_dmabuf_mgr: globals.bind(&qh, 1..=1, ()).ok(),
|
maybe_wlr_dmabuf_mgr: globals.bind(&qh, 1..=1, ()).ok(),
|
||||||
maybe_wlr_screencopy_mgr: globals.bind(&qh, 2..=2, ()).ok(),
|
maybe_wlr_screencopy_mgr: globals.bind(&qh, 3..=3, ()).ok(),
|
||||||
|
maybe_zwp_linux_dmabuf: globals.bind(&qh, 4..=4, ()).ok(),
|
||||||
outputs: IdMap::new(),
|
outputs: IdMap::new(),
|
||||||
queue: Arc::new(Mutex::new(queue)),
|
queue: Arc::new(Mutex::new(queue)),
|
||||||
globals,
|
globals,
|
||||||
@@ -441,3 +446,27 @@ impl Dispatch<WlShm, ()> for WlxClient {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Dispatch<ZwpLinuxDmabufV1, ()> for WlxClient {
|
||||||
|
fn event(
|
||||||
|
_state: &mut Self,
|
||||||
|
_proxy: &ZwpLinuxDmabufV1,
|
||||||
|
_event: <ZwpLinuxDmabufV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &Connection,
|
||||||
|
_qhandle: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<ZwpLinuxBufferParamsV1, ()> for WlxClient {
|
||||||
|
fn event(
|
||||||
|
_state: &mut Self,
|
||||||
|
_proxy: &ZwpLinuxBufferParamsV1,
|
||||||
|
_event: <ZwpLinuxBufferParamsV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &Connection,
|
||||||
|
_qhandle: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use wayland_client::{
|
|||||||
Connection, Dispatch, Proxy, QueueHandle, WEnum,
|
Connection, Dispatch, Proxy, QueueHandle, WEnum,
|
||||||
protocol::{wl_buffer::WlBuffer, wl_shm::Format, wl_shm_pool::WlShmPool},
|
protocol::{wl_buffer::WlBuffer, wl_shm::Format, wl_shm_pool::WlShmPool},
|
||||||
};
|
};
|
||||||
|
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_buffer_params_v1;
|
||||||
|
|
||||||
use smithay_client_toolkit::reexports::protocols_wlr::screencopy::v1::client::zwlr_screencopy_frame_v1::{ZwlrScreencopyFrameV1, self};
|
use smithay_client_toolkit::reexports::protocols_wlr::screencopy::v1::client::zwlr_screencopy_frame_v1::{ZwlrScreencopyFrameV1, self};
|
||||||
|
|
||||||
@@ -23,59 +24,82 @@ use crate::{
|
|||||||
wayland::WlxClient,
|
wayland::WlxClient,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BufData {
|
pub trait DmaExporter {
|
||||||
|
fn next_frame(
|
||||||
|
&mut self,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
fourcc: DrmFourcc,
|
||||||
|
) -> Option<(FramePlane, DrmModifier)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BufData {
|
||||||
|
Shm {
|
||||||
wl_buffer: WlBuffer,
|
wl_buffer: WlBuffer,
|
||||||
wl_pool: WlShmPool,
|
wl_pool: WlShmPool,
|
||||||
fd: RawFd,
|
fd: RawFd,
|
||||||
|
},
|
||||||
|
Dma {
|
||||||
|
wl_buffer: WlBuffer,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for BufData {
|
impl Drop for BufData {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.wl_buffer.destroy();
|
match self {
|
||||||
self.wl_pool.destroy();
|
Self::Shm {
|
||||||
|
wl_buffer,
|
||||||
|
wl_pool,
|
||||||
|
fd,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
wl_buffer.destroy();
|
||||||
|
wl_pool.destroy();
|
||||||
unsafe {
|
unsafe {
|
||||||
libc::close(self.fd);
|
libc::close(*fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::Dma { wl_buffer } => {
|
||||||
|
wl_buffer.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ScreenCopyEvent {
|
enum ScreenCopyEvent {
|
||||||
Buffer {
|
Buffer {
|
||||||
data: BufData,
|
shm_format: Format,
|
||||||
drm_format: DrmFormat,
|
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
stride: u32,
|
stride: u32,
|
||||||
},
|
},
|
||||||
|
DmaBuf {
|
||||||
|
format: DrmFourcc,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
},
|
||||||
|
BuffersDone,
|
||||||
Ready,
|
Ready,
|
||||||
Failed,
|
Failed,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CaptureData<U, R>
|
struct CaptureData<U, R> {
|
||||||
where
|
|
||||||
U: Any,
|
|
||||||
R: Any,
|
|
||||||
{
|
|
||||||
sender: mpsc::SyncSender<R>,
|
sender: mpsc::SyncSender<R>,
|
||||||
receiver: mpsc::Receiver<R>,
|
receiver: mpsc::Receiver<R>,
|
||||||
user_data: U,
|
user_data: Option<Box<U>>,
|
||||||
receive_callback: fn(&U, WlxFrame) -> Option<R>,
|
receive_callback: fn(&U, WlxFrame) -> Option<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WlrScreencopyCapture<U, R>
|
pub struct WlrScreencopyCapture<U, R> {
|
||||||
where
|
|
||||||
U: Any + Send,
|
|
||||||
R: Any + Send,
|
|
||||||
{
|
|
||||||
output_id: u32,
|
output_id: u32,
|
||||||
wl: Option<Box<WlxClient>>,
|
wl: Option<Box<WlxClient>>,
|
||||||
handle: Option<JoinHandle<Box<WlxClient>>>,
|
handle: Option<JoinHandle<(Box<WlxClient>, Box<U>)>>,
|
||||||
data: Option<CaptureData<U, R>>,
|
data: Option<CaptureData<U, R>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R> WlrScreencopyCapture<U, R>
|
impl<U, R> WlrScreencopyCapture<U, R>
|
||||||
where
|
where
|
||||||
U: Any + Send,
|
U: Any + Send + DmaExporter,
|
||||||
R: Any + Send,
|
R: Any + Send,
|
||||||
{
|
{
|
||||||
pub fn new(wl: WlxClient, output_id: u32) -> Self {
|
pub fn new(wl: WlxClient, output_id: u32) -> Self {
|
||||||
@@ -90,7 +114,7 @@ where
|
|||||||
|
|
||||||
impl<U, R> WlxCapture<U, R> for WlrScreencopyCapture<U, R>
|
impl<U, R> WlxCapture<U, R> for WlrScreencopyCapture<U, R>
|
||||||
where
|
where
|
||||||
U: Any + Send + Clone,
|
U: Any + Send + DmaExporter,
|
||||||
R: Any + Send,
|
R: Any + Send,
|
||||||
{
|
{
|
||||||
fn init(
|
fn init(
|
||||||
@@ -105,7 +129,7 @@ where
|
|||||||
self.data = Some(CaptureData {
|
self.data = Some(CaptureData {
|
||||||
sender,
|
sender,
|
||||||
receiver,
|
receiver,
|
||||||
user_data,
|
user_data: Some(Box::new(user_data)),
|
||||||
receive_callback,
|
receive_callback,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -113,7 +137,7 @@ where
|
|||||||
self.data.is_some()
|
self.data.is_some()
|
||||||
}
|
}
|
||||||
fn supports_dmbuf(&self) -> bool {
|
fn supports_dmbuf(&self) -> bool {
|
||||||
false // screencopy v1
|
true // screencopy v3+
|
||||||
}
|
}
|
||||||
fn receive(&mut self) -> Option<R> {
|
fn receive(&mut self) -> Option<R> {
|
||||||
if let Some(data) = self.data.as_ref() {
|
if let Some(data) = self.data.as_ref() {
|
||||||
@@ -135,7 +159,9 @@ where
|
|||||||
if let Some(handle) = self.handle.take() {
|
if let Some(handle) = self.handle.take() {
|
||||||
if handle.is_finished() {
|
if handle.is_finished() {
|
||||||
wait_for_damage = true;
|
wait_for_damage = true;
|
||||||
self.wl = Some(handle.join().unwrap()); // safe to unwrap because we checked is_finished
|
let (wl, u) = handle.join().unwrap(); // safe to unwrap because is_finished
|
||||||
|
self.wl = Some(wl);
|
||||||
|
self.data.as_mut().unwrap().user_data = Some(u);
|
||||||
} else {
|
} else {
|
||||||
self.handle = Some(handle);
|
self.handle = Some(handle);
|
||||||
return;
|
return;
|
||||||
@@ -148,12 +174,12 @@ where
|
|||||||
|
|
||||||
let data = self
|
let data = self
|
||||||
.data
|
.data
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.expect("must call init once before request_new_frame");
|
.expect("must call init once before request_new_frame");
|
||||||
|
|
||||||
self.handle = Some(std::thread::spawn({
|
self.handle = Some(std::thread::spawn({
|
||||||
let sender = data.sender.clone();
|
let sender = data.sender.clone();
|
||||||
let user_data = data.user_data.clone();
|
let user_data = data.user_data.take().unwrap();
|
||||||
let receive_callback = data.receive_callback;
|
let receive_callback = data.receive_callback;
|
||||||
|
|
||||||
let output_id = self.output_id;
|
let output_id = self.output_id;
|
||||||
@@ -176,20 +202,20 @@ fn request_screencopy_frame<U, R>(
|
|||||||
client: Box<WlxClient>,
|
client: Box<WlxClient>,
|
||||||
output_id: u32,
|
output_id: u32,
|
||||||
sender: SyncSender<R>,
|
sender: SyncSender<R>,
|
||||||
user_data: U,
|
mut user_data: Box<U>,
|
||||||
receive_callback: fn(&U, WlxFrame) -> Option<R>,
|
receive_callback: fn(&U, WlxFrame) -> Option<R>,
|
||||||
wait_for_damage: bool,
|
wait_for_damage: bool,
|
||||||
) -> Box<WlxClient>
|
) -> (Box<WlxClient>, Box<U>)
|
||||||
where
|
where
|
||||||
U: Any + Send,
|
U: Any + Send + DmaExporter,
|
||||||
R: Any + Send,
|
R: Any + Send,
|
||||||
{
|
{
|
||||||
let Some(screencopy_manager) = client.maybe_wlr_screencopy_mgr.as_ref() else {
|
let Some(screencopy_manager) = client.maybe_wlr_screencopy_mgr.as_ref() else {
|
||||||
return client;
|
return (client, user_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(output) = client.outputs.get(output_id) else {
|
let Some(output) = client.outputs.get(output_id) else {
|
||||||
return client;
|
return (client, user_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
let transform = output.transform;
|
let transform = output.transform;
|
||||||
@@ -206,44 +232,138 @@ where
|
|||||||
|
|
||||||
let mut frame_buffer = None;
|
let mut frame_buffer = None;
|
||||||
|
|
||||||
|
let mut maybe_buffer = None;
|
||||||
|
let mut maybe_dmabuf = None;
|
||||||
|
|
||||||
'receiver: loop {
|
'receiver: loop {
|
||||||
for event in rx.try_iter() {
|
for event in rx.try_iter() {
|
||||||
match event {
|
match event {
|
||||||
ScreenCopyEvent::Buffer {
|
ScreenCopyEvent::Buffer { .. } => {
|
||||||
data,
|
log::trace!("{name}: ScreenCopy Buffer event received");
|
||||||
drm_format,
|
maybe_buffer = Some(event);
|
||||||
|
}
|
||||||
|
ScreenCopyEvent::DmaBuf { .. } => {
|
||||||
|
log::trace!("{name}: ScreenCopy LinuxDmabuf event received");
|
||||||
|
maybe_dmabuf = Some(event);
|
||||||
|
}
|
||||||
|
ScreenCopyEvent::BuffersDone => {
|
||||||
|
log::trace!("{name}: ScreenCopy BuffersDone event received");
|
||||||
|
if let Some(zwp_linux_dmabuf) = client.maybe_zwp_linux_dmabuf.as_ref()
|
||||||
|
&& let Some(ScreenCopyEvent::DmaBuf {
|
||||||
|
format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}) = maybe_dmabuf
|
||||||
|
&& let Some((plane, modifier)) = user_data.next_frame(width, height, format)
|
||||||
|
{
|
||||||
|
let mod_hi = (u64::from(modifier) >> 32) as _;
|
||||||
|
let mod_lo = (u64::from(modifier) & 0xFFFFFFFF) as _;
|
||||||
|
let fd = unsafe { BorrowedFd::borrow_raw(plane.fd.unwrap()) };
|
||||||
|
|
||||||
|
let params = zwp_linux_dmabuf.create_params(&client.queue_handle, ());
|
||||||
|
params.add(fd, 0, plane.offset, plane.stride as _, mod_hi, mod_lo);
|
||||||
|
|
||||||
|
let wl_buffer = params.create_immed(
|
||||||
|
width as _,
|
||||||
|
height as _,
|
||||||
|
format as _,
|
||||||
|
zwp_linux_buffer_params_v1::Flags::empty(),
|
||||||
|
&client.queue_handle,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
|
||||||
|
log::trace!("{name}: ScreenCopy with Dmabuf");
|
||||||
|
// copy_with_damage seems to not work here
|
||||||
|
proxy.copy(&wl_buffer);
|
||||||
|
|
||||||
|
frame_buffer = Some((WlxFrame::Implicit, BufData::Dma { wl_buffer }));
|
||||||
|
} else if let Some(ScreenCopyEvent::Buffer {
|
||||||
|
shm_format,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
stride,
|
stride,
|
||||||
} => {
|
}) = maybe_buffer
|
||||||
|
&& let Some(fourcc) = fourcc_from_wlshm(shm_format)
|
||||||
|
{
|
||||||
|
let fd_num = FD_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
|
let shm_name = CString::new(format!("wlx-{}", fd_num)).unwrap(); // safe
|
||||||
|
let size = stride * height;
|
||||||
|
let fd = unsafe {
|
||||||
|
let fd = libc::shm_open(
|
||||||
|
shm_name.as_ptr(),
|
||||||
|
O_CREAT | O_RDWR,
|
||||||
|
S_IRUSR | S_IWUSR,
|
||||||
|
);
|
||||||
|
libc::shm_unlink(shm_name.as_ptr());
|
||||||
|
libc::ftruncate(fd, size as _);
|
||||||
|
fd
|
||||||
|
};
|
||||||
|
|
||||||
|
let borrowed_fd = unsafe { BorrowedFd::borrow_raw(fd) };
|
||||||
|
|
||||||
|
let wl_pool = client.wl_shm.create_pool(
|
||||||
|
borrowed_fd,
|
||||||
|
size as _,
|
||||||
|
&client.queue_handle,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let wl_buffer = wl_pool.create_buffer(
|
||||||
|
0,
|
||||||
|
width as _,
|
||||||
|
height as _,
|
||||||
|
stride as _,
|
||||||
|
shm_format,
|
||||||
|
&client.queue_handle,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
|
||||||
|
log::trace!("{name}: ScreenCopy with SHM");
|
||||||
|
if wait_for_damage {
|
||||||
|
proxy.copy_with_damage(&wl_buffer);
|
||||||
|
} else {
|
||||||
|
proxy.copy(&wl_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
let frame = MemFdFrame {
|
let frame = MemFdFrame {
|
||||||
format: FrameFormat {
|
format: FrameFormat {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
drm_format,
|
drm_format: DrmFormat {
|
||||||
|
code: fourcc,
|
||||||
|
modifier: DrmModifier::Invalid,
|
||||||
|
},
|
||||||
transform,
|
transform,
|
||||||
},
|
},
|
||||||
plane: FramePlane {
|
plane: FramePlane {
|
||||||
fd: Some(data.fd),
|
fd: Some(fd),
|
||||||
offset: 0,
|
offset: 0,
|
||||||
stride: stride as _,
|
stride: stride as _,
|
||||||
},
|
},
|
||||||
mouse: None,
|
mouse: None,
|
||||||
};
|
};
|
||||||
log::trace!("{}: Received screencopy buffer, copying", name.as_ref());
|
frame_buffer = Some((
|
||||||
if wait_for_damage {
|
WlxFrame::MemFd(frame),
|
||||||
proxy.copy_with_damage(&data.wl_buffer);
|
BufData::Shm {
|
||||||
|
wl_buffer,
|
||||||
|
wl_pool,
|
||||||
|
fd,
|
||||||
|
},
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
proxy.copy(&data.wl_buffer);
|
log::error!("{name}: No usable ScreenCopy buffers received.");
|
||||||
|
proxy.destroy();
|
||||||
|
break 'receiver;
|
||||||
}
|
}
|
||||||
frame_buffer = Some((frame, data));
|
|
||||||
client.dispatch();
|
client.dispatch();
|
||||||
}
|
}
|
||||||
ScreenCopyEvent::Ready => {
|
ScreenCopyEvent::Ready => {
|
||||||
|
log::trace!("{}: Frame ready?", name.as_ref());
|
||||||
if let Some((frame, buffer)) = frame_buffer {
|
if let Some((frame, buffer)) = frame_buffer {
|
||||||
if let Some(r) = receive_callback(&user_data, WlxFrame::MemFd(frame)) {
|
if let Some(r) = receive_callback(&user_data, frame) {
|
||||||
let _ = sender.send(r);
|
let _ = sender.send(r);
|
||||||
log::trace!("{}: Frame ready", name.as_ref());
|
log::trace!("{}: Frame ready!", name.as_ref());
|
||||||
}
|
}
|
||||||
drop(buffer);
|
drop(buffer);
|
||||||
}
|
}
|
||||||
@@ -257,19 +377,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client
|
(client, user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static FD_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
static FD_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
impl Dispatch<ZwlrScreencopyFrameV1, SyncSender<ScreenCopyEvent>> for WlxClient {
|
impl Dispatch<ZwlrScreencopyFrameV1, SyncSender<ScreenCopyEvent>> for WlxClient {
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut Self,
|
_state: &mut Self,
|
||||||
proxy: &ZwlrScreencopyFrameV1,
|
proxy: &ZwlrScreencopyFrameV1,
|
||||||
event: <ZwlrScreencopyFrameV1 as Proxy>::Event,
|
event: <ZwlrScreencopyFrameV1 as Proxy>::Event,
|
||||||
data: &SyncSender<ScreenCopyEvent>,
|
data: &SyncSender<ScreenCopyEvent>,
|
||||||
_conn: &Connection,
|
_conn: &Connection,
|
||||||
qhandle: &QueueHandle<Self>,
|
_qhandle: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
zwlr_screencopy_frame_v1::Event::Failed => {
|
zwlr_screencopy_frame_v1::Event::Failed => {
|
||||||
@@ -289,58 +409,36 @@ impl Dispatch<ZwlrScreencopyFrameV1, SyncSender<ScreenCopyEvent>> for WlxClient
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(fourcc) = fourcc_from_wlshm(shm_format) else {
|
|
||||||
log::warn!("Unsupported screencopy format");
|
|
||||||
let _ = data.send(ScreenCopyEvent::Failed);
|
|
||||||
proxy.destroy();
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let fd_num = FD_COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let name = CString::new(format!("wlx-{}", fd_num)).unwrap(); // safe
|
|
||||||
let size = stride * height;
|
|
||||||
let fd = unsafe {
|
|
||||||
let fd = libc::shm_open(name.as_ptr(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
|
||||||
libc::shm_unlink(name.as_ptr());
|
|
||||||
libc::ftruncate(fd, size as _);
|
|
||||||
fd
|
|
||||||
};
|
|
||||||
|
|
||||||
let borrowed_fd = unsafe { BorrowedFd::borrow_raw(fd) };
|
|
||||||
|
|
||||||
let wl_pool = state
|
|
||||||
.wl_shm
|
|
||||||
.create_pool(borrowed_fd, size as _, qhandle, ());
|
|
||||||
|
|
||||||
let wl_buffer = wl_pool.create_buffer(
|
|
||||||
0,
|
|
||||||
width as _,
|
|
||||||
height as _,
|
|
||||||
stride as _,
|
|
||||||
shm_format,
|
|
||||||
qhandle,
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let _ = data.send(ScreenCopyEvent::Buffer {
|
let _ = data.send(ScreenCopyEvent::Buffer {
|
||||||
data: BufData {
|
|
||||||
wl_buffer,
|
|
||||||
wl_pool,
|
|
||||||
fd,
|
|
||||||
},
|
|
||||||
drm_format: DrmFormat {
|
|
||||||
code: fourcc,
|
|
||||||
modifier: DrmModifier::Invalid,
|
|
||||||
},
|
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
stride,
|
stride,
|
||||||
|
shm_format,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
zwlr_screencopy_frame_v1::Event::Ready { .. } => {
|
zwlr_screencopy_frame_v1::Event::Ready { .. } => {
|
||||||
let _ = data.send(ScreenCopyEvent::Ready);
|
let _ = data.send(ScreenCopyEvent::Ready);
|
||||||
proxy.destroy();
|
proxy.destroy();
|
||||||
}
|
}
|
||||||
|
zwlr_screencopy_frame_v1::Event::LinuxDmabuf {
|
||||||
|
format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
} => {
|
||||||
|
let Ok(format) = DrmFourcc::try_from(format) else {
|
||||||
|
log::warn!("{format} is not a known FourCC");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = data.send(ScreenCopyEvent::DmaBuf {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
format,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
zwlr_screencopy_frame_v1::Event::BufferDone => {
|
||||||
|
let _ = data.send(ScreenCopyEvent::BuffersDone);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,24 @@ pub type SerializedWindowStates = HashMap<Arc<str>, OverlayWindowState>;
|
|||||||
#[derive(Default, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)]
|
#[derive(Default, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)]
|
||||||
pub enum CaptureMethod {
|
pub enum CaptureMethod {
|
||||||
#[default]
|
#[default]
|
||||||
#[serde(alias = "pipewire", alias = "auto")]
|
#[serde(alias = "auto")]
|
||||||
|
#[strum(props(Translation = "APP_SETTINGS.OPTION.AUTO", Tooltip = "APP_SETTINGS.OPTION.AUTO_HELP"))]
|
||||||
|
Auto,
|
||||||
|
|
||||||
|
#[serde(alias = "pipewire")]
|
||||||
#[strum(props(Text = "PipeWire GPU", Tooltip = "APP_SETTINGS.OPTION.PIPEWIRE_HELP"))]
|
#[strum(props(Text = "PipeWire GPU", Tooltip = "APP_SETTINGS.OPTION.PIPEWIRE_HELP"))]
|
||||||
PipeWire,
|
PipeWire,
|
||||||
|
|
||||||
|
#[strum(props(Text = "ScreenCopy GPU", Tooltip = "APP_SETTINGS.OPTION.SCREENCOPY_GPU_HELP"))]
|
||||||
|
ScreenCopyGpu,
|
||||||
|
|
||||||
#[serde(alias = "pw-fallback")]
|
#[serde(alias = "pw-fallback")]
|
||||||
#[strum(props(Text = "PipeWire CPU", Tooltip = "APP_SETTINGS.OPTION.PW_FALLBACK_HELP"))]
|
#[strum(props(Text = "PipeWire CPU", Tooltip = "APP_SETTINGS.OPTION.PW_FALLBACK_HELP"))]
|
||||||
PwFallback,
|
PipeWireCpu,
|
||||||
|
|
||||||
#[serde(alias = "screencopy")]
|
#[serde(alias = "screencopy")]
|
||||||
#[strum(props(Text = "ScreenCopy CPU", Tooltip = "APP_SETTINGS.OPTION.SCREENCOPY_HELP"))]
|
#[strum(props(Text = "ScreenCopy CPU", Tooltip = "APP_SETTINGS.OPTION.SCREENCOPY_HELP"))]
|
||||||
ScreenCopy,
|
ScreenCopyCpu,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)]
|
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)]
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ impl WvrServerState {
|
|||||||
// this will throw a compile-time error if smithay's drm-fourcc is out of sync with wlx-capture's
|
// this will throw a compile-time error if smithay's drm-fourcc is out of sync with wlx-capture's
|
||||||
let mut formats: Vec<smithay::backend::allocator::Format> = vec![];
|
let mut formats: Vec<smithay::backend::allocator::Format> = vec![];
|
||||||
|
|
||||||
for f in &gfx_extras.drm_formats {
|
for f in &*gfx_extras.drm_formats {
|
||||||
formats.push(*f);
|
formats.push(*f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,14 @@ use vulkano::{
|
|||||||
VulkanError, VulkanObject,
|
VulkanError, VulkanObject,
|
||||||
device::Device,
|
device::Device,
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{Image, ImageCreateInfo, ImageTiling, ImageUsage, SubresourceLayout, sys::RawImage},
|
image::{
|
||||||
|
Image, ImageCreateInfo, ImageMemory, ImageTiling, ImageType, ImageUsage, SubresourceLayout,
|
||||||
|
sys::RawImage, view::ImageView,
|
||||||
|
},
|
||||||
memory::{
|
memory::{
|
||||||
DedicatedAllocation, DeviceMemory, ExternalMemoryHandleType, ExternalMemoryHandleTypes,
|
DedicatedAllocation, DeviceMemory, ExternalMemoryHandleType, ExternalMemoryHandleTypes,
|
||||||
MemoryAllocateInfo, MemoryImportInfo, MemoryPropertyFlags, ResourceMemory,
|
MemoryAllocateInfo, MemoryImportInfo, MemoryPropertyFlags, ResourceMemory,
|
||||||
allocator::{MemoryAllocator, MemoryTypeFilter},
|
allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter},
|
||||||
},
|
},
|
||||||
sync::Sharing,
|
sync::Sharing,
|
||||||
};
|
};
|
||||||
@@ -299,6 +302,70 @@ pub(super) unsafe fn create_dmabuf_image(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ExportedDmabufImage {
|
||||||
|
pub view: Arc<ImageView>,
|
||||||
|
pub fd: std::fs::File,
|
||||||
|
pub offset: u32,
|
||||||
|
pub stride: i32,
|
||||||
|
pub modifier: DrmModifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export_dmabuf_image(
|
||||||
|
allocator: Arc<dyn MemoryAllocator>,
|
||||||
|
extent: [u32; 3],
|
||||||
|
format: Format,
|
||||||
|
modifier: DrmModifier,
|
||||||
|
) -> anyhow::Result<ExportedDmabufImage> {
|
||||||
|
let layout = SubresourceLayout {
|
||||||
|
offset: 0,
|
||||||
|
size: 0,
|
||||||
|
row_pitch: align_to(format.block_size() * (extent[0] as u64), 64),
|
||||||
|
array_pitch: None,
|
||||||
|
depth_pitch: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let image = Image::new(
|
||||||
|
allocator.clone(),
|
||||||
|
ImageCreateInfo {
|
||||||
|
image_type: ImageType::Dim2d,
|
||||||
|
format,
|
||||||
|
extent,
|
||||||
|
usage: ImageUsage::TRANSFER_DST | ImageUsage::TRANSFER_SRC | ImageUsage::SAMPLED,
|
||||||
|
tiling: ImageTiling::DrmFormatModifier,
|
||||||
|
drm_format_modifiers: vec![modifier.into()],
|
||||||
|
drm_format_modifier_plane_layouts: vec![layout],
|
||||||
|
external_memory_handle_types: ExternalMemoryHandleTypes::DMA_BUF,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AllocationCreateInfo {
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.context("Could not create image to export")?;
|
||||||
|
|
||||||
|
let fd = match image.memory() {
|
||||||
|
ImageMemory::Normal(planes) if planes.len() == 1 => {
|
||||||
|
let plane = planes.first().unwrap();
|
||||||
|
plane
|
||||||
|
.device_memory()
|
||||||
|
.export_fd(ExternalMemoryHandleType::DmaBuf)?
|
||||||
|
}
|
||||||
|
_ => anyhow::bail!("Could not export DMA-buf: invalid ImageMemory"),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ExportedDmabufImage {
|
||||||
|
view: ImageView::new_default(image)?,
|
||||||
|
fd,
|
||||||
|
modifier: DrmModifier::from(modifier),
|
||||||
|
offset: layout.offset as _,
|
||||||
|
stride: layout.row_pitch as _,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn align_to(value: u64, alignment: u64) -> u64 {
|
||||||
|
((value + alignment - 1) / alignment) * alignment
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn get_drm_formats(device: Arc<Device>) -> Vec<DrmFormat> {
|
pub(super) fn get_drm_formats(device: Arc<Device>) -> Vec<DrmFormat> {
|
||||||
let possible_formats = [
|
let possible_formats = [
|
||||||
DrmFourcc::Abgr8888,
|
DrmFourcc::Abgr8888,
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ pub const BLEND_ALPHA: AttachmentBlend = AttachmentBlend {
|
|||||||
|
|
||||||
pub struct WGfxExtras {
|
pub struct WGfxExtras {
|
||||||
pub shaders: HashMap<&'static str, Arc<ShaderModule>>,
|
pub shaders: HashMap<&'static str, Arc<ShaderModule>>,
|
||||||
pub drm_formats: Vec<DrmFormat>,
|
pub drm_formats: Arc<[DrmFormat]>,
|
||||||
pub queue_capture: Option<Arc<Queue>>,
|
pub queue_capture: Option<Arc<Queue>>,
|
||||||
pub quad_verts: Vert2Buf,
|
pub quad_verts: Vert2Buf,
|
||||||
pub fallback_image: Arc<ImageView>,
|
pub fallback_image: Arc<ImageView>,
|
||||||
@@ -95,7 +95,7 @@ impl WGfxExtras {
|
|||||||
let shader = frag_screen::load(gfx.device.clone())?;
|
let shader = frag_screen::load(gfx.device.clone())?;
|
||||||
shaders.insert("frag_screen", shader);
|
shaders.insert("frag_screen", shader);
|
||||||
|
|
||||||
let drm_formats = get_drm_formats(gfx.device.clone());
|
let drm_formats = get_drm_formats(gfx.device.clone()).into();
|
||||||
|
|
||||||
let vertices = [
|
let vertices = [
|
||||||
Vert2Uv {
|
Vert2Uv {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use crate::{
|
|||||||
input::{HoverResult, PointerHit, PointerMode},
|
input::{HoverResult, PointerHit, PointerMode},
|
||||||
},
|
},
|
||||||
graphics::ExtentExt,
|
graphics::ExtentExt,
|
||||||
|
overlays::screen::capture::MyFirstDmaExporter,
|
||||||
state::AppState,
|
state::AppState,
|
||||||
subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta},
|
subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta},
|
||||||
windowing::backend::{
|
windowing::backend::{
|
||||||
@@ -41,8 +42,15 @@ fn set_next_move(millis_from_now: u64) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) enum CaptureType {
|
||||||
|
PipeWire,
|
||||||
|
ScreenCopy,
|
||||||
|
Xshm,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ScreenBackend {
|
pub struct ScreenBackend {
|
||||||
name: Arc<str>,
|
name: Arc<str>,
|
||||||
|
capture_type: CaptureType,
|
||||||
capture: Box<dyn WlxCapture<WlxCaptureIn, WlxCaptureOut>>,
|
capture: Box<dyn WlxCapture<WlxCaptureIn, WlxCaptureOut>>,
|
||||||
pipeline: Option<ScreenPipeline>,
|
pipeline: Option<ScreenPipeline>,
|
||||||
cur_frame: Option<WlxCaptureOut>,
|
cur_frame: Option<WlxCaptureOut>,
|
||||||
@@ -61,10 +69,12 @@ impl ScreenBackend {
|
|||||||
pub(super) fn new_raw(
|
pub(super) fn new_raw(
|
||||||
name: Arc<str>,
|
name: Arc<str>,
|
||||||
xr_backend: XrBackend,
|
xr_backend: XrBackend,
|
||||||
|
capture_type: CaptureType,
|
||||||
capture: Box<dyn WlxCapture<WlxCaptureIn, WlxCaptureOut>>,
|
capture: Box<dyn WlxCapture<WlxCaptureIn, WlxCaptureOut>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
|
capture_type,
|
||||||
capture,
|
capture,
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
cur_frame: None,
|
cur_frame: None,
|
||||||
@@ -151,17 +161,17 @@ impl OverlayBackend for ScreenBackend {
|
|||||||
|
|
||||||
let allow_dmabuf = !matches!(
|
let allow_dmabuf = !matches!(
|
||||||
capture_method,
|
capture_method,
|
||||||
CaptureMethod::PwFallback | CaptureMethod::ScreenCopy
|
CaptureMethod::PipeWireCpu | CaptureMethod::ScreenCopyCpu
|
||||||
);
|
);
|
||||||
|
|
||||||
let dmabuf_formats = if !supports_dmabuf {
|
let (dmabuf_formats, dma_exporter) = if !supports_dmabuf {
|
||||||
log::info!("Capture method does not support DMA-buf");
|
log::info!("Capture method does not support DMA-buf");
|
||||||
if app.gfx_extras.queue_capture.is_none() {
|
if app.gfx_extras.queue_capture.is_none() {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Current GPU does not support multiple queues. Software capture will take place on the main thread. Expect degraded performance."
|
"Current GPU does not support multiple queues. Software capture will take place on the main thread. Expect degraded performance."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
&Vec::new()
|
([].as_slice(), None)
|
||||||
} else if !allow_dmabuf {
|
} else if !allow_dmabuf {
|
||||||
log::info!(
|
log::info!(
|
||||||
"Not using DMA-buf capture due to {}",
|
"Not using DMA-buf capture due to {}",
|
||||||
@@ -172,16 +182,25 @@ impl OverlayBackend for ScreenBackend {
|
|||||||
"Current GPU does not support multiple queues. Software capture will take place on the main thread. Expect degraded performance."
|
"Current GPU does not support multiple queues. Software capture will take place on the main thread. Expect degraded performance."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
&Vec::new()
|
([].as_slice(), None)
|
||||||
} else {
|
} else {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Using GPU capture. If you're having issues with screens, go to the Dashboard's Settings tab and switch 'Wayland capture method' to a CPU option!"
|
"Using GPU capture. If you're having issues with screens, go to the Dashboard's Settings tab and switch 'Wayland capture method' to a CPU option!"
|
||||||
);
|
);
|
||||||
|
|
||||||
&app.gfx_extras.drm_formats
|
let dma_exporter = if matches!(self.capture_type, CaptureType::ScreenCopy) {
|
||||||
|
Some(MyFirstDmaExporter::new(
|
||||||
|
app.gfx.clone(),
|
||||||
|
app.gfx_extras.drm_formats.clone(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_data = WlxCaptureIn::new(self.name.clone(), app);
|
(&*app.gfx_extras.drm_formats, dma_exporter)
|
||||||
|
};
|
||||||
|
|
||||||
|
let user_data = WlxCaptureIn::new(self.name.clone(), app, dma_exporter);
|
||||||
self.capture
|
self.capture
|
||||||
.init(dmabuf_formats, user_data, receive_callback);
|
.init(dmabuf_formats, user_data, receive_callback);
|
||||||
self.capture.request_new_frame();
|
self.capture.request_new_frame();
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
use std::{f32::consts::PI, sync::Arc};
|
use std::{
|
||||||
|
f32::consts::PI,
|
||||||
|
os::fd::AsRawFd,
|
||||||
|
sync::{Arc, OnceLock},
|
||||||
|
};
|
||||||
|
|
||||||
use glam::{Affine3A, Vec3};
|
use glam::{Affine3A, Vec3};
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
@@ -8,24 +12,30 @@ use vulkano::{
|
|||||||
device::Queue,
|
device::Queue,
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{Image, sampler::Filter, view::ImageView},
|
image::{Image, sampler::Filter, view::ImageView},
|
||||||
|
memory::{ExternalMemoryHandleTypes, allocator::MemoryAllocator},
|
||||||
pipeline::graphics::color_blend::AttachmentBlend,
|
pipeline::graphics::color_blend::AttachmentBlend,
|
||||||
};
|
};
|
||||||
use wgui::gfx::{
|
use wgui::{
|
||||||
|
gfx::{
|
||||||
WGfx,
|
WGfx,
|
||||||
cmd::WGfxClearMode,
|
cmd::WGfxClearMode,
|
||||||
|
memory_allocator,
|
||||||
pass::WGfxPass,
|
pass::WGfxPass,
|
||||||
pipeline::{WGfxPipeline, WPipelineCreateInfo},
|
pipeline::{WGfxPipeline, WPipelineCreateInfo},
|
||||||
|
},
|
||||||
|
log::LogErr,
|
||||||
};
|
};
|
||||||
use wlx_capture::{
|
use wlx_capture::{
|
||||||
DrmFormat, WlxCapture,
|
DrmFormat, DrmFourcc, DrmModifier, WlxCapture,
|
||||||
frame::{self as wlx_frame, FrameFormat, MouseMeta, WlxFrame},
|
frame::{self as wlx_frame, FrameFormat, MouseMeta, WlxFrame},
|
||||||
|
wlr_screencopy::DmaExporter,
|
||||||
};
|
};
|
||||||
use wlx_common::{config::GeneralConfig, overlays::StereoMode};
|
use wlx_common::{config::GeneralConfig, overlays::StereoMode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
graphics::{
|
graphics::{
|
||||||
Vert2Uv,
|
ExtentExt, Vert2Uv,
|
||||||
dmabuf::{WGfxDmabuf, fourcc_to_vk},
|
dmabuf::{ExportedDmabufImage, WGfxDmabuf, export_dmabuf_image, fourcc_to_vk},
|
||||||
upload_quad_vertices,
|
upload_quad_vertices,
|
||||||
},
|
},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
@@ -343,15 +353,120 @@ fn stereo_mode_to_verts(stereo: StereoMode, array_index: usize) -> [Vert2Uv; 4]
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
static DMA_ALLOCATOR: OnceLock<Arc<dyn MemoryAllocator>> = OnceLock::new();
|
||||||
|
|
||||||
|
pub(super) struct MyFirstDmaExporter {
|
||||||
|
gfx: Arc<WGfx>,
|
||||||
|
drm_formats: Arc<[DrmFormat]>,
|
||||||
|
images: SmallVec<[ExportedDmabufImage; 2]>,
|
||||||
|
fourcc: DrmFourcc,
|
||||||
|
current: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyFirstDmaExporter {
|
||||||
|
pub(super) fn new(gfx: Arc<WGfx>, drm_formats: Arc<[DrmFormat]>) -> Self {
|
||||||
|
Self {
|
||||||
|
gfx,
|
||||||
|
drm_formats,
|
||||||
|
images: smallvec![],
|
||||||
|
fourcc: DrmFourcc::Argb8888,
|
||||||
|
current: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current(&self) -> Option<(Arc<ImageView>, FrameFormat)> {
|
||||||
|
let image = self.images.get(self.current)?;
|
||||||
|
let extent = image.view.extent_u32arr();
|
||||||
|
Some((
|
||||||
|
image.view.clone(),
|
||||||
|
FrameFormat {
|
||||||
|
width: extent[0],
|
||||||
|
height: extent[1],
|
||||||
|
drm_format: DrmFormat {
|
||||||
|
code: self.fourcc,
|
||||||
|
modifier: image.modifier,
|
||||||
|
},
|
||||||
|
transform: wlx_frame::Transform::Undefined,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_format(
|
||||||
|
&mut self,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
fourcc: wlx_capture::DrmFourcc,
|
||||||
|
) -> Option<()> {
|
||||||
|
if let Some(image) = self.images.first() {
|
||||||
|
let extent = image.view.image().extent();
|
||||||
|
if self.fourcc == fourcc && extent[0] == width && extent[1] == height {
|
||||||
|
return Some(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.images.clear();
|
||||||
|
|
||||||
|
let Some(modifier) = self
|
||||||
|
.drm_formats
|
||||||
|
.iter()
|
||||||
|
.filter(|f| f.code == fourcc)
|
||||||
|
.map(|f| f.modifier)
|
||||||
|
.next()
|
||||||
|
else {
|
||||||
|
log::error!("Unsupported format requested: {fourcc}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let format = fourcc_to_vk(fourcc)
|
||||||
|
.log_err("Could not export new dmabuf due to invalid format")
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
let allocator = DMA_ALLOCATOR.get_or_init(|| {
|
||||||
|
memory_allocator(
|
||||||
|
self.gfx.device.clone(),
|
||||||
|
Some(ExternalMemoryHandleTypes::DMA_BUF),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
for _ in 0..2 {
|
||||||
|
let image =
|
||||||
|
export_dmabuf_image(allocator.clone(), [width, height, 1], format, modifier)
|
||||||
|
.log_err("Could not export DMA-buf image")
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
self.images.push(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_frame(&mut self) -> Option<(wlx_frame::FramePlane, DrmModifier)> {
|
||||||
|
self.current = 1 - self.current;
|
||||||
|
let image = self.images.get(self.current)?;
|
||||||
|
|
||||||
|
Some((
|
||||||
|
wlx_frame::FramePlane {
|
||||||
|
fd: Some(image.fd.as_raw_fd()),
|
||||||
|
offset: image.offset,
|
||||||
|
stride: image.stride,
|
||||||
|
},
|
||||||
|
image.modifier,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WlxCaptureIn {
|
pub struct WlxCaptureIn {
|
||||||
name: Arc<str>,
|
name: Arc<str>,
|
||||||
gfx: Arc<WGfx>,
|
gfx: Arc<WGfx>,
|
||||||
queue: Arc<Queue>,
|
queue: Arc<Queue>,
|
||||||
|
dma_exporter: Option<MyFirstDmaExporter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlxCaptureIn {
|
impl WlxCaptureIn {
|
||||||
pub(super) fn new(name: Arc<str>, app: &AppState) -> Self {
|
pub(super) fn new(
|
||||||
|
name: Arc<str>,
|
||||||
|
app: &AppState,
|
||||||
|
dma_exporter: Option<MyFirstDmaExporter>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
gfx: app.gfx.clone(),
|
gfx: app.gfx.clone(),
|
||||||
@@ -361,10 +476,24 @@ impl WlxCaptureIn {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or_else(|| &app.gfx.queue_xfer)
|
.unwrap_or_else(|| &app.gfx.queue_xfer)
|
||||||
.clone(),
|
.clone(),
|
||||||
|
dma_exporter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DmaExporter for WlxCaptureIn {
|
||||||
|
fn next_frame(
|
||||||
|
&mut self,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
fourcc: DrmFourcc,
|
||||||
|
) -> Option<(wlx_frame::FramePlane, DrmModifier)> {
|
||||||
|
let dma_exporter = self.dma_exporter.as_mut()?;
|
||||||
|
dma_exporter.set_format(width, height, fourcc)?;
|
||||||
|
dma_exporter.next_frame()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(super) struct WlxCaptureOut {
|
pub(super) struct WlxCaptureOut {
|
||||||
pub(super) image: Arc<ImageView>,
|
pub(super) image: Arc<ImageView>,
|
||||||
@@ -501,6 +630,33 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
|
|||||||
mouse: frame.mouse,
|
mouse: frame.mouse,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
WlxFrame::Implicit => {
|
||||||
|
log::trace!("{}: New Implicit frame", me.name);
|
||||||
|
|
||||||
|
let Some((image, format)) = me.dma_exporter.as_ref().unwrap().get_current() else {
|
||||||
|
log::error!("{}: Implicit frame is missing!", me.name);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(WlxCaptureOut {
|
||||||
|
image,
|
||||||
|
format,
|
||||||
|
mouse: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DmaExporter is not used for SHM capture
|
||||||
|
pub(super) struct DummyDrmExporter;
|
||||||
|
impl DmaExporter for DummyDrmExporter {
|
||||||
|
fn next_frame(
|
||||||
|
&mut self,
|
||||||
|
_: u32,
|
||||||
|
_: u32,
|
||||||
|
_: DrmFourcc,
|
||||||
|
) -> Option<(wlx_frame::FramePlane, DrmModifier)> {
|
||||||
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,7 +664,7 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
|
|||||||
// In this case, receive_callback needs to run on the main thread
|
// In this case, receive_callback needs to run on the main thread
|
||||||
pub(super) struct MainThreadWlxCapture<T>
|
pub(super) struct MainThreadWlxCapture<T>
|
||||||
where
|
where
|
||||||
T: WlxCapture<(), WlxFrame>,
|
T: WlxCapture<DummyDrmExporter, WlxFrame>,
|
||||||
{
|
{
|
||||||
inner: T,
|
inner: T,
|
||||||
data: Option<WlxCaptureIn>,
|
data: Option<WlxCaptureIn>,
|
||||||
@@ -516,7 +672,7 @@ where
|
|||||||
|
|
||||||
impl<T> MainThreadWlxCapture<T>
|
impl<T> MainThreadWlxCapture<T>
|
||||||
where
|
where
|
||||||
T: WlxCapture<(), WlxFrame>,
|
T: WlxCapture<DummyDrmExporter, WlxFrame>,
|
||||||
{
|
{
|
||||||
pub const fn new(inner: T) -> Self {
|
pub const fn new(inner: T) -> Self {
|
||||||
Self { inner, data: None }
|
Self { inner, data: None }
|
||||||
@@ -525,7 +681,7 @@ where
|
|||||||
|
|
||||||
impl<T> WlxCapture<WlxCaptureIn, WlxCaptureOut> for MainThreadWlxCapture<T>
|
impl<T> WlxCapture<WlxCaptureIn, WlxCaptureOut> for MainThreadWlxCapture<T>
|
||||||
where
|
where
|
||||||
T: WlxCapture<(), WlxFrame>,
|
T: WlxCapture<DummyDrmExporter, WlxFrame>,
|
||||||
{
|
{
|
||||||
fn init(
|
fn init(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -534,7 +690,8 @@ where
|
|||||||
_: fn(&WlxCaptureIn, WlxFrame) -> Option<WlxCaptureOut>,
|
_: fn(&WlxCaptureIn, WlxFrame) -> Option<WlxCaptureOut>,
|
||||||
) {
|
) {
|
||||||
self.data = Some(user_data);
|
self.data = Some(user_data);
|
||||||
self.inner.init(dmabuf_formats, (), receive_callback_dummy);
|
self.inner
|
||||||
|
.init(dmabuf_formats, DummyDrmExporter, receive_callback_dummy);
|
||||||
}
|
}
|
||||||
fn is_ready(&self) -> bool {
|
fn is_ready(&self) -> bool {
|
||||||
self.inner.is_ready()
|
self.inner.is_ready()
|
||||||
@@ -559,7 +716,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref, clippy::unnecessary_wraps)]
|
#[allow(clippy::trivially_copy_pass_by_ref, clippy::unnecessary_wraps)]
|
||||||
const fn receive_callback_dummy(_: &(), frame: WlxFrame) -> Option<WlxFrame> {
|
const fn receive_callback_dummy(_: &DummyDrmExporter, frame: WlxFrame) -> Option<WlxFrame> {
|
||||||
Some(frame)
|
Some(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ use crate::{
|
|||||||
input::{HoverResult, PointerHit},
|
input::{HoverResult, PointerHit},
|
||||||
task::{OverlayTask, TaskType, ToggleMode},
|
task::{OverlayTask, TaskType, ToggleMode},
|
||||||
},
|
},
|
||||||
overlays::screen::capture::{MainThreadWlxCapture, new_wlx_capture},
|
overlays::screen::{
|
||||||
|
backend::CaptureType,
|
||||||
|
capture::{MainThreadWlxCapture, new_wlx_capture},
|
||||||
|
},
|
||||||
state::{AppSession, AppState},
|
state::{AppSession, AppState},
|
||||||
subsystem::hid::WheelDelta,
|
subsystem::hid::WheelDelta,
|
||||||
windowing::{
|
windowing::{
|
||||||
@@ -94,6 +97,7 @@ impl OverlayBackend for MirrorBackend {
|
|||||||
self.renderer = Some(ScreenBackend::new_raw(
|
self.renderer = Some(ScreenBackend::new_raw(
|
||||||
self.name.clone(),
|
self.name.clone(),
|
||||||
app.xr_backend,
|
app.xr_backend,
|
||||||
|
CaptureType::PipeWire,
|
||||||
capture,
|
capture,
|
||||||
));
|
));
|
||||||
app.tasks
|
app.tasks
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ impl ScreenBackend {
|
|||||||
token: Option<&str>,
|
token: Option<&str>,
|
||||||
app: &mut AppState,
|
app: &mut AppState,
|
||||||
) -> anyhow::Result<(Self, Option<String> /* pipewire restore token */)> {
|
) -> anyhow::Result<(Self, Option<String> /* pipewire restore token */)> {
|
||||||
|
use crate::overlays::screen::backend::CaptureType;
|
||||||
|
|
||||||
let name = output.name.clone();
|
let name = output.name.clone();
|
||||||
let embed_mouse = !app.session.config.double_cursor_fix;
|
let embed_mouse = !app.session.config.double_cursor_fix;
|
||||||
|
|
||||||
@@ -57,7 +59,12 @@ impl ScreenBackend {
|
|||||||
PipewireCapture::new(name, node_id)
|
PipewireCapture::new(name, node_id)
|
||||||
);
|
);
|
||||||
Ok((
|
Ok((
|
||||||
Self::new_raw(output.name.clone(), app.xr_backend, capture),
|
Self::new_raw(
|
||||||
|
output.name.clone(),
|
||||||
|
app.xr_backend,
|
||||||
|
CaptureType::PipeWire,
|
||||||
|
capture,
|
||||||
|
),
|
||||||
select_screen_result.restore_token,
|
select_screen_result.restore_token,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use wlx_capture::{
|
|||||||
WlxCapture,
|
WlxCapture,
|
||||||
frame::Transform,
|
frame::Transform,
|
||||||
wayland::{WlxClient, WlxOutput},
|
wayland::{WlxClient, WlxOutput},
|
||||||
wlr_dmabuf::WlrDmabufCapture,
|
|
||||||
wlr_screencopy::WlrScreencopyCapture,
|
wlr_screencopy::WlrScreencopyCapture,
|
||||||
};
|
};
|
||||||
use wlx_common::{
|
use wlx_common::{
|
||||||
@@ -12,7 +11,7 @@ use wlx_common::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
overlays::screen::create_screen_from_backend,
|
overlays::screen::{backend::CaptureType, create_screen_from_backend},
|
||||||
state::{AppState, ScreenMeta},
|
state::{AppState, ScreenMeta},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -24,22 +23,18 @@ use super::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
impl ScreenBackend {
|
impl ScreenBackend {
|
||||||
pub fn new_wlr_dmabuf(output: &WlxOutput, app: &AppState) -> Option<Self> {
|
|
||||||
let client = WlxClient::new()?;
|
|
||||||
let capture = new_wlx_capture!(
|
|
||||||
app.gfx_extras.queue_capture,
|
|
||||||
WlrDmabufCapture::new(client, output.id)
|
|
||||||
);
|
|
||||||
Some(Self::new_raw(output.name.clone(), app.xr_backend, capture))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_wlr_screencopy(output: &WlxOutput, app: &AppState) -> Option<Self> {
|
pub fn new_wlr_screencopy(output: &WlxOutput, app: &AppState) -> Option<Self> {
|
||||||
let client = WlxClient::new()?;
|
let client = WlxClient::new()?;
|
||||||
let capture = new_wlx_capture!(
|
let capture = new_wlx_capture!(
|
||||||
app.gfx_extras.queue_capture,
|
app.gfx_extras.queue_capture,
|
||||||
WlrScreencopyCapture::new(client, output.id)
|
WlrScreencopyCapture::new(client, output.id)
|
||||||
);
|
);
|
||||||
Some(Self::new_raw(output.name.clone(), app.xr_backend, capture))
|
Some(Self::new_raw(
|
||||||
|
output.name.clone(),
|
||||||
|
app.xr_backend,
|
||||||
|
CaptureType::ScreenCopy,
|
||||||
|
capture,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,9 +47,12 @@ pub fn create_screen_renderer_wl(
|
|||||||
) -> Option<ScreenBackend> {
|
) -> Option<ScreenBackend> {
|
||||||
let mut capture: Option<ScreenBackend> = None;
|
let mut capture: Option<ScreenBackend> = None;
|
||||||
|
|
||||||
if matches!(app.session.config.capture_method, CaptureMethod::ScreenCopy) && has_wlr_screencopy
|
if matches!(
|
||||||
|
app.session.config.capture_method,
|
||||||
|
CaptureMethod::ScreenCopyCpu | CaptureMethod::ScreenCopyGpu | CaptureMethod::Auto
|
||||||
|
) && has_wlr_screencopy
|
||||||
{
|
{
|
||||||
log::info!("{}: Using Wlr Screencopy Wl-SHM", &output.name);
|
log::info!("{}: Using ScreenCopy capture", &output.name);
|
||||||
capture = ScreenBackend::new_wlr_screencopy(output, app);
|
capture = ScreenBackend::new_wlr_screencopy(output, app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use wlx_capture::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
overlays::screen::create_screen_from_backend,
|
overlays::screen::{backend::CaptureType, create_screen_from_backend},
|
||||||
state::{AppState, ScreenMeta},
|
state::{AppState, ScreenMeta},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,7 +27,12 @@ impl ScreenBackend {
|
|||||||
app.gfx_extras.queue_capture,
|
app.gfx_extras.queue_capture,
|
||||||
XshmCapture::new(screen.clone())
|
XshmCapture::new(screen.clone())
|
||||||
);
|
);
|
||||||
Self::new_raw(screen.name.clone(), app.xr_backend, capture)
|
Self::new_raw(
|
||||||
|
screen.name.clone(),
|
||||||
|
app.xr_backend,
|
||||||
|
CaptureType::Xshm,
|
||||||
|
capture,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +102,7 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result<ScreenCreateDa
|
|||||||
let mut backend = ScreenBackend::new_raw(
|
let mut backend = ScreenBackend::new_raw(
|
||||||
m.name.clone(),
|
m.name.clone(),
|
||||||
app.xr_backend,
|
app.xr_backend,
|
||||||
|
CaptureType::PipeWire,
|
||||||
new_wlx_capture!(
|
new_wlx_capture!(
|
||||||
app.gfx_extras.queue_capture,
|
app.gfx_extras.queue_capture,
|
||||||
PipewireCapture::new(m.name.clone(), s.node_id)
|
PipewireCapture::new(m.name.clone(), s.node_id)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use chrono_tz::PST8PDT;
|
|
||||||
use glam::{Affine2, Affine3A, Quat, Vec2, Vec3, vec2, vec3};
|
use glam::{Affine2, Affine3A, Quat, Vec2, Vec3, vec2, vec3};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::PopupManager,
|
desktop::PopupManager,
|
||||||
|
|||||||
Reference in New Issue
Block a user