Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

screencapture: implement ext_image_copy_capture_manager_v1 #290

Merged
merged 5 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 48 additions & 44 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,50 +138,54 @@ Jay uses frame scheduling to achieve input latency as low as 1.5 ms.

Jay supports the following wayland protocols:

| Global | Version | Privileged |
|-----------------------------------------|:----------------|---------------|
| ext_foreign_toplevel_list_v1 | 1 | Yes |
| ext_idle_notifier_v1 | 1 | Yes |
| ext_session_lock_manager_v1 | 1 | Yes |
| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes |
| org_kde_kwin_server_decoration_manager | 1 | |
| wl_compositor | 6 | |
| wl_data_device_manager | 3 | |
| wl_drm | 2 | |
| wl_output | 4 | |
| wl_seat | 9 | |
| wl_shm | 2 | |
| wl_subcompositor | 1 | |
| wp_alpha_modifier_v1 | 1 | |
| wp_content_type_manager_v1 | 1 | |
| wp_cursor_shape_manager_v1 | 1 | |
| wp_drm_lease_device_v1 | 1 | |
| wp_fractional_scale_manager_v1 | 1 | |
| wp_linux_drm_syncobj_manager_v1 | 1 | |
| wp_presentation | 1 | |
| wp_security_context_manager_v1 | 1 | |
| wp_single_pixel_buffer_manager_v1 | 1 | |
| wp_tearing_control_manager_v1 | 1 | |
| wp_viewporter | 1 | |
| xdg_activation_v1 | 1 | |
| xdg_toplevel_drag_manager_v1 | 1 | |
| xdg_wm_base | 6 | |
| xdg_wm_dialog_v1 | 1 | |
| zwlr_data_control_manager_v1 | 2 | Yes |
| zwlr_layer_shell_v1 | 5 | No[^lsaccess] |
| zwlr_screencopy_manager_v1 | 3 | Yes |
| zwp_idle_inhibit_manager_v1 | 1 | |
| zwp_input_method_manager_v2 | 1 | Yes |
| zwp_linux_dmabuf_v1 | 5 | |
| zwp_pointer_constraints_v1 | 1 | |
| zwp_pointer_gestures_v1 | 3 | |
| zwp_primary_selection_device_manager_v1 | 1 | |
| zwp_relative_pointer_manager_v1 | 1 | |
| zwp_tablet_manager_v2 | 1 | |
| zwp_text_input_manager_v3 | 1 | |
| zwp_virtual_keyboard_manager_v1 | 1 | Yes |
| zxdg_decoration_manager_v1 | 1 | |
| zxdg_output_manager_v1 | 3 | |
| Global | Version | Privileged |
|------------------------------------------------------|:----------------|---------------|
| ext_foreign_toplevel_image_capture_source_manager_v1 | 1 | |
| ext_foreign_toplevel_list_v1 | 1 | Yes |
| ext_idle_notifier_v1 | 1 | Yes |
| ext_image_copy_capture_manager_v1 | 1[^composited] | Yes |
| ext_output_image_capture_source_manager_v1 | 1 | |
| ext_session_lock_manager_v1 | 1 | Yes |
| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes |
| org_kde_kwin_server_decoration_manager | 1 | |
| wl_compositor | 6 | |
| wl_data_device_manager | 3 | |
| wl_drm | 2 | |
| wl_output | 4 | |
| wl_seat | 9 | |
| wl_shm | 2 | |
| wl_subcompositor | 1 | |
| wp_alpha_modifier_v1 | 1 | |
| wp_content_type_manager_v1 | 1 | |
| wp_cursor_shape_manager_v1 | 1 | |
| wp_drm_lease_device_v1 | 1 | |
| wp_fractional_scale_manager_v1 | 1 | |
| wp_linux_drm_syncobj_manager_v1 | 1 | |
| wp_presentation | 1 | |
| wp_security_context_manager_v1 | 1 | |
| wp_single_pixel_buffer_manager_v1 | 1 | |
| wp_tearing_control_manager_v1 | 1 | |
| wp_viewporter | 1 | |
| xdg_activation_v1 | 1 | |
| xdg_toplevel_drag_manager_v1 | 1 | |
| xdg_wm_base | 6 | |
| xdg_wm_dialog_v1 | 1 | |
| zwlr_data_control_manager_v1 | 2 | Yes |
| zwlr_layer_shell_v1 | 5 | No[^lsaccess] |
| zwlr_screencopy_manager_v1 | 3 | Yes |
| zwp_idle_inhibit_manager_v1 | 1 | |
| zwp_input_method_manager_v2 | 1 | Yes |
| zwp_linux_dmabuf_v1 | 5 | |
| zwp_pointer_constraints_v1 | 1 | |
| zwp_pointer_gestures_v1 | 3 | |
| zwp_primary_selection_device_manager_v1 | 1 | |
| zwp_relative_pointer_manager_v1 | 1 | |
| zwp_tablet_manager_v2 | 1 | |
| zwp_text_input_manager_v3 | 1 | |
| zwp_virtual_keyboard_manager_v1 | 1 | Yes |
| zxdg_decoration_manager_v1 | 1 | |
| zxdg_output_manager_v1 | 3 | |

[^lsaccess]: Sandboxes can restrict access to this protocol.
[^ts_rejected]: Seat creation is always rejected.
[^composited]: Cursors are always composited.
2 changes: 2 additions & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
- Vulkan is now the default renderer.
- Emulate vblank events on the nvidia driver.
- Allow X windows to scale themselves.
- Implement ext-image-capture-source-v1.
- Implement ext-image-copy-capture-v1.

# 1.6.0 (2024-09-25)

Expand Down
8 changes: 7 additions & 1 deletion src/backends/metal/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,13 @@ impl MetalBackend {
return;
}
};
let master = Rc::new(DrmMaster::new(&slf.state.ring, res.fd.clone()));
let master = match DrmMaster::new(&slf.state.ring, res.fd.clone()) {
Ok(m) => Rc::new(m),
Err(e) => {
log::error!("Could not open the drm device: {}", ErrorFmt(e));
return;
}
};
let dev = match slf.create_drm_device(dev, &master) {
Ok(d) => d,
Err(e) => {
Expand Down
9 changes: 2 additions & 7 deletions src/backends/x.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use {
rc::Rc,
},
thiserror::Error,
uapi::{c::dev_t, Errno},
uapi::c::dev_t,
};

#[derive(Debug, Error)]
Expand Down Expand Up @@ -114,8 +114,6 @@ pub enum XBackendError {
MapWindow(#[source] XconError),
#[error("Could not query device")]
QueryDevice(#[source] XconError),
#[error("Could not fstat the drm device")]
DrmDeviceFstat(#[source] Errno),
#[error("Render device does not support XRGB8888 format")]
XRGB8888,
}
Expand Down Expand Up @@ -174,10 +172,7 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
Err(e) => return Err(XBackendError::DriOpen(e)),
}
};
let drm_dev = match uapi::fstat(drm.raw()) {
Ok(s) => s.st_rdev,
Err(e) => return Err(XBackendError::DrmDeviceFstat(e)),
};
let drm_dev = drm.dev();
let gbm = GbmDevice::new(&drm)?;
let ctx = match state.create_gfx_context(&drm, None) {
Ok(r) => r,
Expand Down
26 changes: 21 additions & 5 deletions src/client/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use {
crate::{
client::{Client, ClientError},
ifs::{
ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
ext_image_capture_source_v1::ExtImageCaptureSourceV1,
ext_image_copy::ext_image_copy_capture_session_v1::ExtImageCopyCaptureSessionV1,
ipc::{
wl_data_source::WlDataSource, zwlr_data_control_source_v1::ZwlrDataControlSourceV1,
zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
Expand Down Expand Up @@ -31,11 +34,13 @@ use {
copyhashmap::{CopyHashMap, Locked},
},
wire::{
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPopupId,
XdgPositionerId, XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
ZwpPrimarySelectionSourceV1Id, ZwpTabletToolV2Id,
ExtForeignToplevelHandleV1Id, ExtImageCaptureSourceV1Id,
ExtImageCopyCaptureSessionV1Id, JayOutputId, JayScreencastId, JayToplevelId,
JayWorkspaceId, WlBufferId, WlDataSourceId, WlOutputId, WlPointerId, WlRegionId,
WlRegistryId, WlSeatId, WlSurfaceId, WpDrmLeaseConnectorV1Id,
WpLinuxDrmSyncobjTimelineV1Id, XdgPopupId, XdgPositionerId, XdgSurfaceId,
XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id, ZwpPrimarySelectionSourceV1Id,
ZwpTabletToolV2Id,
},
},
std::{cell::RefCell, mem, rc::Rc},
Expand Down Expand Up @@ -67,6 +72,11 @@ pub struct Objects {
pub drm_lease_outputs: CopyHashMap<WpDrmLeaseConnectorV1Id, Rc<WpDrmLeaseConnectorV1>>,
pub tablet_tools: CopyHashMap<ZwpTabletToolV2Id, Rc<ZwpTabletToolV2>>,
pub xdg_popups: CopyHashMap<XdgPopupId, Rc<XdgPopup>>,
pub image_capture_sources: CopyHashMap<ExtImageCaptureSourceV1Id, Rc<ExtImageCaptureSourceV1>>,
pub foreign_toplevel_handles:
CopyHashMap<ExtForeignToplevelHandleV1Id, Rc<ExtForeignToplevelHandleV1>>,
pub ext_copy_sessions:
CopyHashMap<ExtImageCopyCaptureSessionV1Id, Rc<ExtImageCopyCaptureSessionV1>>,
ids: RefCell<Vec<usize>>,
}

Expand Down Expand Up @@ -100,6 +110,9 @@ impl Objects {
drm_lease_outputs: Default::default(),
tablet_tools: Default::default(),
xdg_popups: Default::default(),
image_capture_sources: Default::default(),
foreign_toplevel_handles: Default::default(),
ext_copy_sessions: Default::default(),
ids: RefCell::new(vec![]),
}
}
Expand Down Expand Up @@ -137,6 +150,9 @@ impl Objects {
self.drm_lease_outputs.clear();
self.tablet_tools.clear();
self.xdg_popups.clear();
self.image_capture_sources.clear();
self.foreign_toplevel_handles.clear();
self.ext_copy_sessions.clear();
}

pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
Expand Down
1 change: 1 addition & 0 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ fn create_dummy_output(state: &Rc<State>) {
latch_event: Default::default(),
presentation_event: Default::default(),
flip_margin_ns: Default::default(),
ext_copy_sessions: Default::default(),
});
let dummy_workspace = Rc::new(WorkspaceNode {
id: state.node_ids.next(),
Expand Down
5 changes: 2 additions & 3 deletions src/drm_feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ impl DrmFeedback {
ids: &DrmFeedbackIds,
render_ctx: &dyn GfxContext,
) -> Result<Self, DrmFeedbackError> {
let drm = match render_ctx.allocator().drm() {
Some(drm) => drm.raw(),
let main_device = match render_ctx.allocator().drm() {
Some(drm) => drm.dev(),
_ => return Err(DrmFeedbackError::NoDrmDevice),
};
let main_device = uapi::fstat(drm).map_err(OsError::from)?.st_rdev;
let (data, index_map) = create_fd_data(render_ctx);
let mut memfd =
uapi::memfd_create("drm_feedback", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
Expand Down
1 change: 1 addition & 0 deletions src/gfx_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ pub trait GfxFramebuffer: Debug {

pub trait GfxInternalFramebuffer: GfxFramebuffer {
fn into_fb(self: Rc<Self>) -> Rc<dyn GfxFramebuffer>;
fn stride(&self) -> i32;

fn staging_size(&self) -> usize;

Expand Down
4 changes: 4 additions & 0 deletions src/gfx_apis/gl/gl/render_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct GlRenderBuffer {
pub ctx: Rc<EglContext>,
pub width: i32,
pub height: i32,
pub stride: i32,
pub format: &'static Format,
rbo: GLuint,
}
Expand All @@ -30,6 +31,7 @@ impl GlRenderBuffer {
ctx: &Rc<EglContext>,
width: i32,
height: i32,
stride: i32,
format: &'static Format,
) -> Result<Rc<GlRenderBuffer>, RenderError> {
let Some(shm_info) = &format.shm_info else {
Expand All @@ -46,6 +48,7 @@ impl GlRenderBuffer {
ctx: ctx.clone(),
width,
height,
stride,
format,
rbo,
}))
Expand All @@ -71,6 +74,7 @@ impl GlRenderBuffer {
ctx: ctx.clone(),
width: img.dmabuf.width,
height: img.dmabuf.height,
stride: 0,
format: img.dmabuf.format,
rbo,
}))
Expand Down
4 changes: 2 additions & 2 deletions src/gfx_apis/gl/renderer/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,11 @@ impl GfxContext for GlRenderContext {
_cpu_worker: &Rc<CpuWorker>,
width: i32,
height: i32,
_stride: i32,
stride: i32,
format: &'static Format,
) -> Result<Rc<dyn GfxInternalFramebuffer>, GfxError> {
let fb = self.ctx.with_current(|| unsafe {
GlRenderBuffer::new(&self.ctx, width, height, format)?.create_framebuffer()
GlRenderBuffer::new(&self.ctx, width, height, stride, format)?.create_framebuffer()
})?;
Ok(Rc::new(Framebuffer { ctx: self, gl: fb }))
}
Expand Down
4 changes: 4 additions & 0 deletions src/gfx_apis/gl/renderer/framebuffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ impl GfxInternalFramebuffer for Framebuffer {
self
}

fn stride(&self) -> i32 {
self.gl.rb.stride
}

fn staging_size(&self) -> usize {
0
}
Expand Down
2 changes: 0 additions & 2 deletions src/gfx_apis/vulkan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ pub enum VulkanError {
CreateInstance(#[source] vk::Result),
#[error("Could not create a debug-utils messenger")]
Messenger(#[source] vk::Result),
#[error("Could not fstat the DRM FD")]
Fstat(#[source] OsError),
#[error("Could not enumerate the physical devices")]
EnumeratePhysicalDevices(#[source] vk::Result),
#[error("Could not find a vulkan device that matches dev_t {0}")]
Expand Down
6 changes: 1 addition & 5 deletions src/gfx_apis/vulkan/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,7 @@ impl VulkanInstance {
}

fn find_dev(&self, drm: &Drm) -> Result<PhysicalDevice, VulkanError> {
let stat = match uapi::fstat(drm.raw()) {
Ok(s) => s,
Err(e) => return Err(VulkanError::Fstat(e.into())),
};
let dev = stat.st_rdev;
let dev = drm.dev();
log::log!(
self.log_level,
"Searching for vulkan device with devnum {}:{}",
Expand Down
7 changes: 7 additions & 0 deletions src/gfx_apis/vulkan/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,13 @@ impl GfxInternalFramebuffer for VulkanImage {
self
}

fn stride(&self) -> i32 {
let VulkanImageMemory::Internal(shm) = &self.ty else {
unreachable!();
};
shm.stride as _
}

fn staging_size(&self) -> usize {
let VulkanImageMemory::Internal(shm) = &self.ty else {
unreachable!();
Expand Down
6 changes: 6 additions & 0 deletions src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ use {
backend::Backend,
client::{Client, ClientCaps},
ifs::{
ext_foreign_toplevel_image_capture_source_manager_v1::ExtForeignToplevelImageCaptureSourceManagerV1Global,
ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1Global,
ext_idle_notifier_v1::ExtIdleNotifierV1Global,
ext_image_copy::ext_image_copy_capture_manager_v1::ExtImageCopyCaptureManagerV1Global,
ext_output_image_capture_source_manager_v1::ExtOutputImageCaptureSourceManagerV1Global,
ext_session_lock_manager_v1::ExtSessionLockManagerV1Global,
ipc::{
wl_data_device_manager::WlDataDeviceManagerGlobal,
Expand Down Expand Up @@ -197,6 +200,9 @@ impl Globals {
add_singleton!(ZwpPointerGesturesV1Global);
add_singleton!(ZwpTabletManagerV2Global);
add_singleton!(JayDamageTrackingGlobal);
add_singleton!(ExtOutputImageCaptureSourceManagerV1Global);
add_singleton!(ExtForeignToplevelImageCaptureSourceManagerV1Global);
add_singleton!(ExtImageCopyCaptureManagerV1Global);
}

pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
Expand Down
4 changes: 4 additions & 0 deletions src/ifs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
pub mod ext_foreign_toplevel_handle_v1;
pub mod ext_foreign_toplevel_image_capture_source_manager_v1;
pub mod ext_foreign_toplevel_list_v1;
pub mod ext_idle_notification_v1;
pub mod ext_idle_notifier_v1;
pub mod ext_image_capture_source_v1;
pub mod ext_image_copy;
pub mod ext_output_image_capture_source_manager_v1;
pub mod ext_session_lock_manager_v1;
pub mod ext_session_lock_v1;
pub mod ipc;
Expand Down
Loading
Loading