From eee3384e20cf8187b7a1ebd8746f5eb32de08290 Mon Sep 17 00:00:00 2001 From: ArchercatNEO Date: Mon, 17 Feb 2025 19:05:58 +0000 Subject: [PATCH] HDR output for linuxbsd (wayland) --- doc/classes/DisplayServer.xml | 2 +- .../vulkan/rendering_context_driver_vulkan.h | 1 + .../vulkan/rendering_device_driver_vulkan.cpp | 50 +- .../vulkan/rendering_device_driver_vulkan.h | 3 +- platform/linuxbsd/wayland/SCsub | 3 + .../wayland/display_server_wayland.cpp | 160 +- .../linuxbsd/wayland/display_server_wayland.h | 21 + .../rendering_context_driver_vulkan_wayland.h | 3 + platform/linuxbsd/wayland/wayland_embedder.h | 11 + platform/linuxbsd/wayland/wayland_thread.cpp | 243 +++ platform/linuxbsd/wayland/wayland_thread.h | 98 + thirdparty/README.md | 4 +- .../staging/color-management/README | 11 + .../color-management/color-management-v1.xml | 1724 +++++++++++++++++ 14 files changed, 2310 insertions(+), 24 deletions(-) create mode 100644 thirdparty/wayland-protocols/staging/color-management/README create mode 100644 thirdparty/wayland-protocols/staging/color-management/color-management-v1.xml diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 6fb91f82b6bb..f22053fde6c3 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -2751,7 +2751,7 @@ Display server supports interaction with screen reader or Braille display. [b]Linux (X11/Wayland), macOS, Windows[/b] - Display server supports HDR output. [b]macOS, iOS, visionOS, Windows[/b] + Display server supports HDR output. [b]Linux (Wayland), macOS, iOS, visionOS, Windows[/b] Unknown or custom role. diff --git a/drivers/vulkan/rendering_context_driver_vulkan.h b/drivers/vulkan/rendering_context_driver_vulkan.h index a3c74b3bec8d..1649013c7820 100644 --- a/drivers/vulkan/rendering_context_driver_vulkan.h +++ b/drivers/vulkan/rendering_context_driver_vulkan.h @@ -155,6 +155,7 @@ class RenderingContextDriverVulkan : public RenderingContextDriver { virtual bool surface_get_needs_resize(SurfaceID p_surface) const override; virtual void surface_destroy(SurfaceID p_surface) override; virtual bool is_debug_utils_enabled() const override; + virtual bool is_colorspace_externally_managed() const { return false; } bool is_colorspace_supported() const; // Vulkan-only methods. diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index 6d92216bc622..c9a69efb3e57 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -3427,9 +3427,10 @@ void RenderingDeviceDriverVulkan::command_buffer_execute_secondary(CommandBuffer struct FormatCandidate { VkFormat format; VkColorSpaceKHR colorspace; + RDD::ColorSpace rdd_colorspace; }; -bool RenderingDeviceDriverVulkan::_determine_swap_chain_format(RenderingContextDriver::SurfaceID p_surface, VkFormat &r_format, VkColorSpaceKHR &r_color_space) { +bool RenderingDeviceDriverVulkan::_determine_swap_chain_format(RenderingContextDriver::SurfaceID p_surface, VkFormat &r_format, VkColorSpaceKHR &r_color_space, RDD::ColorSpace &r_rdd_color_space) { DEV_ASSERT(p_surface != 0); RenderingContextDriverVulkan::Surface *surface = (RenderingContextDriverVulkan::Surface *)(p_surface); @@ -3456,17 +3457,31 @@ bool RenderingDeviceDriverVulkan::_determine_swap_chain_format(RenderingContextD bool hdr_output_requested = context_driver->surface_get_hdr_output_enabled(p_surface); // Determine which formats to prefer based on the requested capabilities. - FixedVector preferred_formats; + FixedVector preferred_formats; + if (hdr_output_requested) { + // Our preferred HDR format is 16-bit float + extended linear. + if (context_driver->is_colorspace_externally_managed()) { + // When the colorspace is managed externally to the driver we need to disable its color management. + // The colorspace which disables color management is VK_COLOR_SPACE_PASS_THROUGH_EXT. + preferred_formats.push_back({ VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_PASS_THROUGH_EXT, COLOR_SPACE_REC709_LINEAR }); + + // SRGB_NONLINEAR_KHR is required for some NVIDIA drivers that support HDR output but do not support PASS_THROUGH_EXT. + preferred_formats.push_back({ VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, COLOR_SPACE_REC709_LINEAR }); + } else if (colorspace_supported) { + preferred_formats.push_back({ VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT, COLOR_SPACE_REC709_LINEAR }); + } + } - // If the surface requests HDR output, try to get an HDR format. - if (hdr_output_requested && colorspace_supported) { - // This format is preferred for HDR output. - preferred_formats.push_back({ VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT }); + // Some drivers may use wp-color-management even when performing SDR. + // https://github.com/godotengine/godot/pull/102987#discussion_r2913373482 + if (context_driver->is_colorspace_externally_managed()) { + preferred_formats.push_back({ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT, COLOR_SPACE_REC709_NONLINEAR_SRGB }); + preferred_formats.push_back({ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT, COLOR_SPACE_REC709_NONLINEAR_SRGB }); } // These formats are always considered for SDR. - preferred_formats.push_back({ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }); - preferred_formats.push_back({ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }); + preferred_formats.push_back({ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, COLOR_SPACE_REC709_NONLINEAR_SRGB }); + preferred_formats.push_back({ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, COLOR_SPACE_REC709_NONLINEAR_SRGB }); bool found = false; for (const FormatCandidate &candidate : preferred_formats) { @@ -3474,6 +3489,7 @@ bool RenderingDeviceDriverVulkan::_determine_swap_chain_format(RenderingContextD if (formats[i].format == candidate.format && formats[i].colorSpace == candidate.colorspace) { r_format = formats[i].format; r_color_space = formats[i].colorSpace; + r_rdd_color_space = candidate.rdd_colorspace; found = true; break; } @@ -3486,11 +3502,11 @@ bool RenderingDeviceDriverVulkan::_determine_swap_chain_format(RenderingContextD // Warnings for when HDR capabilities are requested but not found. if (hdr_output_requested) { - if (!colorspace_supported) { + if (!colorspace_supported && !context_driver->is_colorspace_externally_managed()) { WARN_PRINT("HDR output requested but the vulkan driver does not support VK_EXT_swapchain_colorspace, falling back to SDR."); } - if (r_color_space == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + if (r_rdd_color_space == COLOR_SPACE_REC709_NONLINEAR_SRGB) { WARN_PRINT("HDR output requested but no HDR compatible format was found, falling back to SDR."); } } @@ -3687,11 +3703,13 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, // Determine the format and color space for the swap chain. VkFormat format = VK_FORMAT_UNDEFINED; VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - if (!_determine_swap_chain_format(swap_chain->surface, format, color_space)) { + RDD::ColorSpace rdd_color_space = COLOR_SPACE_REC709_NONLINEAR_SRGB; + if (!_determine_swap_chain_format(swap_chain->surface, format, color_space, rdd_color_space)) { ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Surface did not return any valid formats."); } else { swap_chain->format = format; swap_chain->color_space = color_space; + swap_chain->rdd_color_space = rdd_color_space; } VkSwapchainCreateInfoKHR swap_create_info = {}; @@ -3973,15 +3991,7 @@ RDD::ColorSpace RenderingDeviceDriverVulkan::swap_chain_get_color_space(SwapChai DEV_ASSERT(p_swap_chain.id != 0); SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); - switch (swap_chain->color_space) { - case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: - return COLOR_SPACE_REC709_NONLINEAR_SRGB; - case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT: - return COLOR_SPACE_REC709_LINEAR; - default: - DEV_ASSERT(false && "Unknown swap chain color space."); - return COLOR_SPACE_MAX; - } + return swap_chain->rdd_color_space; } void RenderingDeviceDriverVulkan::swap_chain_set_max_fps(SwapChainID p_swap_chain, int p_max_fps) { diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 3b07d68180ba..d18919db6825 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -418,6 +418,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { RenderingContextDriver::SurfaceID surface = RenderingContextDriver::SurfaceID(); VkFormat format = VK_FORMAT_UNDEFINED; VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + RDD::ColorSpace rdd_color_space = RDD::COLOR_SPACE_REC709_NONLINEAR_SRGB; TightLocalVector images; TightLocalVector image_views; TightLocalVector present_semaphores; @@ -432,7 +433,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { #endif }; - bool _determine_swap_chain_format(RenderingContextDriver::SurfaceID p_surface, VkFormat &r_format, VkColorSpaceKHR &r_color_space); + bool _determine_swap_chain_format(RenderingContextDriver::SurfaceID p_surface, VkFormat &r_format, VkColorSpaceKHR &r_color_space, RDD::ColorSpace &r_rdd_color_space); void _swap_chain_release(SwapChain *p_swap_chain); public: diff --git a/platform/linuxbsd/wayland/SCsub b/platform/linuxbsd/wayland/SCsub index 042bc779edf9..e8531a176333 100644 --- a/platform/linuxbsd/wayland/SCsub +++ b/platform/linuxbsd/wayland/SCsub @@ -58,6 +58,9 @@ generated_sources = [ generate_from_xml("viewporter", "#thirdparty/wayland-protocols/stable/viewporter/viewporter.xml"), generate_from_xml("xdg_shell", "#thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml"), # Staging protocols + generate_from_xml( + "color_management", "#thirdparty/wayland-protocols/staging/color-management/color-management-v1.xml" + ), generate_from_xml("cursor_shape", "#thirdparty/wayland-protocols/staging/cursor-shape/cursor-shape-v1.xml"), generate_from_xml( "fractional_scale", "#thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml" diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 491387173775..7e979cc862d8 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -213,7 +213,8 @@ bool DisplayServerWayland::has_feature(DisplayServerEnums::Feature p_feature) co case DisplayServerEnums::FEATURE_CLIPBOARD_PRIMARY: case DisplayServerEnums::FEATURE_SUBWINDOWS: case DisplayServerEnums::FEATURE_WINDOW_EMBEDDING: - case DisplayServerEnums::FEATURE_SELF_FITTING_WINDOWS: { + case DisplayServerEnums::FEATURE_SELF_FITTING_WINDOWS: + case DisplayServerEnums::FEATURE_HDR_OUTPUT: { return true; } break; @@ -1461,6 +1462,125 @@ void DisplayServerWayland::window_start_resize(DisplayServerEnums::WindowResizeE wayland_thread.window_start_resize(p_edge, p_window); } +void DisplayServerWayland::_window_update_hdr_state(WindowData &p_window) { + DisplayServerEnums::WindowID window_id = p_window.id; + +#if defined(RD_ENABLED) + if (rendering_context) { + // The `display/window/hdr/request_hdr_output` project setting makes the main window "request" HDR. + // On Windows, this means enable HDR for the main window if it is on an HDR screen. + // Since all screens support HDR on Wayland, we use whether the window "prefers" HDR or not instead. + bool hdr_preferred = p_window.color_profile.target_max_luminance > p_window.color_profile.reference_luminance; + bool hdr_desired = wayland_thread.supports_hdr() && hdr_preferred && p_window.hdr_requested; + + if (rendering_context->window_get_hdr_output_enabled(window_id) != hdr_desired) { + rendering_context->window_set_hdr_output_enabled(window_id, hdr_desired); + } + + if (hdr_desired) { + rendering_context->window_set_hdr_output_max_luminance(window_id, p_window.color_profile.target_max_luminance); + rendering_context->window_set_hdr_output_reference_luminance(window_id, p_window.color_profile.reference_luminance); + rendering_context->window_set_hdr_output_linear_luminance_scale(window_id, p_window.color_profile.target_max_luminance); + + p_window.color_profile.named_primary = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB; + p_window.color_profile.named_transfer_function = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR; + } else { + p_window.color_profile.named_primary = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB; + p_window.color_profile.named_transfer_function = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22; + } + + if (p_window.visible) { + MutexLock mutex_lock(wayland_thread.mutex); + wayland_thread.window_set_color_profile(window_id, p_window.color_profile); + } + } +#endif +} + +bool DisplayServerWayland::window_is_hdr_output_supported(DisplayServerEnums::WindowID p_window_id) const { + ERR_FAIL_COND_V(!windows.has(p_window_id), false); + const WindowData &wd = windows[p_window_id]; + + return wd.color_profile.target_max_luminance > wd.color_profile.reference_luminance; +} + +void DisplayServerWayland::window_request_hdr_output(const bool p_enabled, DisplayServerEnums::WindowID p_window_id) { +#if defined(RD_ENABLED) + ERR_FAIL_COND_MSG(!(rendering_device && rendering_device->has_feature(RenderingDevice::Features::SUPPORTS_HDR_OUTPUT)), "HDR output is not supported by the rendering device."); +#endif + + ERR_FAIL_COND(!windows.has(p_window_id)); + WindowData &wd = windows[p_window_id]; + wd.hdr_requested = p_enabled; + + _window_update_hdr_state(wd); +} + +bool DisplayServerWayland::window_is_hdr_output_requested(DisplayServerEnums::WindowID p_window_id) const { + ERR_FAIL_COND_V(!windows.has(p_window_id), false); + const WindowData &wd = windows[p_window_id]; + return wd.hdr_requested; +} + +bool DisplayServerWayland::window_is_hdr_output_enabled(DisplayServerEnums::WindowID p_window_id) const { +#if defined(RD_ENABLED) + if (rendering_context) { + return rendering_context->window_get_hdr_output_enabled(p_window_id); + } +#endif + return false; +} + +void DisplayServerWayland::window_set_hdr_output_reference_luminance(const float p_reference_luminance, DisplayServerEnums::WindowID p_window_id) { + ERR_FAIL_COND(!windows.has(p_window_id)); + if (p_reference_luminance >= 0.0f) { + ERR_PRINT_ONCE("Manually setting reference white luminance is not supported on Linux devices, as they provide a user-facing brightness setting that directly controls reference white luminance."); + } +} + +float DisplayServerWayland::window_get_hdr_output_reference_luminance(DisplayServerEnums::WindowID p_window_id) const { + return -1.0; +} + +float DisplayServerWayland::window_get_hdr_output_current_reference_luminance(DisplayServerEnums::WindowID p_window_id) const { +#if defined(RD_ENABLED) + if (rendering_context) { + return rendering_context->window_get_hdr_output_reference_luminance(p_window_id); + } +#endif + return 0.0f; +} + +void DisplayServerWayland::window_set_hdr_output_max_luminance(const float p_max_luminance, DisplayServerEnums::WindowID p_window_id) { + ERR_FAIL_COND(!windows.has(p_window_id)); + if (p_max_luminance >= 0.0f) { + ERR_PRINT_ONCE("Manually setting max luminance is not supported on Linux devices as they provide a built-in method of calibrating max luminance without the need for additional apps or tools."); + } +} + +float DisplayServerWayland::window_get_hdr_output_max_luminance(DisplayServerEnums::WindowID p_window_id) const { + return -1.0; +} + +float DisplayServerWayland::window_get_hdr_output_current_max_luminance(DisplayServerEnums::WindowID p_window_id) const { +#if defined(RD_ENABLED) + if (rendering_context) { + return rendering_context->window_get_hdr_output_max_luminance(p_window_id); + } +#endif + return 0.0f; +} + +float DisplayServerWayland::window_get_output_max_linear_value(DisplayServerEnums::WindowID p_window_id) const { +#if defined(RD_ENABLED) + if (rendering_context) { + return rendering_context->window_get_output_max_linear_value(p_window_id); + } +#endif + + return 1.0f; +} + void DisplayServerWayland::cursor_set_shape(DisplayServerEnums::CursorShape p_shape) { ERR_FAIL_INDEX(p_shape, DisplayServerEnums::CURSOR_MAX); @@ -1715,6 +1835,35 @@ void DisplayServerWayland::process_events() { wayland_thread.keyboard_echo_keys(); +#if defined(RD_ENABLED) + // Enabling HDR may have failed, in which case we need to clear the color profile. + // NOTE: this happens _before_ reading events because the rendering driver is only updated the frame _after_ we try to enable HDR. + if (rendering_device && (!OS::get_singleton()->is_in_low_processor_usage_mode() || RS::get_singleton()->has_changed())) { + for (KeyValue &pair : windows) { + const RD::ColorSpace color_space = rendering_device->screen_get_color_space(pair.key); + + bool dirty_srgb = color_space == RDD::COLOR_SPACE_REC709_NONLINEAR_SRGB && pair.value.color_profile.named_transfer_function != WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22; + bool dirty_linear = color_space == RDD::COLOR_SPACE_REC709_LINEAR && pair.value.color_profile.named_transfer_function != WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR; + + if (dirty_srgb) { + pair.value.color_profile.named_primary = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB; + pair.value.color_profile.named_transfer_function = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22; + + if (pair.value.visible) { + wayland_thread.window_set_color_profile(pair.key, pair.value.color_profile); + } + } else if (dirty_linear) { + pair.value.color_profile.named_primary = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB; + pair.value.color_profile.named_transfer_function = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR; + + if (pair.value.visible) { + wayland_thread.window_set_color_profile(pair.key, pair.value.color_profile); + } + } + } + } +#endif + while (wayland_thread.has_message()) { Ref msg = wayland_thread.pop_message(); @@ -1846,6 +1995,15 @@ void DisplayServerWayland::process_events() { } continue; } + + Ref color_profile_msg = msg; + if (color_profile_msg.is_valid()) { + WindowData &wd = windows[color_profile_msg->id]; + wd.color_profile = color_profile_msg->color_profile; + + _window_update_hdr_state(wd); + continue; + } } switch (suspend_state) { diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h index d2f63d7c5982..b669e07990b7 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.h +++ b/platform/linuxbsd/wayland/display_server_wayland.h @@ -94,6 +94,9 @@ class DisplayServerWayland : public DisplayServer { DisplayServerEnums::WindowMode mode = DisplayServerEnums::WINDOW_MODE_WINDOWED; + bool hdr_requested = false; + WaylandThread::ColorProfile color_profile; + Callable rect_changed_callback; Callable window_event_callback; Callable input_event_callback; @@ -176,6 +179,8 @@ class DisplayServerWayland : public DisplayServer { void _update_window_rect(const Rect2i &p_rect, DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID); + void _window_update_hdr_state(WindowData &p_window); + void try_suspend(); void initialize_tts() const; @@ -317,6 +322,22 @@ class DisplayServerWayland : public DisplayServer { virtual void window_start_drag(DisplayServerEnums::WindowID p_window = DisplayServerEnums::MAIN_WINDOW_ID) override; virtual void window_start_resize(DisplayServerEnums::WindowResizeEdge p_edge, DisplayServerEnums::WindowID p_window) override; + virtual bool window_is_hdr_output_supported(DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) const override; + + virtual void window_request_hdr_output(const bool p_enabled, DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) override; + virtual bool window_is_hdr_output_requested(DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) const override; + virtual bool window_is_hdr_output_enabled(DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) const override; + + virtual void window_set_hdr_output_reference_luminance(const float p_reference_luminance, DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) override; + virtual float window_get_hdr_output_reference_luminance(DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) const override; + virtual float window_get_hdr_output_current_reference_luminance(DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) const override; + + virtual void window_set_hdr_output_max_luminance(const float p_max_luminance, DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) override; + virtual float window_get_hdr_output_max_luminance(DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) const override; + virtual float window_get_hdr_output_current_max_luminance(DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) const override; + + virtual float window_get_output_max_linear_value(DisplayServerEnums::WindowID p_window_id = DisplayServerEnums::MAIN_WINDOW_ID) const override; + virtual void cursor_set_shape(DisplayServerEnums::CursorShape p_shape) override; virtual DisplayServerEnums::CursorShape cursor_get_shape() const override; virtual void cursor_set_custom_image(const Ref &p_cursor, DisplayServerEnums::CursorShape p_shape, const Vector2 &p_hotspot) override; diff --git a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h index 0515471eb92e..9b9e72e4ef4a 100644 --- a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h +++ b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h @@ -37,6 +37,9 @@ class RenderingContextDriverVulkanWayland : public RenderingContextDriverVulkan { private: virtual const char *_get_platform_surface_extension() const override final; + // If wp-color-management is supported, we will perform color management externally to the driver. + // If wp-color-management is not supported, the driver would not be able to perform color management anyway. + virtual bool is_colorspace_externally_managed() const override final { return true; } protected: SurfaceID surface_create(const void *p_platform_data) override final; diff --git a/platform/linuxbsd/wayland/wayland_embedder.h b/platform/linuxbsd/wayland/wayland_embedder.h index 5fc3da0e2833..8a306a932e92 100644 --- a/platform/linuxbsd/wayland/wayland_embedder.h +++ b/platform/linuxbsd/wayland/wayland_embedder.h @@ -48,6 +48,7 @@ #include "protocol/linux_dmabuf_v1.gen.h" #include "protocol/xdg_shell.gen.h" +#include "protocol/color_management.gen.h" #include "protocol/commit_timing_v1.gen.h" #include "protocol/cursor_shape.gen.h" #include "protocol/fifo_v1.gen.h" @@ -347,6 +348,16 @@ class WaylandEmbedder { &zwp_linux_surface_synchronization_v1_interface, &zwp_linux_buffer_release_v1_interface, + // color-management + &wp_color_manager_v1_interface, + &wp_color_management_output_v1_interface, + &wp_color_management_surface_v1_interface, + &wp_color_management_surface_feedback_v1_interface, + &wp_image_description_creator_icc_v1_interface, + &wp_image_description_creator_params_v1_interface, + &wp_image_description_v1_interface, + &wp_image_description_info_v1_interface, + // fractional-scale &wp_fractional_scale_manager_v1_interface, &wp_fractional_scale_v1_interface, diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index c8e98639f530..44fecb7945cc 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -618,6 +618,16 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re registry->wp_viewporter_name = name; } + if (strcmp(interface, wp_color_manager_v1_interface.name) == 0) { + registry->wp_color_manager = (struct wp_color_manager_v1 *)wl_registry_bind(wl_registry, name, &wp_color_manager_v1_interface, 1); + registry->wp_color_manager_name = name; + wl_proxy_tag_godot((struct wl_proxy *)registry->wp_color_manager); + + WaylandThread::ColorManagementState *color_state = memnew(WaylandThread::ColorManagementState); + wp_color_manager_v1_add_listener(registry->wp_color_manager, &wp_color_manager_listener, color_state); + return; + } + if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { registry->wp_cursor_shape_manager = (struct wp_cursor_shape_manager_v1 *)wl_registry_bind(wl_registry, name, &wp_cursor_shape_manager_v1_interface, 1); registry->wp_cursor_shape_manager_name = name; @@ -849,6 +859,32 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry return; } + if (name == registry->wp_color_manager_name) { + for (KeyValue &pair : registry->wayland_thread->windows) { + WindowState ws = pair.value; + + if (ws.wp_color_management_surface) { + wp_color_management_surface_v1_destroy(ws.wp_color_management_surface); + ws.wp_color_management_surface = nullptr; + } + + if (ws.wp_color_management_surface_feedback) { + wp_color_management_surface_feedback_v1_destroy(ws.wp_color_management_surface_feedback); + ws.wp_color_management_surface_feedback = nullptr; + } + } + + if (registry->wp_color_manager) { + ColorManagementState *color_state = wp_color_manager_get_state(registry->wp_color_manager); + memdelete(color_state); + + wp_color_manager_v1_destroy(registry->wp_color_manager); + registry->wp_color_manager = nullptr; + } + + registry->wp_color_manager_name = 0; + } + if (name == registry->wp_cursor_shape_manager_name) { if (registry->wp_cursor_shape_manager) { wp_cursor_shape_manager_v1_destroy(registry->wp_cursor_shape_manager); @@ -2567,6 +2603,139 @@ void WaylandThread::_wl_data_source_on_dnd_finished(void *data, struct wl_data_s void WaylandThread::_wl_data_source_on_action(void *data, struct wl_data_source *wl_data_source, uint32_t dnd_action) { } +void WaylandThread::_wp_color_manager_on_supported_intent(void *data, struct wp_color_manager_v1 *wp_color_manager_v1, uint32_t render_intent) { + ColorManagementState *cms = (ColorManagementState *)data; + ERR_FAIL_NULL(cms); + + cms->supported_render_intents |= 1 << render_intent; +} + +void WaylandThread::_wp_color_manager_on_supported_feature(void *data, struct wp_color_manager_v1 *wp_color_manager_v1, uint32_t feature) { + ColorManagementState *cms = (ColorManagementState *)data; + ERR_FAIL_NULL(cms); + + cms->supported_render_feature |= 1 << feature; +} + +void WaylandThread::_wp_color_manager_on_supported_tf_named(void *data, struct wp_color_manager_v1 *wp_color_manager_v1, uint32_t tf) { + ColorManagementState *cms = (ColorManagementState *)data; + ERR_FAIL_NULL(cms); + + cms->supported_transfer_function |= 1 << tf; +} + +void WaylandThread::_wp_color_manager_on_supported_primaries_named(void *data, struct wp_color_manager_v1 *wp_color_manager_v1, uint32_t primaries) { + ColorManagementState *cms = (ColorManagementState *)data; + ERR_FAIL_NULL(cms); + + cms->supported_primaries |= 1 << primaries; +} + +void WaylandThread::_wp_color_manager_on_done(void *data, struct wp_color_manager_v1 *wp_color_manager_v1) { + ColorManagementState *cms = (ColorManagementState *)data; + ERR_FAIL_NULL(cms); + + // We require parametric profiles until we can support reading ICC files. + if ((cms->supported_render_feature & (1 << WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC)) == 0) { + return; + } + + // We require the compositor to support extended linear sRGB. + // sRGB primaries support is assumed. + cms->supports_hdr = cms->supported_transfer_function & (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR); +} + +void WaylandThread::_wp_color_management_surface_feedback_on_preferred_changed(void *data, struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1, uint32_t identity) { + _wp_color_management_surface_feedback_on_preferred_changed2(data, wp_color_management_surface_feedback_v1, 0, identity); +} + +void WaylandThread::_wp_color_management_surface_feedback_on_preferred_changed2(void *data, struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1, uint32_t identity_high, uint32_t identity_low) { + struct wp_image_description_v1 *image_description = wp_color_management_surface_feedback_v1_get_preferred_parametric(wp_color_management_surface_feedback_v1); + + wp_image_description_v1_add_listener(image_description, &wp_image_description_listener, data); +} + +void WaylandThread::_wp_image_description_on_failed(void *data, struct wp_image_description_v1 *image_descrptor, uint32_t cause, const char *msg) { + WARN_PRINT(msg); +} + +void WaylandThread::_wp_image_description_on_ready(void *data, struct wp_image_description_v1 *image_descriptor, uint32_t identity) { + _wp_image_description_on_ready2(data, image_descriptor, 0, identity); +} + +void WaylandThread::_wp_image_description_on_ready2(void *data, struct wp_image_description_v1 *image_descriptor, uint32_t identity_high, uint32_t identity_low) { + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + + struct wp_image_description_info_v1 *image_info = wp_image_description_v1_get_information(image_descriptor); + if (image_info != nullptr) { + ColorProfileMessage *msg = memnew(ColorProfileMessage); + msg->id = ws->id; + msg->wayland_thread = ws->wayland_thread; + + wp_image_description_info_v1_add_listener(image_info, &wp_image_description_info_listener, msg); + wp_image_description_v1_destroy(image_descriptor); + } +} + +void WaylandThread::_wp_image_description_info_on_done(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1) { + wp_image_description_info_v1_destroy(wp_image_description_info_v1); + + ColorProfileMessage *msg = (ColorProfileMessage *)data; + ERR_FAIL_NULL(msg); + + msg->wayland_thread->push_message(msg); +} + +void WaylandThread::_wp_image_description_info_on_icc_file(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, int32_t icc, uint32_t icc_size) { + ::close(icc); +} + +void WaylandThread::_wp_image_description_info_on_primaries(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) { +} + +void WaylandThread::_wp_image_description_info_on_primaries_named(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t primaries) { + ColorProfileMessage *msg = (ColorProfileMessage *)data; + ERR_FAIL_NULL(msg); + + msg->color_profile.named_primary = primaries; +} + +void WaylandThread::_wp_image_description_info_on_tf_power(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t eexp) { +} + +void WaylandThread::_wp_image_description_info_on_tf_named(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t tf) { + ColorProfileMessage *msg = (ColorProfileMessage *)data; + ERR_FAIL_NULL(msg); + + msg->color_profile.named_transfer_function = tf; +} + +void WaylandThread::_wp_image_description_info_on_luminances(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum) { + ColorProfileMessage *msg = (ColorProfileMessage *)data; + ERR_FAIL_NULL(msg); + + msg->color_profile.reference_luminance = reference_lum; +} + +void WaylandThread::_wp_image_description_info_on_target_primaries(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) { +} + +void WaylandThread::_wp_image_description_info_on_target_luminance(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t min_lum, uint32_t max_lum) { + ColorProfileMessage *msg = (ColorProfileMessage *)data; + ERR_FAIL_NULL(msg); + + // The uint32 is multiplied by 10000 for precision. + msg->color_profile.target_min_luminance = static_cast(min_lum) / 10000; + msg->color_profile.target_max_luminance = max_lum; +} + +void WaylandThread::_wp_image_description_info_on_target_max_cll(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t max_cll) { +} + +void WaylandThread::_wp_image_description_info_on_target_max_fall(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t max_fall) { +} + void WaylandThread::_wp_fractional_scale_on_preferred_scale(void *data, struct wp_fractional_scale_v1 *wp_fractional_scale_v1, uint32_t scale) { WindowState *ws = (WindowState *)data; ERR_FAIL_NULL(ws); @@ -3479,6 +3648,14 @@ WaylandThread::OfferState *WaylandThread::wp_primary_selection_offer_get_offer_s return nullptr; } +WaylandThread::ColorManagementState *WaylandThread::wp_color_manager_get_state(wp_color_manager_v1 *p_color_manager) { + if (p_color_manager && wl_proxy_is_godot((wl_proxy *)p_color_manager)) { + return (ColorManagementState *)wp_color_manager_v1_get_user_data(p_color_manager); + } + + return nullptr; +} + WaylandThread::EmbeddingCompositorState *WaylandThread::godot_embedding_compositor_get_state(struct godot_embedding_compositor *p_compositor) { // NOTE: No need for tag check as it's a "fake" interface - nothing else exposes it. if (p_compositor) { @@ -3873,6 +4050,17 @@ void WaylandThread::window_create(DisplayServerEnums::WindowID p_window_id, cons } } + if (supports_hdr()) { + ws.wp_color_management_surface_feedback = wp_color_manager_v1_get_surface_feedback(registry.wp_color_manager, ws.wl_surface); + wp_color_management_surface_feedback_v1_add_listener(ws.wp_color_management_surface_feedback, &wp_color_management_surface_feedback_listener, &ws); + + struct wp_image_description_v1 *image_description = wp_color_management_surface_feedback_v1_get_preferred_parametric(ws.wp_color_management_surface_feedback); + wp_image_description_v1_add_listener(image_description, &wp_image_description_listener, &ws); + + //NOTE: requires vulkan to use the VK_COLOR_SPACE_PASSTHROUGH_EXT colorspace to not raise protocol errors + ws.wp_color_management_surface = wp_color_manager_v1_get_surface(registry.wp_color_manager, ws.wl_surface); + } + bool decorated = false; #ifdef LIBDECOR_ENABLED @@ -4052,6 +4240,14 @@ void WaylandThread::window_destroy(DisplayServerEnums::WindowID p_window_id) { wp_fractional_scale_v1_destroy(ws.wp_fractional_scale); } + if (ws.wp_color_management_surface) { + wp_color_management_surface_v1_destroy(ws.wp_color_management_surface); + } + + if (ws.wp_color_management_surface_feedback) { + wp_color_management_surface_feedback_v1_destroy(ws.wp_color_management_surface_feedback); + } + if (ws.wp_viewport) { wp_viewport_destroy(ws.wp_viewport); } @@ -4656,6 +4852,40 @@ bool WaylandThread::window_get_idle_inhibition(DisplayServerEnums::WindowID p_wi return ws.wp_idle_inhibitor != nullptr; } +void WaylandThread::window_set_color_profile(DisplayServerEnums::WindowID p_window_id, ColorProfile p_profile) { + ERR_FAIL_COND(!windows.has(p_window_id)); + const WindowState &ws = windows[p_window_id]; + + if (!ws.wp_color_management_surface) { + return; + } + + if (p_profile.named_transfer_function == WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22) { + // This is largely a problem with some HDR monitors applying "glare compensation" or not. + // For monitors which do not apply glare compensation, it is correct to report gamma22 like we would on SDR. + // But there also exist monitors which apply glare compensation, on these monitors it is correct to request compound_2_4. + // Since we have no way to know on which type of monitor we are in, we unset the image description in the hopes + // that future compositor features may include choosing a default transfer function. + wp_color_management_surface_v1_unset_image_description(ws.wp_color_management_surface); + return; + } + + ColorManagementState *cms = wp_color_manager_get_state(registry.wp_color_manager); + + struct wp_image_description_creator_params_v1 *builder = wp_color_manager_v1_create_parametric_creator(registry.wp_color_manager); + wp_image_description_creator_params_v1_set_primaries_named(builder, p_profile.named_primary); + wp_image_description_creator_params_v1_set_tf_named(builder, p_profile.named_transfer_function); + + if ((cms->supported_render_feature & WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES) > 0) { + uint32_t min_luminance = static_cast(p_profile.target_min_luminance * 10000); + wp_image_description_creator_params_v1_set_luminances(builder, min_luminance, p_profile.target_max_luminance, p_profile.reference_luminance); + } + + struct wp_image_description_v1 *image_desc = wp_image_description_creator_params_v1_create(builder); + wp_color_management_surface_v1_set_image_description(ws.wp_color_management_surface, image_desc, WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL); + wp_image_description_v1_destroy(image_desc); +} + WaylandThread::ScreenData WaylandThread::screen_get_data(int p_screen) const { ERR_FAIL_INDEX_V(p_screen, registry.wl_outputs.size(), ScreenData()); @@ -5351,6 +5581,15 @@ void WaylandThread::primary_set_text(const String &p_text) { wl_display_roundtrip(wl_display); } +bool WaylandThread::supports_hdr() const { + ColorManagementState *color_state = wp_color_manager_get_state(registry.wp_color_manager); + if (!color_state) { + return false; + } + + return color_state->supports_hdr; +} + void WaylandThread::commit_surfaces() { for (KeyValue &pair : windows) { wl_surface_commit(pair.value.wl_surface); @@ -5709,6 +5948,10 @@ void WaylandThread::destroy() { zxdg_decoration_manager_v1_destroy(registry.xdg_decoration_manager); } + if (registry.wp_color_manager) { + wp_color_manager_v1_destroy(registry.wp_color_manager); + } + if (registry.wp_cursor_shape_manager) { wp_cursor_shape_manager_v1_destroy(registry.wp_cursor_shape_manager); } diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h index 2df57dd502a0..cd903e88950e 100644 --- a/platform/linuxbsd/wayland/wayland_thread.h +++ b/platform/linuxbsd/wayland/wayland_thread.h @@ -62,6 +62,7 @@ #include "wayland/protocol/pointer_warp.gen.h" #include "wayland/protocol/relative_pointer.gen.h" #undef pointer +#include "wayland/protocol/color_management.gen.h" #include "wayland/protocol/fractional_scale.gen.h" #include "wayland/protocol/tablet.gen.h" #include "wayland/protocol/text_input.gen.h" @@ -98,6 +99,16 @@ class Image; class WaylandThread { public: + struct ColorProfile { + uint32_t named_primary = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB; + uint32_t named_transfer_function = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22; + + // The luminances the compositor recommends. + float target_min_luminance = 0; + float target_max_luminance = 0; + float reference_luminance = 0; + }; + // Messages used for exchanging information between Godot's and Wayland's thread. class Message : public RefCounted { GDSOFTCLASS(Message, RefCounted); @@ -160,6 +171,14 @@ class WaylandThread { String text; }; + class ColorProfileMessage : public WindowMessage { + GDSOFTCLASS(ColorProfileMessage, WindowMessage); + + public: + WaylandThread *wayland_thread; + ColorProfile color_profile; + }; + struct RegistryState { WaylandThread *wayland_thread; @@ -196,6 +215,9 @@ class WaylandThread { struct wp_viewporter *wp_viewporter = nullptr; uint32_t wp_viewporter_name = 0; + struct wp_color_manager_v1 *wp_color_manager = nullptr; + uint32_t wp_color_manager_name = 0; + struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager = nullptr; uint32_t wp_fractional_scale_manager_name = 0; @@ -323,6 +345,9 @@ class WaylandThread { // What the compositor is recommending us. double preferred_fractional_scale = 0; + struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback = nullptr; + struct wp_color_management_surface_v1 *wp_color_management_surface = nullptr; + struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr; struct zwp_idle_inhibitor_v1 *wp_idle_inhibitor = nullptr; @@ -567,6 +592,15 @@ class WaylandThread { Point2i hotspot; }; + struct ColorManagementState { + // Compositor features. + uint32_t supported_render_intents = 0; + uint32_t supported_render_feature = 0; + uint32_t supported_transfer_function = 0; + uint32_t supported_primaries = 0; + bool supports_hdr = false; + }; + struct EmbeddingCompositorState { LocalVector clients; @@ -744,6 +778,31 @@ class WaylandThread { static void _xdg_popup_on_repositioned(void *data, struct xdg_popup *xdg_popup, uint32_t token); // wayland-protocols event handlers. + static void _wp_color_manager_on_supported_intent(void *data, struct wp_color_manager_v1 *wp_color_manager_v1, uint32_t render_intent); + static void _wp_color_manager_on_supported_feature(void *data, struct wp_color_manager_v1 *wp_color_manager_v1, uint32_t feature); + static void _wp_color_manager_on_supported_tf_named(void *data, struct wp_color_manager_v1 *wp_color_manager_v1, uint32_t tf); + static void _wp_color_manager_on_supported_primaries_named(void *data, struct wp_color_manager_v1 *wp_color_manager_v1, uint32_t primaries); + static void _wp_color_manager_on_done(void *data, struct wp_color_manager_v1 *wp_color_manager_v1); + + static void _wp_color_management_surface_feedback_on_preferred_changed(void *data, struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1, uint32_t identity); + static void _wp_color_management_surface_feedback_on_preferred_changed2(void *data, struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1, uint32_t identity_high, uint32_t identity_low); + + static void _wp_image_description_on_failed(void *data, struct wp_image_description_v1 *wp_image_description_v1, uint32_t cause, const char *msg); + static void _wp_image_description_on_ready(void *data, struct wp_image_description_v1 *wp_image_description_v1, uint32_t identity); + static void _wp_image_description_on_ready2(void *data, struct wp_image_description_v1 *wp_image_description_v1, uint32_t identity_high, uint32_t indentity_low); + + static void _wp_image_description_info_on_done(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1); + static void _wp_image_description_info_on_icc_file(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, int32_t icc, uint32_t icc_size); + static void _wp_image_description_info_on_primaries(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y); + static void _wp_image_description_info_on_primaries_named(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t primaries); + static void _wp_image_description_info_on_tf_power(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t eexp); + static void _wp_image_description_info_on_tf_named(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t tf); + static void _wp_image_description_info_on_luminances(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum); + static void _wp_image_description_info_on_target_primaries(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y); + static void _wp_image_description_info_on_target_luminance(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t min_lum, uint32_t max_lum); + static void _wp_image_description_info_on_target_max_cll(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t max_cll); + static void _wp_image_description_info_on_target_max_fall(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1, uint32_t max_fall); + static void _wp_fractional_scale_on_preferred_scale(void *data, struct wp_fractional_scale_v1 *wp_fractional_scale_v1, uint32_t scale); static void _wp_relative_pointer_on_relative_motion(void *data, struct zwp_relative_pointer_v1 *wp_relative_pointer_v1, uint32_t uptime_hi, uint32_t uptime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel); @@ -912,6 +971,39 @@ class WaylandThread { }; // wayland-protocols event listeners. + static constexpr struct wp_color_manager_v1_listener wp_color_manager_listener = { + .supported_intent = _wp_color_manager_on_supported_intent, + .supported_feature = _wp_color_manager_on_supported_feature, + .supported_tf_named = _wp_color_manager_on_supported_tf_named, + .supported_primaries_named = _wp_color_manager_on_supported_primaries_named, + .done = _wp_color_manager_on_done, + }; + + static constexpr struct wp_color_management_surface_feedback_v1_listener wp_color_management_surface_feedback_listener = { + .preferred_changed = _wp_color_management_surface_feedback_on_preferred_changed, + .preferred_changed2 = _wp_color_management_surface_feedback_on_preferred_changed2, + }; + + static constexpr struct wp_image_description_v1_listener wp_image_description_listener = { + .failed = _wp_image_description_on_failed, + .ready = _wp_image_description_on_ready, + .ready2 = _wp_image_description_on_ready2, + }; + + static constexpr struct wp_image_description_info_v1_listener wp_image_description_info_listener = { + .done = _wp_image_description_info_on_done, + .icc_file = _wp_image_description_info_on_icc_file, + .primaries = _wp_image_description_info_on_primaries, + .primaries_named = _wp_image_description_info_on_primaries_named, + .tf_power = _wp_image_description_info_on_tf_power, + .tf_named = _wp_image_description_info_on_tf_named, + .luminances = _wp_image_description_info_on_luminances, + .target_primaries = _wp_image_description_info_on_target_primaries, + .target_luminance = _wp_image_description_info_on_target_luminance, + .target_max_cll = _wp_image_description_info_on_target_max_cll, + .target_max_fall = _wp_image_description_info_on_target_max_fall, + }; + static constexpr struct wp_fractional_scale_v1_listener wp_fractional_scale_listener = { .preferred_scale = _wp_fractional_scale_on_preferred_scale, }; @@ -1087,6 +1179,7 @@ class WaylandThread { static OfferState *wl_data_offer_get_offer_state(struct wl_data_offer *p_offer); static OfferState *wp_primary_selection_offer_get_offer_state(struct zwp_primary_selection_offer_v1 *p_offer); + static ColorManagementState *wp_color_manager_get_state(wp_color_manager_v1 *p_color_manager); static EmbeddingCompositorState *godot_embedding_compositor_get_state(struct godot_embedding_compositor *p_compositor); @@ -1149,6 +1242,9 @@ class WaylandThread { void window_set_idle_inhibition(DisplayServerEnums::WindowID p_window_id, bool p_enable); bool window_get_idle_inhibition(DisplayServerEnums::WindowID p_window_id) const; + // Optional - require wp_color_management_v1 + void window_set_color_profile(DisplayServerEnums::WindowID p_window_id, ColorProfile p_profile); + ScreenData screen_get_data(int p_screen) const; int get_screen_count() const; @@ -1191,6 +1287,8 @@ class WaylandThread { void primary_set_text(const String &p_text); + bool supports_hdr() const; + void commit_surfaces(); void set_frame(); diff --git a/thirdparty/README.md b/thirdparty/README.md index 30630fff8647..37f8771526e5 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -1209,7 +1209,7 @@ Files extracted from upstream source: # wayland-protocols - Upstream: https://gitlab.freedesktop.org/wayland/wayland-protocols -- Version: 1.46 (6141e1154303dadd5c3e480bc4a16e26f1dcb2af, 2025) +- Version: 1.47 (88223018d1b578d0d8869866da66d9608e05f928, 2025) - License: MIT Files extracted from upstream source: @@ -1220,6 +1220,8 @@ Files extracted from upstream source: - `stable/viewporter/viewporter.xml` - `stable/xdg-shell/README` - `stable/xdg-shell/xdg-shell.xml` +- `staging/color-management/README.md` +- `staging/color-management/color-management-v1.xml` - `staging/fractional-scale/README` - `staging/fractional-scale/fractional-scale-v1.xml` - `staging/xdg-activation/README` diff --git a/thirdparty/wayland-protocols/staging/color-management/README b/thirdparty/wayland-protocols/staging/color-management/README new file mode 100644 index 000000000000..e14f2a8cb0d4 --- /dev/null +++ b/thirdparty/wayland-protocols/staging/color-management/README @@ -0,0 +1,11 @@ +Color management and HDR protocol + +Maintainers: +Sebastian Wick +Pekka Paalanen + + +Historical credits not mentioned in the first commit: + +- Niels Ole Salscheider, for an early protocol version + https://lists.freedesktop.org/archives/wayland-devel/2014-October/017755.html diff --git a/thirdparty/wayland-protocols/staging/color-management/color-management-v1.xml b/thirdparty/wayland-protocols/staging/color-management/color-management-v1.xml new file mode 100644 index 000000000000..0aa59bda510c --- /dev/null +++ b/thirdparty/wayland-protocols/staging/color-management/color-management-v1.xml @@ -0,0 +1,1724 @@ + + + + Copyright 2019 Sebastian Wick + Copyright 2019 Erwin Burema + Copyright 2020 AMD + Copyright 2020-2024 Collabora, Ltd. + Copyright 2024 Xaver Hugl + Copyright 2022-2025 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + The aim of the color management extension is to allow clients to know + the color properties of outputs, and to tell the compositor about the color + properties of their content on surfaces. All surface contents must be + readily intended for some display, but not necessarily for the display at + hand. Doing this enables a compositor to perform automatic color management + of content for different outputs according to how content is intended to + look like. + + For an introduction, see the section "Color management" in the Wayland + documentation at https://wayland.freedesktop.org/docs/html/ . + + The color properties are represented as an image description object which + is immutable after it has been created. A wl_output always has an + associated image description that clients can observe. A wl_surface + always has an associated preferred image description as a hint chosen by + the compositor that clients can also observe. Clients can set an image + description on a wl_surface to denote the color characteristics of the + surface contents. + + An image description essentially defines a display and (indirectly) its + viewing environment. An image description includes SDR and HDR colorimetry + and encoding, HDR metadata, and some parameters related to the viewing + environment. An image description does not include the properties set + through color-representation extension. It is expected that the + color-representation extension is used in conjunction with the + color-management extension when necessary, particularly with the YUV family + of pixel formats. + + The normative appendix for this protocol is in the appendix.md file beside + this XML file. + + The color-and-hdr repository + (https://gitlab.freedesktop.org/pq/color-and-hdr) contains + background information on the protocol design and legacy color management. + It also contains a glossary, learning resources for digital color, tools, + samples and more. + + The terminology used in this protocol is based on common color science and + color encoding terminology where possible. The glossary in the color-and-hdr + repository shall be the authority on the definition of terms in this + protocol. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + + + + + A singleton global interface used for getting color management extensions + for wl_surface and wl_output objects, and for creating client defined + image description objects. The extension interfaces allow + getting the image description of outputs and setting the image + description of surfaces. + + Compositors should never remove this global. + + + + + Destroy the wp_color_manager_v1 object. This does not affect any other + objects in any way. + + + + + + + + + + + See the ICC.1:2022 specification from the International Color Consortium + for more details about rendering intents. + + The principles of ICC defined rendering intents apply with all types of + image descriptions, not only those with ICC file profiles. + + Compositors must support the perceptual rendering intent. Other + rendering intents are optional. + + + + + + + + + + This rendering intent is a modified absolute rendering intent that + assumes the viewer is not adapted to the display white point, so no + chromatic adaptation between surface and display is done. + This can be useful for color proofing applications. + + + + + + + + + + + + + + + The compositor supports set_mastering_display_primaries request with a + target color volume fully contained inside the primary color volume. + + + + + The compositor additionally supports target color volumes that + extend outside of the primary color volume. + + This can only be advertised if feature set_mastering_display_primaries + is supported as well. + + + + + + + + Named color primaries used to encode well-known sets of primaries. + + A value of 0 is invalid and will never be present in the list of enums. + + + + + Color primaries as defined by + - Rec. ITU-R BT.709-6 + - Rec. ITU-R BT.1361-0 conventional colour gamut system and extended + colour gamut system (historical) + - IEC 61966-2-1 sRGB or sYCC + - IEC 61966-2-4 + - Society of Motion Picture and Television Engineers (SMPTE) RP 177 + (1993) Annex B + + + + + Color primaries as defined by + - Rec. ITU-R BT.470-6 System M (historical) + - United States National Television System Committee 1953 + Recommendation for transmission standards for color television + - United States Federal Communications Commission (2003) Title 47 Code + of Federal Regulations 73.682 (a)(20) + + + + + Color primaries as defined by + - Rec. ITU-R BT.470-6 System B, G (historical) + - Rec. ITU-R BT.601-7 625 + - Rec. ITU-R BT.1358-0 625 (historical) + - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + + + + + Color primaries as defined by + - Rec. ITU-R BT.601-7 525 + - Rec. ITU-R BT.1358-1 525 or 625 (historical) + - Rec. ITU-R BT.1700-0 NTSC + - SMPTE 170M (2004) + - SMPTE 240M (1999) (historical) + + + + + Color primaries as defined by Recommendation ITU-T H.273 + "Coding-independent code points for video signal type identification" + for "generic film". + + + + + Color primaries as defined by + - Rec. ITU-R BT.2020-2 + - Rec. ITU-R BT.2100-0 + + + + + Color primaries as defined as the maximum of the CIE 1931 XYZ color + space by + - SMPTE ST 428-1 + - (CIE 1931 XYZ as in ISO 11664-1) + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE RP 431-2 (2011). + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE EG 432-1 (2010). + + + + + Color primaries as defined by Adobe as "Adobe RGB" and later published + by ISO 12640-4 (2011). + + + + + + + Named transfer functions used to represent well-known transfer + characteristics of displays. + + A value of 0 is invalid and will never be present in the list of enums. + + See appendix.md for the formulae. + + + + + Rec. ITU-R BT.1886 is the display transfer characteristic assumed by + - Rec. ITU-R BT.601-7 525 and 625 + - Rec. ITU-R BT.709-6 + - Rec. ITU-R BT.2020-2 + + This TF implies these default luminances from Rec. ITU-R BT.2035: + - primary color volume minimum: 0.01 cd/m² + - primary color volume maximum: 100 cd/m² + - reference white: 100 cd/m² + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.470-6 System M (historical) + - United States National Television System Committee 1953 + Recommendation for transmission standards for color television + - United States Federal Communications Commission (2003) Title 47 Code + of Federal Regulations 73.682 (a) (20) + - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + - IEC 61966-2-1 (reference display) + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.470-6 System B, G (historical) + + + + + Transfer characteristics as defined by + - SMPTE ST 240 (1999) + + + + + Linear transfer function defined over all real numbers. + Normalised electrical values are equal the normalised optical values. + + + + + Logarithmic transfer characteristic (100:1 range). + + + + + Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range). + + + + + Transfer characteristics as defined by + - IEC 61966-2-4 + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sRGB + + As a rule of thumb, use gamma22 for video, motion picture and + computer graphics, or compound_power_2_4 for ICC calibrated print + workflows. + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sYCC + + + + + Transfer characteristics as defined by + - SMPTE ST 2084 (2014) for 10-, 12-, 14- and 16-bit systems + - Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system + + This TF implies these default luminances + - primary color volume minimum: 0.005 cd/m² + - primary color volume maximum: 10000 cd/m² + - reference white: 203 cd/m² + + The difference between the primary color volume minimum and maximum + must be approximately 10000 cd/m² as that is the swing of the EOTF + defined by ST 2084 and BT.2100. The default value for the + reference white is a protocol addition: it is suggested by + Report ITU-R BT.2408-7 and is not part of ST 2084 or BT.2100. + + + + + Transfer characteristics as defined by + - SMPTE ST 428-1 (2019) + + + + + Transfer characteristics as defined by + - ARIB STD-B67 (2015) + - Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system + + This TF implies these default luminances + - primary color volume minimum: 0.005 cd/m² + - primary color volume maximum: 1000 cd/m² + - reference white: 203 cd/m² + + HLG is a relative display-referred signal with a specified + non-linear mapping to the display peak luminance (the HLG OOTF). + All absolute luminance values used here for HLG assume a 1000 cd/m² + peak display. + + The default value for the reference white is a protocol addition: + it is suggested by Report ITU-R BT.2408-7 and is not part of + ARIB STD-B67 or BT.2100. + + + + + Encoding characteristics as defined by IEC 61966-2-1, for displays + that invert the encoding function. + + + + + + + This creates a new wp_color_management_output_v1 object for the + given wl_output. + + See the wp_color_management_output_v1 interface for more details. + + + + + + + + + If a wp_color_management_surface_v1 object already exists for the given + wl_surface, the protocol error surface_exists is raised. + + This creates a new color wp_color_management_surface_v1 object for the + given wl_surface. + + See the wp_color_management_surface_v1 interface for more details. + + + + + + + + + This creates a new color wp_color_management_surface_feedback_v1 object + for the given wl_surface. + + See the wp_color_management_surface_feedback_v1 interface for more + details. + + + + + + + + + Makes a new ICC-based image description creator object with all + properties initially unset. The client can then use the object's + interface to define all the required properties for an image description + and finally create a wp_image_description_v1 object. + + This request can be used when the compositor advertises + wp_color_manager_v1.feature.icc_v2_v4. + Otherwise this request raises the protocol error unsupported_feature. + + + + + + + + Makes a new parametric image description creator object with all + properties initially unset. The client can then use the object's + interface to define all the required properties for an image description + and finally create a wp_image_description_v1 object. + + This request can be used when the compositor advertises + wp_color_manager_v1.feature.parametric. + Otherwise this request raises the protocol error unsupported_feature. + + + + + + + + This creates a pre-defined image description for the so-called + Windows-scRGB stimulus encoding. This comes from the Windows 10 handling + of its own definition of an scRGB color space for an HDR screen + driven in BT.2100/PQ signalling mode. + + Windows-scRGB uses sRGB (BT.709) color primaries and white point. + The transfer characteristic is extended linear. + + The nominal color channel value range is extended, meaning it includes + negative and greater than 1.0 values. Negative values are used to + escape the sRGB color gamut boundaries. To make use of the extended + range, the client needs to use a pixel format that can represent those + values, e.g. floating-point 16 bits per channel. + + Nominal color value R=G=B=0.0 corresponds to BT.2100/PQ system + 0 cd/m², and R=G=B=1.0 corresponds to BT.2100/PQ system 80 cd/m². + The maximum is R=G=B=125.0 corresponding to 10k cd/m². + + Windows-scRGB is displayed by Windows 10 by converting it to + BT.2100/PQ, maintaining the CIE 1931 chromaticity and mapping the + luminance as above. No adjustment is made to the signal to account + for the viewing conditions. + + The reference white level of Windows-scRGB is unknown. If a + reference white level must be assumed for compositor processing, it + should be R=G=B=2.5375 corresponding to 203 cd/m² of Report ITU-R + BT.2408-7. + + The target color volume of Windows-scRGB is unknown. The color gamut + may be anything between sRGB and BT.2100. + + Note: EGL_EXT_gl_colorspace_scrgb_linear definition differs from + Windows-scRGB by using R=G=B=1.0 as the reference white level, while + Windows-scRGB reference white level is unknown or varies. However, + it seems probable that Windows implements both + EGL_EXT_gl_colorspace_scrgb_linear and Vulkan + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT as Windows-scRGB. + + This request can be used when the compositor advertises + wp_color_manager_v1.feature.windows_scrgb. + Otherwise this request raises the protocol error unsupported_feature. + + The resulting image description object does not allow get_information + request. The wp_image_description_v1.ready event shall be sent. + + + + + + + + When this object is created, it shall immediately send this event once + for each rendering intent the compositor supports. + + A compositor must not advertise intents that are deprecated in the + bound version of the interface. + + + + + + + + When this object is created, it shall immediately send this event once + for each compositor supported feature listed in the enumeration. + + A compositor must not advertise features that are deprecated in the + bound version of the interface. + + + + + + + + When this object is created, it shall immediately send this event once + for each named transfer function the compositor supports with the + parametric image description creator. + + A compositor must not advertise transfer functions that are deprecated + in the bound version of the interface. + + + + + + + + When this object is created, it shall immediately send this event once + for each named set of primaries the compositor supports with the + parametric image description creator. + + A compositor must not advertise names that are deprecated in the + bound version of the interface. + + + + + + + + This event is sent when all supported rendering intents, features, + transfer functions and named primaries have been sent. + + + + + + This request retrieves the image description backing a reference. + + The get_information request can be used if and only if the request that + creates the reference allows it. + + + + + + + + + + A wp_color_management_output_v1 describes the color properties of an + output. + + The wp_color_management_output_v1 is associated with the wl_output global + underlying the wl_output object. Therefore the client destroying the + wl_output object has no impact, but the compositor removing the output + global makes the wp_color_management_output_v1 object inert. + + + + + Destroy the color wp_color_management_output_v1 object. This does not + affect any remaining protocol objects. + + + + + + This event is sent whenever the image description of the output changed, + followed by one wl_output.done event common to output events across all + extensions. + + If the client wants to use the updated image description, it needs to do + get_image_description again, because image description objects are + immutable. + + + + + + This creates a new wp_image_description_v1 object for the current image + description of the output. There always is exactly one image description + active for an output so the client should destroy the image description + created by earlier invocations of this request. This request is usually + sent as a reaction to the image_description_changed event or when + creating a wp_color_management_output_v1 object. + + The image description of an output represents the color encoding the + output expects. There might be performance and power advantages, as well + as improved color reproduction, if a content update matches the image + description of the output it is being shown on. If a content update is + shown on any other output than the one it matches the image description + of, then the color reproduction on those outputs might be considerably + worse. + + The created wp_image_description_v1 object preserves the image + description of the output from the time the object was created. + + The resulting image description object allows get_information request. + + If this protocol object is inert, the resulting image description object + shall immediately deliver the wp_image_description_v1.failed event with + the no_output cause. + + If the interface version is inadequate for the output's image + description, meaning that the client does not support all the events + needed to deliver the crucial information, the resulting image + description object shall immediately deliver the + wp_image_description_v1.failed event with the low_version cause. + + Otherwise the object shall immediately deliver the ready event. + + + + + + + + + A wp_color_management_surface_v1 allows the client to set the color + space and HDR properties of a surface. + + If the wl_surface associated with the wp_color_management_surface_v1 is + destroyed, the wp_color_management_surface_v1 object becomes inert. + + + + + Destroy the wp_color_management_surface_v1 object and do the same as + unset_image_description. + + + + + + + + + + + + + If this protocol object is inert, the protocol error inert is raised. + + Set the image description of the underlying surface. The image + description and rendering intent are double-buffered state, see + wl_surface.commit. + + It is the client's responsibility to understand the image description + it sets on a surface, and to provide content that matches that image + description. Compositors might convert images to match their own or any + other image descriptions. + + Image descriptions which are not ready (see wp_image_description_v1) + are forbidden in this request, and in such case the protocol error + image_description is raised. + + All image descriptions which are ready (see wp_image_description_v1) + are allowed and must always be accepted by the compositor. + + When an image description is set on a surface, it establishes an + explicit link between surface pixel values and surface colorimetry. + This link may be undefined for some pixel values, see the image + description creator interfaces for the conditions. Non-finite + floating-point values (NaN, Inf) always have an undefined colorimetry. + + A rendering intent provides the client's preference on how surface + colorimetry should be mapped to each output. The render_intent value + must be one advertised by the compositor with + wp_color_manager_v1.render_intent event, otherwise the protocol error + render_intent is raised. + + By default, a surface does not have an associated image description + nor a rendering intent. The handling of color on such surfaces is + compositor implementation defined. Compositors should handle such + surfaces as sRGB, but may handle them differently if they have specific + requirements. + + Setting the image description has copy semantics; after this request, + the image description can be immediately destroyed without affecting + the pending state of the surface. + + + + + + + + + If this protocol object is inert, the protocol error inert is raised. + + This request removes any image description from the surface. See + set_image_description for how a compositor handles a surface without + an image description. This is double-buffered state, see + wl_surface.commit. + + + + + + + A wp_color_management_surface_feedback_v1 allows the client to get the + preferred image description of a surface. + + If the wl_surface associated with this object is destroyed, the + wp_color_management_surface_feedback_v1 object becomes inert. + + + + + Destroy the wp_color_management_surface_feedback_v1 object. + + + + + + + + + + + + Starting from interface version 2, 'preferred_changed2' is sent instead + of this event. See the 'preferred_changed2' event for the definition. + + + + + + + + If this protocol object is inert, the protocol error inert is raised. + + The preferred image description represents the compositor's preferred + color encoding for this wl_surface at the current time. There might be + performance and power advantages, as well as improved color + reproduction, if the image description of a content update matches the + preferred image description. + + This creates a new wp_image_description_v1 object for the currently + preferred image description for the wl_surface. The client should + stop using and destroy the image descriptions created by earlier + invocations of this request for the associated wl_surface. + This request is usually sent as a reaction to the preferred_changed + event or when creating a wp_color_management_surface_feedback_v1 object + if the client is capable of adapting to image descriptions. + + The created wp_image_description_v1 object preserves the preferred image + description of the wl_surface from the time the object was created. + + The resulting image description object allows get_information request. + + If the image description is parametric, the client should set it on its + wl_surface only if the image description is an exact match with the + client content. Particularly if everything else matches, but the target + color volume is greater than what the client needs, the client should + create its own parameric image description with its exact parameters. + + If the interface version is inadequate for the preferred image + description, meaning that the client does not support all the + events needed to deliver the crucial information, the resulting image + description object shall immediately deliver the + wp_image_description_v1.failed event with the low_version cause, + otherwise the object shall immediately deliver the ready event. + + + + + + + + The same description as for get_preferred applies, except the returned + image description is guaranteed to be parametric. This is meant for + clients that can only deal with parametric image descriptions. + + If the compositor doesn't support parametric image descriptions, the + unsupported_feature error is emitted. + + + + + + + + + + The preferred image description is the one which likely has the most + performance and/or quality benefits for the compositor if used by the + client for its wl_surface contents. This event is sent whenever the + compositor changes the wl_surface's preferred image description. + + This event sends the identity of the new preferred state as the argument, + so clients who are aware of the image description already can reuse it. + Otherwise, if the client client wants to know what the preferred image + description is, it shall use the get_preferred request. + + The preferred image description is not automatically used for anything. + It is only a hint, and clients may set any valid image description with + set_image_description, but there might be performance and color accuracy + improvements by providing the wl_surface contents in the preferred + image description. Therefore clients that can, should render according + to the preferred image description + + + + + + + + + + + This type of object is used for collecting all the information required + to create a wp_image_description_v1 object from an ICC file. A complete + set of required parameters consists of these properties: + - ICC file + + Each required property must be set exactly once if the client is to create + an image description. The set requests verify that a property was not + already set. The create request verifies that all required properties are + set. There may be several alternative requests for setting each property, + and in that case the client must choose one of them. + + Once all properties have been set, the create request must be used to + create the image description object, destroying the creator in the + process. + + The link between a pixel value (a device value in ICC) and its respective + colorimetry is defined by the details of the particular ICC profile. + Those details also determine when colorimetry becomes undefined. + + + + + + + + + + + + + + + Create an image description object based on the ICC information + previously set on this object. A compositor must parse the ICC data in + some undefined but finite amount of time. + + The completeness of the parameter set is verified. If the set is not + complete, the protocol error incomplete_set is raised. For the + definition of a complete set, see the description of this interface. + + If the particular combination of the information is not supported + by the compositor, the resulting image description object shall + immediately deliver the wp_image_description_v1.failed event with the + 'unsupported' cause. If a valid image description was created from the + information, the wp_image_description_v1.ready event will eventually + be sent instead. + + This request destroys the wp_image_description_creator_icc_v1 object. + + The resulting image description object does not allow get_information + request. + + + + + + + + Sets the ICC profile file to be used as the basis of the image + description. + + The data shall be found through the given fd at the given offset, having + the given length. The fd must be seekable and readable. Violating these + requirements raises the bad_fd protocol error. + + If reading the data fails due to an error independent of the client, the + compositor shall send the wp_image_description_v1.failed event on the + created wp_image_description_v1 with the 'operating_system' cause. + + The maximum size of the ICC profile is 32 MB. If length is greater than + that or zero, the protocol error bad_size is raised. If offset + length + exceeds the file size, the protocol error out_of_file is raised. + + A compositor may read the file at any time starting from this request + and only until whichever happens first: + - If create request was issued, the wp_image_description_v1 object + delivers either failed or ready event; or + - if create request was not issued, this + wp_image_description_creator_icc_v1 object is destroyed. + + A compositor shall not modify the contents of the file, and the fd may + be sealed for writes and size changes. The client must ensure to its + best ability that the data does not change while the compositor is + reading it. + + The data must represent a valid ICC profile. The ICC profile version + must be 2 or 4, it must be a 3 channel profile and the class must be + Display or ColorSpace. Violating these requirements will not result in a + protocol error, but will eventually send the + wp_image_description_v1.failed event on the created + wp_image_description_v1 with the 'unsupported' cause. + + See the International Color Consortium specification ICC.1:2022 for more + details about ICC profiles. + + If ICC file has already been set on this object, the protocol error + already_set is raised. + + + + + + + + + + + This type of object is used for collecting all the parameters required + to create a wp_image_description_v1 object. A complete set of required + parameters consists of these properties: + - transfer characteristic function (tf) + - chromaticities of primaries and white point (primary color volume) + + The following properties are optional and have a well-defined default + if not explicitly set: + - primary color volume luminance range + - reference white luminance level + - mastering display primaries and white point (target color volume) + - mastering luminance range + + The following properties are optional and will be ignored + if not explicitly set: + - maximum content light level + - maximum frame-average light level + + Each required property must be set exactly once if the client is to create + an image description. The set requests verify that a property was not + already set. The create request verifies that all required properties are + set. There may be several alternative requests for setting each property, + and in that case the client must choose one of them. + + Once all properties have been set, the create request must be used to + create the image description object, destroying the creator in the + process. + + A viewer, who is viewing the display defined by the resulting image + description (the viewing environment included), is assumed to be fully + adapted to the primary color volume's white point. + + Any of the following conditions will cause the colorimetry of a pixel + to become undefined: + - Values outside of the defined range of the transfer characteristic. + - Tristimulus that exceeds the target color volume. + - If extended_target_volume is not supported: tristimulus that exceeds + the primary color volume. + + The closest correspondence to an image description created through this + interface is the Display class of profiles in ICC. + + + + + + + + + + + + + + + + Create an image description object based on the parameters previously + set on this object. + + The completeness of the parameter set is verified. If the set is not + complete, the protocol error incomplete_set is raised. For the + definition of a complete set, see the description of this interface. + + When both max_cll and max_fall are set, max_fall must be less or equal + to max_cll otherwise the invalid_luminance protocol error is raised. + + In version 1, these following conditions also result in the + invalid_luminance protocol error. Version 2 and later do not have this + requirement. + - When max_cll is set, it must be greater than min L and less or equal + to max L of the mastering luminance range. + - When max_fall is set, it must be greater than min L and less or equal + to max L of the mastering luminance range. + + If the particular combination of the parameter set is not supported + by the compositor, the resulting image description object shall + immediately deliver the wp_image_description_v1.failed event with the + 'unsupported' cause. If a valid image description was created from the + parameter set, the wp_image_description_v1.ready event will eventually + be sent instead. + + This request destroys the wp_image_description_creator_params_v1 + object. + + The resulting image description object does not allow get_information + request. + + + + + + + + Sets the transfer characteristic using explicitly enumerated named + functions. + + When the resulting image description is attached to an image, the + content should be decoded according to the industry standard + practices for the transfer characteristic. + + Only names advertised with wp_color_manager_v1 event supported_tf_named + are allowed. Other values shall raise the protocol error invalid_tf. + + If transfer characteristic has already been set on this object, the + protocol error already_set is raised. + + + + + + + + Sets the color component transfer characteristic to a power curve with + the given exponent. Negative values are handled by mirroring the + positive half of the curve through the origin. The valid domain and + range of the curve are all finite real numbers. This curve represents + the conversion from electrical to optical color channel values. + + The curve exponent shall be multiplied by 10000 to get the argument eexp + value to carry the precision of 4 decimals. + + The curve exponent must be at least 1.0 and at most 10.0. Otherwise the + protocol error invalid_tf is raised. + + If transfer characteristic has already been set on this object, the + protocol error already_set is raised. + + This request can be used when the compositor advertises + wp_color_manager_v1.feature.set_tf_power. Otherwise this request raises + the protocol error unsupported_feature. + + + + + + + + Sets the color primaries and white point using explicitly named sets. + This describes the primary color volume which is the basis for color + value encoding. + + Only names advertised with wp_color_manager_v1 event + supported_primaries_named are allowed. Other values shall raise the + protocol error invalid_primaries_named. + + If primaries have already been set on this object, the protocol error + already_set is raised. + + + + + + + + Sets the color primaries and white point using CIE 1931 xy chromaticity + coordinates. This describes the primary color volume which is the basis + for color value encoding. + + Each coordinate value is multiplied by 1 million to get the argument + value to carry precision of 6 decimals. + + If primaries have already been set on this object, the protocol error + already_set is raised. + + This request can be used if the compositor advertises + wp_color_manager_v1.feature.set_primaries. Otherwise this request raises + the protocol error unsupported_feature. + + + + + + + + + + + + + + + Sets the primary color volume luminance range and the reference white + luminance level. These values include the minimum display emission, but + not external flare. The minimum display emission is assumed to have + the chromaticity of the primary color volume white point. + + The default luminances from + https://www.color.org/chardata/rgb/srgb.xalter are + - primary color volume minimum: 0.2 cd/m² + - primary color volume maximum: 80 cd/m² + - reference white: 80 cd/m² + + Setting a named transfer characteristic can imply other default + luminances. + + The default luminances get overwritten when this request is used. + With transfer_function.st2084_pq the given 'max_lum' value is ignored, + and 'max_lum' is taken as 'min_lum' + 10000 cd/m². + + 'min_lum' and 'max_lum' specify the minimum and maximum luminances of + the primary color volume as reproduced by the targeted display. + + 'reference_lum' specifies the luminance of the reference white as + reproduced by the targeted display, and reflects the targeted viewing + environment. + + Compositors should make sure that all content is anchored, meaning that + an input signal level of 'reference_lum' on one image description and + another input signal level of 'reference_lum' on another image + description should produce the same output level, even though the + 'reference_lum' on both image representations can be different. + + 'reference_lum' may be higher than 'max_lum'. In that case reaching + the reference white output level in image content requires the + 'extended_target_volume' feature support. + + If 'max_lum' or 'reference_lum' are less than or equal to 'min_lum', + the protocol error invalid_luminance is raised. + + The minimum luminance is multiplied by 10000 to get the argument + 'min_lum' value and carries precision of 4 decimals. The maximum + luminance and reference white luminance values are unscaled. + + If the primary color volume luminance range and the reference white + luminance level have already been set on this object, the protocol error + already_set is raised. + + This request can be used if the compositor advertises + wp_color_manager_v1.feature.set_luminances. Otherwise this request + raises the protocol error unsupported_feature. + + + + + + + + + + Provides the color primaries and white point of the mastering display + using CIE 1931 xy chromaticity coordinates. This is compatible with the + SMPTE ST 2086 definition of HDR static metadata. + + The mastering display primaries and mastering display luminances define + the target color volume. + + If mastering display primaries are not explicitly set, the target color + volume is assumed to have the same primaries as the primary color volume. + + The target color volume is defined by all tristimulus values between 0.0 + and 1.0 (inclusive) of the color space defined by the given mastering + display primaries and white point. The colorimetry is identical between + the container color space and the mastering display color space, + including that no chromatic adaptation is applied even if the white + points differ. + + The target color volume can exceed the primary color volume to allow for + a greater color volume with an existing color space definition (for + example scRGB). It can be smaller than the primary color volume to + minimize gamut and tone mapping distances for big color spaces (HDR + metadata). + + To make use of the entire target color volume a suitable pixel format + has to be chosen (e.g. floating point to exceed the primary color + volume, or abusing limited quantization range as with xvYCC). + + Each coordinate value is multiplied by 1 million to get the argument + value to carry precision of 6 decimals. + + If mastering display primaries have already been set on this object, the + protocol error already_set is raised. + + This request can be used if the compositor advertises + wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise + this request raises the protocol error unsupported_feature. The + advertisement implies support only for target color volumes fully + contained within the primary color volume. + + If a compositor additionally supports target color volume exceeding the + primary color volume, it must advertise + wp_color_manager_v1.feature.extended_target_volume. If a client uses + target color volume exceeding the primary color volume and the + compositor does not support it, the result is implementation defined. + Compositors are recommended to detect this case and fail the image + description gracefully, but it may as well result in color artifacts. + + + + + + + + + + + + + + + Sets the luminance range that was used during the content mastering + process as the minimum and maximum absolute luminance L. These values + include the minimum display emission and ambient flare luminances, + assumed to be optically additive and have the chromaticity of the + primary color volume white point. This should be + compatible with the SMPTE ST 2086 definition of HDR static metadata. + + The mastering display primaries and mastering display luminances define + the target color volume. + + If mastering luminances are not explicitly set, the target color volume + is assumed to have the same min and max luminances as the primary color + volume. + + If max L is less than or equal to min L, the protocol error + invalid_luminance is raised. + + Min L value is multiplied by 10000 to get the argument min_lum value + and carry precision of 4 decimals. Max L value is unscaled for max_lum. + + This request can be used if the compositor advertises + wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise + this request raises the protocol error unsupported_feature. The + advertisement implies support only for target color volumes fully + contained within the primary color volume. + + If a compositor additionally supports target color volume exceeding the + primary color volume, it must advertise + wp_color_manager_v1.feature.extended_target_volume. If a client uses + target color volume exceeding the primary color volume and the + compositor does not support it, the result is implementation defined. + Compositors are recommended to detect this case and fail the image + description gracefully, but it may as well result in color artifacts. + + + + + + + + + Sets the maximum content light level (max_cll) as defined by CTA-861-H. + + max_cll is undefined by default. + + + + + + + + Sets the maximum frame-average light level (max_fall) as defined by + CTA-861-H. + + max_fall is undefined by default. + + + + + + + + + An image description carries information about the pixel color encoding + and its intended display and viewing environment. The image description is + attached to a wl_surface via + wp_color_management_surface_v1.set_image_description. A compositor can use + this information to decode pixel values into colorimetrically meaningful + quantities, which allows the compositor to transform the surface contents + to become suitable for various displays and viewing environments. + + Note, that the wp_image_description_v1 object is not ready to be used + immediately after creation. The object eventually delivers either the + 'ready' or the 'failed' event, specified in all requests creating it. The + object is deemed "ready" after receiving the 'ready' event. + + An object which is not ready is illegal to use, it can only be destroyed. + Any other request in this interface shall result in the 'not_ready' + protocol error. Attempts to use an object which is not ready through other + interfaces shall raise protocol errors defined there. + + Once created and regardless of how it was created, a + wp_image_description_v1 object always refers to one fixed image + description. It cannot change after creation. + + + + + Destroy this object. It is safe to destroy an object which is not ready. + + Destroying a wp_image_description_v1 object has no side-effects, not + even if a wp_color_management_surface_v1.set_image_description has not + yet been followed by a wl_surface.commit. + + + + + + + + + + + + + + + + + + + + + + If creating a wp_image_description_v1 object fails for a reason that is + not defined as a protocol error, this event is sent. + + The requests that create image description objects define whether and + when this can occur. Only such creation requests can trigger this event. + This event cannot be triggered after the image description was + successfully formed. + + Once this event has been sent, the wp_image_description_v1 object will + never become ready and it can only be destroyed. + + + + + + + + + Starting from interface version 2, the 'ready2' event is sent instead + of this event. + + For the definition of this event, see the 'ready2' event. The + difference to this event is as follows. + + The id number is valid only as long as the protocol object is alive. If + all protocol objects referring to the same image description record are + destroyed, the id number may be recycled for a different image + description record. + + + + + + + + Creates a wp_image_description_info_v1 object which delivers the + information that makes up the image description. + + Not all image description protocol objects allow get_information + request. Whether it is allowed or not is defined by the request that + created the object. If get_information is not allowed, the protocol + error no_information is raised. + + + + + + + + + + Once this event has been sent, the wp_image_description_v1 object is + deemed "ready". Ready objects can be used to send requests and can be + used through other interfaces. + + Every ready wp_image_description_v1 protocol object refers to an + underlying image description record in the compositor. Multiple protocol + objects may end up referring to the same record. Clients may identify + these "copies" by comparing their id numbers: if the numbers from two + protocol objects are identical, the protocol objects refer to the same + image description record. Two different image description records + cannot have the same id number simultaneously. The id number does not + change during the lifetime of the image description record. + + Image description id number is not a protocol object id. Zero is + reserved as an invalid id number. It shall not be possible for a client + to refer to an image description by its id number in protocol. The id + numbers might not be portable between Wayland connections. A compositor + shall not send an invalid id number. + + Compositors must not recycle image description id numbers. + + This identity allows clients to de-duplicate image description records + and avoid get_information request if they already have the image + description information. + + + + + + + + + + Sends all matching events describing an image description object exactly + once and finally sends the 'done' event. + + This means + - if the image description is parametric, it must send + - primaries + - named_primaries, if applicable + - at least one of tf_power and tf_named, as applicable + - luminances + - target_primaries + - target_luminance + - if the image description is parametric, it may send, if applicable, + - target_max_cll + - target_max_fall + - if the image description contains an ICC profile, it must send the + icc_file event + + Once a wp_image_description_info_v1 object has delivered a 'done' event it + is automatically destroyed. + + Every wp_image_description_info_v1 created from the same + wp_image_description_v1 shall always return the exact same data. + + + + + Signals the end of information events and destroys the object. + + + + + + The icc argument provides a file descriptor to the client which may be + memory-mapped to provide the ICC profile matching the image description. + The fd is read-only, and if mapped then it must be mapped with + MAP_PRIVATE by the client. + + The ICC profile version and other details are determined by the + compositor. There is no provision for a client to ask for a specific + kind of a profile. + + + + + + + + + + Delivers the primary color volume primaries and white point using CIE + 1931 xy chromaticity coordinates. + + Each coordinate value is multiplied by 1 million to get the argument + value to carry precision of 6 decimals. + + + + + + + + + + + + + + + Delivers the primary color volume primaries and white point using an + explicitly enumerated named set. + + + + + + + + The color component transfer characteristic of this image description is + a pure power curve. This event provides the exponent of the power + function. This curve represents the conversion from electrical to + optical pixel or color values. + + The curve exponent has been multiplied by 10000 to get the argument eexp + value to carry the precision of 4 decimals. + + + + + + + + Delivers the transfer characteristic using an explicitly enumerated + named function. + + + + + + + + Delivers the primary color volume luminance range and the reference + white luminance level. These values include the minimum display emission + and ambient flare luminances, assumed to be optically additive and have + the chromaticity of the primary color volume white point. + + The minimum luminance is multiplied by 10000 to get the argument + 'min_lum' value and carries precision of 4 decimals. The maximum + luminance and reference white luminance values are unscaled. + + + + + + + + + + Provides the color primaries and white point of the target color volume + using CIE 1931 xy chromaticity coordinates. This is compatible with the + SMPTE ST 2086 definition of HDR static metadata for mastering displays. + + While primary color volume is about how color is encoded, the target + color volume is the actually displayable color volume. If target color + volume is equal to the primary color volume, then this event is not + sent. + + Each coordinate value is multiplied by 1 million to get the argument + value to carry precision of 6 decimals. + + + + + + + + + + + + + + + Provides the luminance range that the image description is targeting as + the minimum and maximum absolute luminance L. These values include the + minimum display emission and ambient flare luminances, assumed to be + optically additive and have the chromaticity of the primary color + volume white point. This should be compatible with the SMPTE ST 2086 + definition of HDR static metadata. + + This luminance range is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + Min L value is multiplied by 10000 to get the argument min_lum value and + carry precision of 4 decimals. Max L value is unscaled for max_lum. + + + + + + + + + Provides the targeted max_cll of the image description. max_cll is + defined by CTA-861-H. + + This luminance is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + + + + + + + Provides the targeted max_fall of the image description. max_fall is + defined by CTA-861-H. + + This luminance is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + + + + + + + + This object is a reference to an image description. This interface is + frozen at version 1 to allow other protocols to create + wp_image_description_v1 objects. + + The wp_color_manager_v1.get_image_description request can be used to + retrieve the underlying image description. + + + + + Destroy this object. This has no effect on the referenced image + description. + + + +