diff --git a/crates/gpui_macos/src/display_colorspace.rs b/crates/gpui_macos/src/display_colorspace.rs new file mode 100644 index 0000000000..45ff69ebd1 --- /dev/null +++ b/crates/gpui_macos/src/display_colorspace.rs @@ -0,0 +1,39 @@ +// GPUI macOS platform - GPUI is licensed under the Apache License, Version 2.0 +// (see the gpui submodule's license). + +//! The main display's colorspace as a raw `CGColorSpaceRef`, for the +//! color-management coordination in `metal_renderer` (when the app +//! self-manages the display transform, the CAMetalLayer is tagged with the +//! display's colorspace so ColorSync passes the pixels through). +//! +//! This lives in its own module because the `metal_renderer` build script +//! scans `metal_renderer.rs` for FFI declarations and forwards them into +//! the Metal shader header — raw extern blocks must not be added there. + +use std::ffi::c_void; + +#[link(name = "CoreGraphics", kind = "framework")] +unsafe extern "C" { + fn CGMainDisplayID() -> u32; + fn CGDisplayCopyColorSpace(display: u32) -> *mut c_void; +} + +#[link(name = "CoreFoundation", kind = "framework")] +unsafe extern "C" { + fn CFRelease(obj: *const c_void); +} + +/// The main display's colorspace as a raw pointer (caller's +/// responsibility to keep it alive for the msg_send call; released here +/// after the layer call returns — the layer retains it). `None` when the +/// display has no colorspace (headless). +pub fn with_main_display_colorspace(f: impl FnOnce(*mut c_void)) { + unsafe { + let space = CGDisplayCopyColorSpace(CGMainDisplayID()); + if space.is_null() { + return; + } + f(space); + CFRelease(space); + } +} diff --git a/crates/gpui_macos/src/gpui_macos.rs b/crates/gpui_macos/src/gpui_macos.rs index ebe1fd3439..a8c47cd985 100644 --- a/crates/gpui_macos/src/gpui_macos.rs +++ b/crates/gpui_macos/src/gpui_macos.rs @@ -6,6 +6,7 @@ mod dispatcher; mod display; +mod display_colorspace; mod display_link; mod events; mod haptic_feedback; diff --git a/crates/gpui_macos/src/metal_renderer.rs b/crates/gpui_macos/src/metal_renderer.rs index 249b33b88c..59ff75da9c 100644 --- a/crates/gpui_macos/src/metal_renderer.rs +++ b/crates/gpui_macos/src/metal_renderer.rs @@ -251,6 +251,20 @@ impl MetalRenderer { ]; } + // Color management coordination: when the app self-manages the + // display transform (OAK_MACOS_LAYER_COLORSPACE=display, set at + // startup when display-ICC color management is active), tag the + // layer with the DISPLAY's colorspace so ColorSync's mapping + // becomes a pass-through — otherwise the OS would re-correct our + // already-corrected pixels (double correction). + if std::env::var_os("OAK_MACOS_LAYER_COLORSPACE").as_deref() + == Some(std::ffi::OsStr::new("display")) + { + crate::display_colorspace::with_main_display_colorspace(|space| unsafe { + let _: () = msg_send![&*layer, setColorspace: space]; + }); + } + Self::new_internal(device, Some(layer), !transparent, instance_buffer_pool) }