From a1748811381338dff75e5cd5a26c51b83977ba94 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 1 Mar 2025 14:06:42 +0100 Subject: [PATCH] gfx: attach color descriptions --- src/backends/metal/present.rs | 10 ++- src/backends/metal/video.rs | 21 ++++- src/backends/x.rs | 2 + src/cmm/cmm_description.rs | 2 - src/cmm/cmm_manager.rs | 2 - src/compositor.rs | 5 +- src/cursor.rs | 3 + src/cursor_user.rs | 1 + src/damage.rs | 8 +- src/gfx_api.rs | 84 ++++++++++++++++++- src/gfx_apis/gl.rs | 12 ++- src/gfx_apis/gl/renderer/framebuffer.rs | 8 +- src/gfx_apis/vulkan/image.rs | 4 + .../ext_image_copy_capture_frame_v1.rs | 6 ++ .../ext_image_copy_capture_session_v1.rs | 3 + src/ifs/jay_screencast.rs | 6 ++ src/it/test_gfx_api.rs | 4 + src/portal.rs | 3 + src/portal/ptr_gui.rs | 29 +++++-- src/renderer.rs | 71 +++++++++++----- src/renderer/renderer_base.rs | 41 +++++++-- src/screenshoter.rs | 2 + src/state.rs | 17 +++- src/tree/output.rs | 9 ++ 24 files changed, 291 insertions(+), 62 deletions(-) diff --git a/src/backends/metal/present.rs b/src/backends/metal/present.rs index e89574f1..35a299c3 100644 --- a/src/backends/metal/present.rs +++ b/src/backends/metal/present.rs @@ -451,7 +451,9 @@ impl MetalConnector { }; self.state.present_hardware_cursor(node, &mut c); if c.cursor_swap_buffer { - c.sync_file = c.cursor_buffer.copy_to_dev(c.sync_file)?; + c.sync_file = c + .cursor_buffer + .copy_to_dev(&self.state.color_manager, c.sync_file)?; } self.cursor_swap_buffer.set(c.cursor_swap_buffer); if c.sync_file.is_some() { @@ -747,12 +749,14 @@ impl MetalConnector { .perform_render_pass( AcquireSync::Unnecessary, ReleaseSync::Explicit, + self.state.color_manager.srgb_srgb(), &latched.pass, &latched.damage, buffer.blend_buffer.as_ref(), + self.state.color_manager.srgb_linear(), ) .map_err(MetalError::RenderFrame)?; - sync_file = buffer.copy_to_dev(sf)?; + sync_file = buffer.copy_to_dev(&self.state.color_manager, sf)?; fb = buffer.drm.clone(); tex = buffer.render_tex.clone(); } @@ -792,6 +796,7 @@ impl MetalConnector { None => { output.perform_screencopies( &fb.tex, + self.state.color_manager.srgb_srgb(), None, &AcquireSync::Unnecessary, ReleaseSync::None, @@ -804,6 +809,7 @@ impl MetalConnector { Some(dsd) => { output.perform_screencopies( &dsd.tex, + self.state.color_manager.srgb_srgb(), dsd.resv.as_ref(), &dsd.acquire_sync, dsd.release_sync, diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index c49c68c0..0897f8cb 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -14,6 +14,7 @@ use { POST_COMMIT_MARGIN_DELTA, PresentFb, }, }, + cmm::cmm_manager::ColorManager, drm_feedback::DrmFeedback, edid::{CtaDataBlock, Descriptor, EdidExtension}, format::{ARGB8888, Format, XRGB8888}, @@ -2704,7 +2705,11 @@ impl MetalBackend { Err(e) => return Err(MetalError::ImportFb(e)), }; dev_fb - .clear(AcquireSync::Unnecessary, ReleaseSync::None) + .clear( + AcquireSync::Unnecessary, + ReleaseSync::None, + self.state.color_manager.srgb_srgb(), + ) .map_err(MetalError::Clear)?; let (dev_tex, render_tex, render_fb, render_bo) = if dev.id == render_ctx.dev_id { let render_tex = match dev_img.to_texture() { @@ -2758,7 +2763,11 @@ impl MetalBackend { Err(e) => return Err(MetalError::ImportFb(e)), }; render_fb - .clear(AcquireSync::Unnecessary, ReleaseSync::None) + .clear( + AcquireSync::Unnecessary, + ReleaseSync::None, + self.state.color_manager.srgb_srgb(), + ) .map_err(MetalError::Clear)?; let render_tex = match render_img.to_texture() { Ok(fb) => fb, @@ -3030,7 +3039,11 @@ impl RenderBuffer { .unwrap_or_else(|| self.dev_fb.clone()) } - pub fn copy_to_dev(&self, sync_file: Option) -> Result, MetalError> { + pub fn copy_to_dev( + &self, + cm: &ColorManager, + sync_file: Option, + ) -> Result, MetalError> { let Some(tex) = &self.dev_tex else { return Ok(sync_file); }; @@ -3038,7 +3051,9 @@ impl RenderBuffer { .copy_texture( AcquireSync::Unnecessary, ReleaseSync::Explicit, + cm.srgb_srgb(), tex, + cm.srgb_srgb(), None, AcquireSync::from_sync_file(sync_file), ReleaseSync::None, diff --git a/src/backends/x.rs b/src/backends/x.rs index 6bfd3aae..8cf4442d 100644 --- a/src/backends/x.rs +++ b/src/backends/x.rs @@ -751,11 +751,13 @@ impl XBackend { let res = self.state.present_output( &node, &image.fb.get(), + self.state.color_manager.srgb_srgb(), AcquireSync::Implicit, ReleaseSync::Implicit, &image.tex.get(), true, None, + self.state.color_manager.srgb_linear(), ); if let Err(e) = res { log::error!("Could not render screen: {}", ErrorFmt(e)); diff --git a/src/cmm/cmm_description.rs b/src/cmm/cmm_description.rs index a1c1a499..efdc7143 100644 --- a/src/cmm/cmm_description.rs +++ b/src/cmm/cmm_description.rs @@ -44,11 +44,9 @@ pub struct LinearColorDescription { #[derive(Debug)] pub struct ColorDescription { pub id: ColorDescriptionId, - #[expect(dead_code)] pub linear: Rc, #[expect(dead_code)] pub named_primaries: Option, - #[expect(dead_code)] pub transfer_function: TransferFunction, pub(super) shared: Rc, } diff --git a/src/cmm/cmm_manager.rs b/src/cmm/cmm_manager.rs index 23505765..1244e2d6 100644 --- a/src/cmm/cmm_manager.rs +++ b/src/cmm/cmm_manager.rs @@ -92,12 +92,10 @@ impl ColorManager { }) } - #[expect(dead_code)] pub fn srgb_srgb(&self) -> &Rc { &self.srgb_srgb } - #[expect(dead_code)] pub fn srgb_linear(&self) -> &Rc { &self.srgb_linear } diff --git a/src/compositor.rs b/src/compositor.rs index e9ffb99c..3b902ead 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -153,6 +153,7 @@ fn start_compositor2( let scales = RefCounted::default(); scales.add(Scale::from_int(1)); let cpu_worker = Rc::new(CpuWorker::new(&ring, &engine)?); + let color_manager = ColorManager::new(); let state = Rc::new(State { kb_ctx, backend: CloneCell::new(Rc::new(DummyBackend)), @@ -267,7 +268,7 @@ fn start_compositor2( tablet_ids: Default::default(), tablet_tool_ids: Default::default(), tablet_pad_ids: Default::default(), - damage_visualizer: DamageVisualizer::new(&engine), + damage_visualizer: DamageVisualizer::new(&engine, &color_manager), default_vrr_mode: Cell::new(VrrMode::NEVER), default_vrr_cursor_hz: Cell::new(None), default_tearing_mode: Cell::new(TearingMode::VARIANT_3), @@ -285,7 +286,7 @@ fn start_compositor2( data_control_device_ids: Default::default(), workspace_managers: Default::default(), color_management_enabled: Cell::new(false), - color_manager: ColorManager::new(), + color_manager, }); state.tracker.register(ClientId::from_raw(0)); create_dummy_output(&state); diff --git a/src/cursor.rs b/src/cursor.rs index 95bbeaf2..e09c3dc7 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -398,6 +398,7 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed AcquireSync::None, ReleaseSync::None, false, + renderer.state.color_manager.srgb_srgb(), ); } } @@ -422,6 +423,7 @@ impl Cursor for StaticCursor { AcquireSync::None, ReleaseSync::None, false, + renderer.state.color_manager.srgb_srgb(), ); } } @@ -464,6 +466,7 @@ impl Cursor for AnimatedCursor { AcquireSync::None, ReleaseSync::None, false, + renderer.state.color_manager.srgb_srgb(), ); } } diff --git a/src/cursor_user.rs b/src/cursor_user.rs index 6b6d526e..e1970e2d 100644 --- a/src/cursor_user.rs +++ b/src/cursor_user.rs @@ -507,6 +507,7 @@ impl CursorUser { &self.group.state, scale, transform, + self.group.state.color_manager.srgb_srgb(), ); match res { Ok(sync_file) => { diff --git a/src/damage.rs b/src/damage.rs index 88b0aadc..39d877ae 100644 --- a/src/damage.rs +++ b/src/damage.rs @@ -1,6 +1,7 @@ use { crate::{ async_engine::AsyncEngine, + cmm::cmm_manager::ColorManager, fixed::Fixed, gfx_api::GfxApiOpt, ifs::wl_output::WlOutputGlobal, @@ -77,6 +78,7 @@ pub struct DamageVisualizer { enabled: Cell, decay: Cell, color: Cell, + color_manager: Rc, } const MAX_RECTS: usize = 100_000; @@ -87,7 +89,7 @@ struct Damage { } impl DamageVisualizer { - pub fn new(eng: &Rc) -> Self { + pub fn new(eng: &Rc, color_manager: &Rc) -> Self { Self { eng: eng.clone(), entries: Default::default(), @@ -95,6 +97,7 @@ impl DamageVisualizer { enabled: Default::default(), decay: Cell::new(Duration::from_secs(2)), color: Cell::new(Color::from_srgba_straight(255, 0, 0, 128)), + color_manager: color_manager.clone(), } } @@ -162,13 +165,14 @@ impl DamageVisualizer { let dy = -cursor_rect.y1(); let decay_millis = decay.as_millis() as u64 as f32; renderer.ops.push(GfxApiOpt::Sync); + let srgb = &self.color_manager.srgb_srgb().linear; for entry in entries.iter().rev() { let region = Region::new(entry.rect); let region = region.subtract(&used); if region.is_not_empty() { let age = (now - entry.time).as_millis() as u64 as f32 / decay_millis; let color = base_color * (1.0 - age); - renderer.fill_boxes2(region.rects(), &color, dx, dy); + renderer.fill_boxes2(region.rects(), &color, srgb, dx, dy); used = used.union(®ion); } } diff --git a/src/gfx_api.rs b/src/gfx_api.rs index e832a8e1..302f63af 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -1,6 +1,7 @@ use { crate::{ allocator::Allocator, + cmm::cmm_description::{ColorDescription, LinearColorDescription}, cpu_worker::CpuWorker, cursor::Cursor, damage::DamageVisualizer, @@ -41,6 +42,7 @@ pub enum GfxApiOpt { pub struct GfxRenderPass { pub ops: Vec, pub clear: Option, + pub clear_cd: Rc, } #[derive(Default, Debug, Copy, Clone, PartialEq)] @@ -194,6 +196,8 @@ pub struct FillRect { pub rect: FramebufferRect, pub color: Color, pub alpha: Option, + #[expect(dead_code)] + pub cd: Rc, } impl FillRect { @@ -215,6 +219,8 @@ pub struct CopyTexture { pub release_sync: ReleaseSync, pub alpha: Option, pub opaque: bool, + #[expect(dead_code)] + pub cd: Rc, } #[derive(Clone, Debug)] @@ -299,10 +305,13 @@ pub trait GfxFramebuffer: Debug { self: Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, + cd: &Rc, ops: &[GfxApiOpt], clear: Option<&Color>, + clear_cd: &Rc, region: &Region, blend_buffer: Option<&Rc>, + blend_cd: &Rc, ) -> Result, GfxError>; fn format(&self) -> &'static Format; @@ -333,17 +342,23 @@ impl dyn GfxFramebuffer { self: &Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, + cd: &Rc, ops: &[GfxApiOpt], clear: Option<&Color>, + clear_cd: &Rc, blend_buffer: Option<&Rc>, + blend_cd: &Rc, ) -> Result, GfxError> { self.clone().render_with_region( acquire_sync, release_sync, + cd, ops, clear, + clear_cd, &self.full_region(), blend_buffer, + blend_cd, ) } @@ -351,17 +366,35 @@ impl dyn GfxFramebuffer { self: &Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, + cd: &Rc, ) -> Result, GfxError> { - self.clear_with(acquire_sync, release_sync, &Color::TRANSPARENT) + self.clear_with( + acquire_sync, + release_sync, + cd, + &Color::TRANSPARENT, + &cd.linear, + ) } pub fn clear_with( self: &Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, + cd: &Rc, color: &Color, + color_cd: &Rc, ) -> Result, GfxError> { - self.render(acquire_sync, release_sync, &[], Some(color), None) + self.render( + acquire_sync, + release_sync, + cd, + &[], + Some(color), + color_cd, + None, + cd, + ) } pub fn logical_size(&self, transform: Transform) -> (i32, i32) { @@ -381,7 +414,9 @@ impl dyn GfxFramebuffer { self: &Rc, fb_acquire_sync: AcquireSync, fb_release_sync: ReleaseSync, + fb_cd: &Rc, texture: &Rc, + texture_cd: &Rc, resv: Option<&Rc>, acquire_sync: AcquireSync, release_sync: ReleaseSync, @@ -404,24 +439,46 @@ impl dyn GfxFramebuffer { acquire_sync, release_sync, false, + texture_cd, ); let clear = self.format().has_alpha.then_some(&Color::TRANSPARENT); - self.render(fb_acquire_sync, fb_release_sync, &ops, clear, None) + self.render( + fb_acquire_sync, + fb_release_sync, + fb_cd, + &ops, + clear, + &fb_cd.linear, + None, + fb_cd, + ) } pub fn render_custom( self: &Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, + cd: &Rc, scale: Scale, clear: Option<&Color>, + clear_cd: &Rc, blend_buffer: Option<&Rc>, + blend_cd: &Rc, f: &mut dyn FnMut(&mut RendererBase), ) -> Result, GfxError> { let mut ops = vec![]; let mut renderer = self.renderer_base(&mut ops, scale, Transform::None); f(&mut renderer); - self.render(acquire_sync, release_sync, &ops, clear, blend_buffer) + self.render( + acquire_sync, + release_sync, + cd, + &ops, + clear, + clear_cd, + blend_buffer, + blend_cd, + ) } pub fn create_render_pass( @@ -456,17 +513,22 @@ impl dyn GfxFramebuffer { self: &Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, + cd: &Rc, pass: &GfxRenderPass, region: &Region, blend_buffer: Option<&Rc>, + blend_cd: &Rc, ) -> Result, GfxError> { self.clone().render_with_region( acquire_sync, release_sync, + cd, &pass.ops, pass.clear.as_ref(), + &pass.clear_cd, region, blend_buffer, + blend_cd, ) } @@ -474,6 +536,7 @@ impl dyn GfxFramebuffer { self: &Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, + cd: &Rc, node: &OutputNode, state: &State, cursor_rect: Option, @@ -481,10 +544,12 @@ impl dyn GfxFramebuffer { render_hardware_cursor: bool, fill_black_in_grace_period: bool, blend_buffer: Option<&Rc>, + blend_cd: &Rc, ) -> Result, GfxError> { self.render_node( acquire_sync, release_sync, + cd, node, state, cursor_rect, @@ -495,6 +560,7 @@ impl dyn GfxFramebuffer { fill_black_in_grace_period, node.global.persistent.transform.get(), blend_buffer, + blend_cd, ) } @@ -502,6 +568,7 @@ impl dyn GfxFramebuffer { self: &Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, + cd: &Rc, node: &dyn Node, state: &State, cursor_rect: Option, @@ -512,6 +579,7 @@ impl dyn GfxFramebuffer { fill_black_in_grace_period: bool, transform: Transform, blend_buffer: Option<&Rc>, + blend_cd: &Rc, ) -> Result, GfxError> { let pass = self.create_render_pass( node, @@ -528,9 +596,11 @@ impl dyn GfxFramebuffer { self.perform_render_pass( acquire_sync, release_sync, + cd, &pass, &self.full_region(), blend_buffer, + blend_cd, ) } @@ -542,6 +612,7 @@ impl dyn GfxFramebuffer { state: &State, scale: Scale, transform: Transform, + cd: &Rc, ) -> Result, GfxError> { let mut ops = vec![]; let mut renderer = Renderer { @@ -557,9 +628,12 @@ impl dyn GfxFramebuffer { self.render( acquire_sync, release_sync, + cd, &ops, Some(&Color::TRANSPARENT), + &cd.linear, None, + cd, ) } } @@ -832,6 +906,7 @@ pub fn create_render_pass( return GfxRenderPass { ops: vec![], clear: Some(Color::SOLID_BLACK), + clear_cd: state.color_manager.srgb_srgb().linear.clone(), }; } let mut ops = vec![]; @@ -898,6 +973,7 @@ pub fn create_render_pass( GfxRenderPass { ops, clear: Some(c), + clear_cd: state.color_manager.srgb_srgb().linear.clone(), } } diff --git a/src/gfx_apis/gl.rs b/src/gfx_apis/gl.rs index ff3dc526..d9b62411 100644 --- a/src/gfx_apis/gl.rs +++ b/src/gfx_apis/gl.rs @@ -69,7 +69,7 @@ use { crate::{ cmm::cmm_transfer_function::TransferFunction, gfx_api::{ - AcquireSync, CopyTexture, FillRect, GfxApiOpt, GfxContext, GfxError, GfxTexture, + AcquireSync, CopyTexture, FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxTexture, ReleaseSync, SyncFile, }, gfx_apis::gl::{ @@ -205,10 +205,15 @@ enum RenderError { #[derive(Default)] struct GfxGlState { triangles: RefCell>, - fill_rect: VecStorage, + fill_rect: VecStorage, copy_tex: VecStorage<&'static CopyTexture>, } +struct GlFillRect { + pub rect: FramebufferRect, + pub color: Color, +} + fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option { let mut state = fb.ctx.gl_state.borrow_mut(); let state = &mut *state; @@ -236,10 +241,9 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option { } } GfxApiOpt::FillRect(f) => { - fill_rect.push(FillRect { + fill_rect.push(GlFillRect { rect: f.rect, color: f.effective_color(), - alpha: None, }); i += 1; } diff --git a/src/gfx_apis/gl/renderer/framebuffer.rs b/src/gfx_apis/gl/renderer/framebuffer.rs index 714cdc69..e952778f 100644 --- a/src/gfx_apis/gl/renderer/framebuffer.rs +++ b/src/gfx_apis/gl/renderer/framebuffer.rs @@ -1,6 +1,9 @@ use { crate::{ - cmm::cmm_transfer_function::TransferFunction, + cmm::{ + cmm_description::{ColorDescription, LinearColorDescription}, + cmm_transfer_function::TransferFunction, + }, format::Format, gfx_api::{ AcquireSync, AsyncShmGfxTextureCallback, GfxApiOpt, GfxBlendBuffer, GfxError, @@ -105,10 +108,13 @@ impl GfxFramebuffer for Framebuffer { self: Rc, acquire_sync: AcquireSync, _release_sync: ReleaseSync, + _cd: &Rc, ops: &[GfxApiOpt], clear: Option<&Color>, + _clear_cd: &Rc, _region: &Region, _blend_buffer: Option<&Rc>, + _blend_cd: &Rc, ) -> Result, GfxError> { (*self) .render(acquire_sync, ops, clear) diff --git a/src/gfx_apis/vulkan/image.rs b/src/gfx_apis/vulkan/image.rs index 8b269883..b1ddcdcd 100644 --- a/src/gfx_apis/vulkan/image.rs +++ b/src/gfx_apis/vulkan/image.rs @@ -1,5 +1,6 @@ use { crate::{ + cmm::cmm_description::{ColorDescription, LinearColorDescription}, format::Format, gfx_api::{ AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, @@ -552,10 +553,13 @@ impl GfxFramebuffer for VulkanImage { self: Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, + _cd: &Rc, ops: &[GfxApiOpt], clear: Option<&Color>, + _clear_cd: &Rc, region: &Region, blend_buffer: Option<&Rc>, + _blend_cd: &Rc, ) -> Result, GfxError> { let mut blend_buffer = blend_buffer.map(|b| b.clone().into_vk(&self.renderer.device.device)); diff --git a/src/ifs/ext_image_copy/ext_image_copy_capture_frame_v1.rs b/src/ifs/ext_image_copy/ext_image_copy_capture_frame_v1.rs index ce4ee503..d90612e4 100644 --- a/src/ifs/ext_image_copy/ext_image_copy_capture_frame_v1.rs +++ b/src/ifs/ext_image_copy/ext_image_copy_capture_frame_v1.rs @@ -1,6 +1,7 @@ use { crate::{ client::{Client, ClientError}, + cmm::cmm_description::ColorDescription, gfx_api::{ AcquireSync, AsyncShmGfxTextureCallback, BufferResv, GfxError, GfxFramebuffer, GfxTexture, ReleaseSync, STAGING_DOWNLOAD, SyncFile, @@ -199,6 +200,7 @@ impl ExtImageCopyCaptureFrameV1 { self: &Rc, on: &OutputNode, texture: &Rc, + cd: &Rc, resv: Option<&Rc>, acquire_sync: &AcquireSync, release_sync: ReleaseSync, @@ -215,10 +217,12 @@ impl ExtImageCopyCaptureFrameV1 { resv, acquire_sync, release_sync, + cd, &fb, aq, re, jay_config::video::Transform::None, + self.client.state.color_manager.srgb_srgb(), on.global.pos.get(), render_hardware_cursors, x_off, @@ -236,6 +240,7 @@ impl ExtImageCopyCaptureFrameV1 { fb.render_node( aq, re, + self.client.state.color_manager.srgb_srgb(), node, &self.client.state, Some(node.node_absolute_position()), @@ -246,6 +251,7 @@ impl ExtImageCopyCaptureFrameV1 { false, jay_config::video::Transform::None, None, + self.client.state.color_manager.srgb_linear(), ) }); } diff --git a/src/ifs/ext_image_copy/ext_image_copy_capture_session_v1.rs b/src/ifs/ext_image_copy/ext_image_copy_capture_session_v1.rs index 65f7dc34..3ac1c7c6 100644 --- a/src/ifs/ext_image_copy/ext_image_copy_capture_session_v1.rs +++ b/src/ifs/ext_image_copy/ext_image_copy_capture_session_v1.rs @@ -1,6 +1,7 @@ use { crate::{ client::{Client, ClientError}, + cmm::cmm_description::ColorDescription, format::{FORMATS, Format}, gfx_api::{ AcquireSync, BufferResv, GfxInternalFramebuffer, GfxStagingBuffer, GfxTexture, @@ -213,6 +214,7 @@ impl ExtImageCopyCaptureSessionV1 { self: &Rc, on: &OutputNode, texture: &Rc, + cd: &Rc, resv: Option<&Rc>, acquire_sync: &AcquireSync, release_sync: ReleaseSync, @@ -226,6 +228,7 @@ impl ExtImageCopyCaptureSessionV1 { frame.copy_texture( on, texture, + cd, resv, acquire_sync, release_sync, diff --git a/src/ifs/jay_screencast.rs b/src/ifs/jay_screencast.rs index bde24705..f55ccec0 100644 --- a/src/ifs/jay_screencast.rs +++ b/src/ifs/jay_screencast.rs @@ -2,6 +2,7 @@ use { crate::{ allocator::{AllocatorError, BO_USE_LINEAR, BO_USE_RENDERING, BufferObject}, client::{Client, ClientError}, + cmm::cmm_description::ColorDescription, format::XRGB8888, gfx_api::{ AcquireSync, BufferResv, GfxContext, GfxError, GfxFramebuffer, GfxTexture, ReleaseSync, @@ -193,6 +194,7 @@ impl JayScreencast { let res = buffer.fb.render_node( AcquireSync::Implicit, ReleaseSync::Implicit, + self.client.state.color_manager.srgb_srgb(), tl.tl_as_node(), &self.client.state, Some(tl.node_absolute_position()), @@ -203,6 +205,7 @@ impl JayScreencast { false, Transform::None, None, + self.client.state.color_manager.srgb_linear(), ); match res { Ok(_) => { @@ -304,6 +307,7 @@ impl JayScreencast { &self, on: &OutputNode, texture: &Rc, + cd: &Rc, resv: Option<&Rc>, acquire_sync: &AcquireSync, release_sync: ReleaseSync, @@ -332,10 +336,12 @@ impl JayScreencast { resv, acquire_sync, release_sync, + cd, &buffer.fb, AcquireSync::Implicit, ReleaseSync::Implicit, Transform::None, + self.client.state.color_manager.srgb_srgb(), on.global.pos.get(), render_hardware_cursors, x_off, diff --git a/src/it/test_gfx_api.rs b/src/it/test_gfx_api.rs index 1069fbd9..658358da 100644 --- a/src/it/test_gfx_api.rs +++ b/src/it/test_gfx_api.rs @@ -1,6 +1,7 @@ use { crate::{ allocator::{Allocator, AllocatorError, BufferObject, BufferUsage}, + cmm::cmm_description::{ColorDescription, LinearColorDescription}, cpu_worker::CpuWorker, format::{ARGB8888, Format, XRGB8888}, gfx_api::{ @@ -391,10 +392,13 @@ impl GfxFramebuffer for TestGfxFb { self: Rc, _acquire_sync: AcquireSync, _release_sync: ReleaseSync, + _cd: &Rc, ops: &[GfxApiOpt], clear: Option<&Color>, + _clear_cd: &Rc, _region: &Region, _blend_buffer: Option<&Rc>, + _blend_cd: &Rc, ) -> Result, GfxError> { let fb_points = |width: i32, height: i32, rect: &FramebufferRect| { let points = rect.to_points(); diff --git a/src/portal.rs b/src/portal.rs index 9dc71936..e07942d9 100644 --- a/src/portal.rs +++ b/src/portal.rs @@ -10,6 +10,7 @@ use { crate::{ async_engine::AsyncEngine, cli::GlobalArgs, + cmm::cmm_manager::ColorManager, dbus::{ BUS_DEST, BUS_PATH, DBUS_NAME_FLAG_DO_NOT_QUEUE, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER, Dbus, DbusSocket, @@ -207,6 +208,7 @@ async fn run_async( render_ctxs: Default::default(), dma_buf_ids: Default::default(), pw_con: pw_con.as_ref().map(|c| c.con.clone()), + color_manager: ColorManager::new(), }); if let Some(pw_con) = &pw_con { pw_con.con.owner.set(Some(state.clone())); @@ -302,6 +304,7 @@ struct PortalState { render_ctxs: CopyHashMap>, dma_buf_ids: Rc, pw_con: Option>, + color_manager: Rc, } impl PortalState { diff --git a/src/portal/ptr_gui.rs b/src/portal/ptr_gui.rs index 458634c0..edc3865c 100644 --- a/src/portal/ptr_gui.rs +++ b/src/portal/ptr_gui.rs @@ -2,6 +2,7 @@ use { crate::{ allocator::{BO_USE_RENDERING, BufferObject, BufferUsage}, async_engine::{Phase, SpawnedFuture}, + cmm::cmm_manager::ColorManager, cursor::KnownCursor, fixed::Fixed, format::ARGB8888, @@ -59,7 +60,7 @@ pub trait GuiElement { max_width: f32, max_height: f32, ) -> (f32, f32); - fn render_at(&self, r: &mut RendererBase, x: f32, y: f32); + fn render_at(&self, color_manager: &ColorManager, r: &mut RendererBase, x: f32, y: f32); fn child_at(&self, x: f32, y: f32) -> Option>; fn hover_cursor(&self) -> KnownCursor { @@ -190,7 +191,9 @@ impl GuiElement for Button { (extents.width, extents.height) } - fn render_at(&self, r: &mut RendererBase, x1: f32, y1: f32) { + fn render_at(&self, color_manager: &ColorManager, r: &mut RendererBase, x1: f32, y1: f32) { + let srgb_srgb = color_manager.srgb_srgb(); + let srgb = &srgb_srgb.linear; let x2 = x1 + self.data.width.get(); let y2 = y1 + self.data.height.get(); let border = self.border.get(); @@ -201,7 +204,7 @@ impl GuiElement for Button { (x1, y1 + border, x1 + border, y2 - border), (x2 - border, y1 + border, x2, y2 - border), ]; - r.fill_boxes_f(&rects, &self.border_color.get()); + r.fill_boxes_f(&rects, &self.border_color.get(), srgb); } { let rects = [(x1 + border, y1 + border, x2 - border, y2 - border)]; @@ -209,7 +212,7 @@ impl GuiElement for Button { true => self.bg_color.get(), false => self.bg_hover_color.get(), }; - r.fill_boxes_f(&rects, &color); + r.fill_boxes_f(&rects, &color, srgb); } if let Some(tex) = self.tex.get() { let (tx, ty) = r.scale_point_f(x1 + self.tex_off_x.get(), y1 + self.tex_off_y.get()); @@ -226,6 +229,7 @@ impl GuiElement for Button { AcquireSync::None, ReleaseSync::None, false, + srgb_srgb, ); } } @@ -311,7 +315,7 @@ impl GuiElement for Label { (width as f32 / scale, height as f32 / scale) } - fn render_at(&self, r: &mut RendererBase, x: f32, y: f32) { + fn render_at(&self, color_manager: &ColorManager, r: &mut RendererBase, x: f32, y: f32) { if let Some(tex) = self.tex.get() { let (tx, ty) = r.scale_point_f(x, y); r.render_texture( @@ -327,6 +331,7 @@ impl GuiElement for Label { AcquireSync::None, ReleaseSync::None, false, + color_manager.srgb_srgb(), ); } } @@ -439,9 +444,14 @@ impl GuiElement for Flow { (w.min(max_width), h.min(max_height)) } - fn render_at(&self, r: &mut RendererBase, x: f32, y: f32) { + fn render_at(&self, color_manager: &ColorManager, r: &mut RendererBase, x: f32, y: f32) { for element in self.elements.borrow_mut().deref() { - element.render_at(r, x + element.data().x.get(), y + element.data().y.get()); + element.render_at( + color_manager, + r, + x + element.data().x.get(), + y + element.data().y.get(), + ); } } @@ -634,12 +644,15 @@ impl WindowData { let res = buf.fb.render_custom( AcquireSync::Implicit, ReleaseSync::Implicit, + self.dpy.state.color_manager.srgb_srgb(), self.scale.get(), Some(&Color::from_gray_srgb(0)), + &self.dpy.state.color_manager.srgb_srgb().linear, None, + self.dpy.state.color_manager.srgb_linear(), &mut |r| { if let Some(content) = self.content.get() { - content.render_at(r, 0.0, 0.0) + content.render_at(&self.dpy.state.color_manager, r, 0.0, 0.0) } }, ); diff --git a/src/renderer.rs b/src/renderer.rs index 6948a611..22b73182 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,6 +1,5 @@ use { crate::{ - cmm::cmm_transfer_function::TransferFunction, gfx_api::{AcquireSync, GfxApiOpt, ReleaseSync, SampleRect}, ifs::wl_surface::{ SurfaceBuffer, WlSurface, @@ -78,6 +77,8 @@ impl Renderer<'_> { } let theme = &self.state.theme; let th = theme.sizes.title_height.get(); + let srgb_srgb = self.state.color_manager.srgb_srgb(); + let srgb = &srgb_srgb.linear; if let Some(fs) = fullscreen { fs.tl_as_node().node_render(self, x, y, None); } else { @@ -90,26 +91,28 @@ impl Renderer<'_> { let bar_bg = self.base.scale_rect(bar_bg); let c = theme.colors.bar_background.get(); self.base - .fill_boxes3(slice::from_ref(&bar_bg), &c, None, x, y, true); + .fill_boxes3(slice::from_ref(&bar_bg), &c, None, srgb, x, y, true); let rd = output.render_data.borrow_mut(); if let Some(aw) = &rd.active_workspace { let c = match aw.captured { true => theme.colors.captured_focused_title_background.get(), false => theme.colors.focused_title_background.get(), }; - self.base.fill_boxes2(slice::from_ref(&aw.rect), &c, x, y); + self.base + .fill_boxes2(slice::from_ref(&aw.rect), &c, srgb, x, y); } let c = theme.colors.separator.get(); self.base - .fill_boxes2(slice::from_ref(&rd.underline), &c, x, y); + .fill_boxes2(slice::from_ref(&rd.underline), &c, srgb, x, y); let c = theme.colors.unfocused_title_background.get(); - self.base.fill_boxes2(&rd.inactive_workspaces, &c, x, y); + self.base + .fill_boxes2(&rd.inactive_workspaces, &c, srgb, x, y); let c = theme.colors.captured_unfocused_title_background.get(); self.base - .fill_boxes2(&rd.captured_inactive_workspaces, &c, x, y); + .fill_boxes2(&rd.captured_inactive_workspaces, &c, srgb, x, y); let c = theme.colors.attention_requested_background.get(); self.base - .fill_boxes2(&rd.attention_requested_workspaces, &c, x, y); + .fill_boxes2(&rd.attention_requested_workspaces, &c, srgb, x, y); let scale = output.global.persistent.scale.get(); for title in &rd.titles { let (x, y) = self.base.scale_point(x + title.tex_x, y + title.tex_y); @@ -126,6 +129,7 @@ impl Renderer<'_> { AcquireSync::None, ReleaseSync::None, false, + self.state.color_manager.srgb_srgb(), ); } if let Some(status) = &rd.status { @@ -144,6 +148,7 @@ impl Renderer<'_> { AcquireSync::None, ReleaseSync::None, false, + srgb_srgb, ); } } @@ -182,7 +187,7 @@ impl Renderer<'_> { if ws.render_highlight.get() > 0 { let color = self.state.theme.colors.highlight.get(); let bounds = ws.position.get().at_point(x, y + th + 1); - self.base.fill_boxes(&[bounds], &color); + self.base.fill_boxes(&[bounds], &color, srgb); } } } @@ -204,6 +209,7 @@ impl Renderer<'_> { self.base.fill_boxes( std::slice::from_ref(&pos.at_point(x, y)), &Color::from_srgba_straight(20, 20, 20, 255), + &self.state.color_manager.srgb_srgb().linear, ); if let Some(tex) = placeholder.textures.borrow().get(&self.base.scale) { if let Some(texture) = tex.texture() { @@ -223,6 +229,7 @@ impl Renderer<'_> { AcquireSync::None, ReleaseSync::None, false, + self.state.color_manager.srgb_srgb(), ); } } @@ -231,17 +238,21 @@ impl Renderer<'_> { pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) { { + let srgb_srgb = self.state.color_manager.srgb_srgb(); + let srgb = &srgb_srgb.linear; let rd = container.render_data.borrow_mut(); let c = self.state.theme.colors.unfocused_title_background.get(); - self.base.fill_boxes2(&rd.title_rects, &c, x, y); + self.base.fill_boxes2(&rd.title_rects, &c, srgb, x, y); let c = self.state.theme.colors.focused_title_background.get(); - self.base.fill_boxes2(&rd.active_title_rects, &c, x, y); + self.base + .fill_boxes2(&rd.active_title_rects, &c, srgb, x, y); let c = self.state.theme.colors.attention_requested_background.get(); - self.base.fill_boxes2(&rd.attention_title_rects, &c, x, y); + self.base + .fill_boxes2(&rd.attention_title_rects, &c, srgb, x, y); let c = self.state.theme.colors.separator.get(); - self.base.fill_boxes2(&rd.underline_rects, &c, x, y); + self.base.fill_boxes2(&rd.underline_rects, &c, srgb, x, y); let c = self.state.theme.colors.border.get(); - self.base.fill_boxes2(&rd.border_rects, &c, x, y); + self.base.fill_boxes2(&rd.border_rects, &c, srgb, x, y); if let Some(lar) = &rd.last_active_rect { let c = self .state @@ -249,7 +260,8 @@ impl Renderer<'_> { .colors .focused_inactive_title_background .get(); - self.base.fill_boxes2(std::slice::from_ref(lar), &c, x, y); + self.base + .fill_boxes2(std::slice::from_ref(lar), &c, srgb, x, y); } if let Some(titles) = rd.titles.get(&self.base.scale) { for title in titles { @@ -269,6 +281,7 @@ impl Renderer<'_> { AcquireSync::None, ReleaseSync::None, false, + srgb_srgb, ); } } @@ -341,14 +354,22 @@ impl Renderer<'_> { }; let color = self.state.theme.colors.highlight.get(); self.base.ops.push(GfxApiOpt::Sync); - self.base - .fill_scaled_boxes(slice::from_ref(bounds), &color, None); + self.base.fill_scaled_boxes( + slice::from_ref(bounds), + &color, + None, + &self.state.color_manager.srgb_srgb().linear, + ); } pub fn render_highlight(&mut self, rect: &Rect) { let color = self.state.theme.colors.highlight.get(); self.base.ops.push(GfxApiOpt::Sync); - self.base.fill_boxes(slice::from_ref(rect), &color); + self.base.fill_boxes( + slice::from_ref(rect), + &color, + &self.state.color_manager.srgb_srgb().linear, + ); } pub fn render_surface(&mut self, surface: &WlSurface, x: i32, y: i32, bounds: Option<&Rect>) { @@ -423,6 +444,7 @@ impl Renderer<'_> { bounds: Option<&Rect>, ) { let alpha = surface.alpha(); + let cd = self.state.color_manager.srgb_srgb(); if let Some(tex) = buffer.buffer.get_texture(surface) { let mut opaque = surface.opaque(); if !opaque && tex.format().has_alpha { @@ -441,6 +463,7 @@ impl Renderer<'_> { AcquireSync::Unnecessary, buffer.release_sync, opaque, + cd, ); } else if let Some(color) = &buffer.buffer.color { if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) { @@ -450,14 +473,15 @@ impl Renderer<'_> { }; if !rect.is_empty() { let color = Color::from_u32_premultiplied( - TransferFunction::Srgb, + cd.transfer_function, color[0], color[1], color[2], color[3], ); self.base.ops.push(GfxApiOpt::Sync); - self.base.fill_scaled_boxes(&[rect], &color, alpha); + self.base + .fill_scaled_boxes(&[rect], &color, alpha, &cd.linear); } } } else { @@ -489,12 +513,14 @@ impl Renderer<'_> { Rect::new_sized(x + pos.width() - bw, y + bw, bw, pos.height() - bw).unwrap(), Rect::new_sized(x + bw, y + pos.height() - bw, pos.width() - 2 * bw, bw).unwrap(), ]; - self.base.fill_boxes(&borders, &bc); + let srgb_srgb = self.state.color_manager.srgb_srgb(); + let srgb = &srgb_srgb.linear; + self.base.fill_boxes(&borders, &bc, srgb); let title = [Rect::new_sized(x + bw, y + bw, pos.width() - 2 * bw, th).unwrap()]; - self.base.fill_boxes(&title, &tc); + self.base.fill_boxes(&title, &tc, srgb); let title_underline = [Rect::new_sized(x + bw, y + bw + th, pos.width() - 2 * bw, 1).unwrap()]; - self.base.fill_boxes(&title_underline, &uc); + self.base.fill_boxes(&title_underline, &uc, srgb); if let Some(title) = floating.title_textures.borrow().get(&self.base.scale) { if let Some(texture) = title.texture() { let rect = floating.title_rect.get().move_(x, y); @@ -513,6 +539,7 @@ impl Renderer<'_> { AcquireSync::None, ReleaseSync::None, false, + srgb_srgb, ); } } diff --git a/src/renderer/renderer_base.rs b/src/renderer/renderer_base.rs index b5413b87..f245a6a8 100644 --- a/src/renderer/renderer_base.rs +++ b/src/renderer/renderer_base.rs @@ -1,5 +1,6 @@ use { crate::{ + cmm::cmm_description::{ColorDescription, LinearColorDescription}, gfx_api::{ AcquireSync, BufferResv, CopyTexture, FillRect, FramebufferRect, GfxApiOpt, GfxTexture, ReleaseSync, SampleRect, @@ -64,16 +65,29 @@ impl RendererBase<'_> { rect } - pub fn fill_scaled_boxes(&mut self, boxes: &[Rect], color: &Color, alpha: Option) { - self.fill_boxes3(boxes, color, alpha, 0, 0, true); + pub fn fill_scaled_boxes( + &mut self, + boxes: &[Rect], + color: &Color, + alpha: Option, + cd: &Rc, + ) { + self.fill_boxes3(boxes, color, alpha, cd, 0, 0, true); } - pub fn fill_boxes(&mut self, boxes: &[Rect], color: &Color) { - self.fill_boxes3(boxes, color, None, 0, 0, false); + pub fn fill_boxes(&mut self, boxes: &[Rect], color: &Color, cd: &Rc) { + self.fill_boxes3(boxes, color, None, cd, 0, 0, false); } - pub fn fill_boxes2(&mut self, boxes: &[Rect], color: &Color, dx: i32, dy: i32) { - self.fill_boxes3(boxes, color, None, dx, dy, false); + pub fn fill_boxes2( + &mut self, + boxes: &[Rect], + color: &Color, + cd: &Rc, + dx: i32, + dy: i32, + ) { + self.fill_boxes3(boxes, color, None, cd, dx, dy, false); } pub fn fill_boxes3( @@ -81,6 +95,7 @@ impl RendererBase<'_> { boxes: &[Rect], color: &Color, alpha: Option, + cd: &Rc, dx: i32, dy: i32, scaled: bool, @@ -106,18 +121,25 @@ impl RendererBase<'_> { ), color: *color, alpha, + cd: cd.clone(), })); } } - pub fn fill_boxes_f(&mut self, boxes: &[(f32, f32, f32, f32)], color: &Color) { - self.fill_boxes2_f(boxes, color, 0.0, 0.0); + pub fn fill_boxes_f( + &mut self, + boxes: &[(f32, f32, f32, f32)], + color: &Color, + cd: &Rc, + ) { + self.fill_boxes2_f(boxes, color, cd, 0.0, 0.0); } pub fn fill_boxes2_f( &mut self, boxes: &[(f32, f32, f32, f32)], color: &Color, + cd: &Rc, dx: f32, dy: f32, ) { @@ -139,6 +161,7 @@ impl RendererBase<'_> { ), color: *color, alpha: None, + cd: cd.clone(), })); } } @@ -157,6 +180,7 @@ impl RendererBase<'_> { acquire_sync: AcquireSync, release_sync: ReleaseSync, opaque: bool, + cd: &Rc, ) { let mut texcoord = tpoints.unwrap_or_else(SampleRect::identity); @@ -200,6 +224,7 @@ impl RendererBase<'_> { acquire_sync, release_sync, opaque, + cd: cd.clone(), })); } } diff --git a/src/screenshoter.rs b/src/screenshoter.rs index 657551d4..b89356c1 100644 --- a/src/screenshoter.rs +++ b/src/screenshoter.rs @@ -79,6 +79,7 @@ pub fn take_screenshot( fb.render_node( AcquireSync::Unnecessary, ReleaseSync::Implicit, + state.color_manager.srgb_srgb(), state.root.deref(), state, Some(state.root.extents.get()), @@ -89,6 +90,7 @@ pub fn take_screenshot( false, Transform::None, None, + state.color_manager.srgb_linear(), )?; let drm = match allocator.drm() { Some(drm) => Some(drm.dup_render()?.fd().clone()), diff --git a/src/state.rs b/src/state.rs index cb136dc6..703d8f7a 100644 --- a/src/state.rs +++ b/src/state.rs @@ -11,7 +11,7 @@ use { cli::RunArgs, client::{Client, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange}, clientmem::ClientMemOffset, - cmm::cmm_manager::ColorManager, + cmm::{cmm_description::ColorDescription, cmm_manager::ColorManager}, compositor::LIBEI_SOCKET, config::ConfigProxy, cpu_worker::CpuWorker, @@ -235,7 +235,6 @@ pub struct State { pub data_control_device_ids: DataControlDeviceIds, pub workspace_managers: WorkspaceManagerState, pub color_management_enabled: Cell, - #[expect(dead_code)] pub color_manager: Rc, } @@ -979,15 +978,18 @@ impl State { &self, output: &OutputNode, fb: &Rc, + cd: &Rc, acquire_sync: AcquireSync, release_sync: ReleaseSync, tex: &Rc, render_hw_cursor: bool, blend_buffer: Option<&Rc>, + blend_cd: &Rc, ) -> Result, GfxError> { let sync_file = fb.render_output( acquire_sync, release_sync, + cd, output, self, Some(output.global.pos.get()), @@ -995,10 +997,12 @@ impl State { render_hw_cursor, true, blend_buffer, + blend_cd, )?; output.latched(false); output.perform_screencopies( tex, + cd, None, &AcquireSync::Unnecessary, ReleaseSync::None, @@ -1016,10 +1020,12 @@ impl State { resv: Option<&Rc>, acquire_sync: &AcquireSync, release_sync: ReleaseSync, + src_cd: &Rc, target: &Rc, target_acquire_sync: AcquireSync, target_release_sync: ReleaseSync, target_transform: Transform, + target_cd: &Rc, position: Rect, render_hardware_cursors: bool, x_off: i32, @@ -1053,6 +1059,7 @@ impl State { acquire_sync.clone(), release_sync, false, + src_cd, ); if render_hardware_cursors { if let Some(cursor_user_group) = self.cursor_user_group_hardware_cursor.get() { @@ -1069,15 +1076,19 @@ impl State { target.render( target_acquire_sync, target_release_sync, + target_cd, &ops, Some(&Color::SOLID_BLACK), + &target_cd.linear, None, + target_cd, ) } pub fn perform_shm_screencopy( &self, src: &Rc, + src_cd: &Rc, acquire_sync: &AcquireSync, position: Rect, x_off: i32, @@ -1108,10 +1119,12 @@ impl State { None, acquire_sync, ReleaseSync::None, + src_cd, &fb.clone().into_fb(), AcquireSync::Unnecessary, ReleaseSync::None, transform, + self.color_manager.srgb_srgb(), position, true, x_off - capture.rect.x1(), diff --git a/src/tree/output.rs b/src/tree/output.rs index 44fceb82..2d291819 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -2,6 +2,7 @@ use { crate::{ backend::{HardwareCursor, KeyState, Mode}, client::ClientId, + cmm::cmm_description::ColorDescription, cursor::KnownCursor, fixed::Fixed, gfx_api::{AcquireSync, BufferResv, GfxTexture, ReleaseSync}, @@ -252,6 +253,7 @@ impl OutputNode { pub fn perform_screencopies( &self, tex: &Rc, + cd: &Rc, resv: Option<&Rc>, acquire_sync: &AcquireSync, release_sync: ReleaseSync, @@ -267,6 +269,7 @@ impl OutputNode { } self.perform_wlr_screencopies( tex, + cd, resv, acquire_sync, release_sync, @@ -279,6 +282,7 @@ impl OutputNode { sc.copy_texture( self, tex, + cd, resv, acquire_sync, release_sync, @@ -292,6 +296,7 @@ impl OutputNode { sc.copy_texture( self, tex, + cd, resv, acquire_sync, release_sync, @@ -306,6 +311,7 @@ impl OutputNode { pub fn perform_wlr_screencopies( &self, tex: &Rc, + cd: &Rc, resv: Option<&Rc>, acquire_sync: &AcquireSync, release_sync: ReleaseSync, @@ -337,6 +343,7 @@ impl OutputNode { WlBufferStorage::Shm { mem, stride } => { let res = self.state.perform_shm_screencopy( tex, + cd, acquire_sync, self.global.pos.get(), x_off, @@ -375,10 +382,12 @@ impl OutputNode { resv, acquire_sync, release_sync, + cd, &fb, AcquireSync::Implicit, ReleaseSync::Implicit, self.global.persistent.transform.get(), + self.state.color_manager.srgb_srgb(), self.global.pos.get(), render_hardware_cursors, x_off - capture.rect.x1(),