HDR output for linuxbsd (wayland)
This commit is contained in:
@@ -2751,7 +2751,7 @@
|
||||
Display server supports interaction with screen reader or Braille display. [b]Linux (X11/Wayland), macOS, Windows[/b]
|
||||
</constant>
|
||||
<constant name="FEATURE_HDR_OUTPUT" value="35" enum="Feature">
|
||||
Display server supports HDR output. [b]macOS, iOS, visionOS, Windows[/b]
|
||||
Display server supports HDR output. [b]Linux (Wayland), macOS, iOS, visionOS, Windows[/b]
|
||||
</constant>
|
||||
<constant name="ROLE_UNKNOWN" value="0" enum="AccessibilityRole" deprecated="Use [AccessibilityServer] instead.">
|
||||
Unknown or custom role.
|
||||
|
||||
@@ -155,6 +155,7 @@ public:
|
||||
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.
|
||||
|
||||
@@ -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<FormatCandidate, 3> preferred_formats;
|
||||
FixedVector<FormatCandidate, 6> 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 });
|
||||
|
||||
// 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 });
|
||||
// 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 });
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
@@ -418,6 +418,7 @@ private:
|
||||
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<VkImage> images;
|
||||
TightLocalVector<VkImageView> image_views;
|
||||
TightLocalVector<VkSemaphore> present_semaphores;
|
||||
@@ -432,7 +433,7 @@ private:
|
||||
#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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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<DisplayServerEnums::WindowID, WindowData> &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<WaylandThread::Message> msg = wayland_thread.pop_message();
|
||||
|
||||
@@ -1846,6 +1995,15 @@ void DisplayServerWayland::process_events() {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Ref<WaylandThread::ColorProfileMessage> 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) {
|
||||
|
||||
@@ -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 @@ public:
|
||||
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<Resource> &p_cursor, DisplayServerEnums::CursorShape p_shape, const Vector2 &p_hotspot) override;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<DisplayServerEnums::WindowID, WindowState> &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<float>(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<uint32_t>(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<DisplayServerEnums::WindowID, WindowState> &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);
|
||||
}
|
||||
|
||||
@@ -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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
// 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 @@ public:
|
||||
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<struct godot_embedded_client *> clients;
|
||||
|
||||
@@ -744,6 +778,31 @@ private:
|
||||
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 @@ private:
|
||||
};
|
||||
|
||||
// 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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
void primary_set_text(const String &p_text);
|
||||
|
||||
bool supports_hdr() const;
|
||||
|
||||
void commit_surfaces();
|
||||
|
||||
void set_frame();
|
||||
|
||||
Vendored
+3
-1
@@ -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`
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Color management and HDR protocol
|
||||
|
||||
Maintainers:
|
||||
Sebastian Wick <sebastian at sebastianwick.net>
|
||||
Pekka Paalanen <pekka.paalanen@collabora.com>
|
||||
|
||||
|
||||
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
|
||||
+1724
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user