From 0708828ad573f2df3c3c717b70f7d5c692658e5c Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Fri, 13 Dec 2024 20:05:58 +0300 Subject: [PATCH 01/12] xx-color-management-v4 initial support --- CMakeLists.txt | 1 + protocols/meson.build | 1 + protocols/xx-color-management-v4.xml | 1453 ++++++++++++++++++++++++++ src/config/ConfigDescriptions.hpp | 24 + src/config/ConfigManager.cpp | 6 + src/desktop/WLSurface.hpp | 15 +- src/managers/ProtocolManager.cpp | 5 + src/protocols/ColorManagement.cpp | 152 +++ src/protocols/ColorManagement.hpp | 80 ++ src/protocols/core/Compositor.cpp | 2 +- src/render/Renderer.cpp | 51 + 11 files changed, 1783 insertions(+), 7 deletions(-) create mode 100644 protocols/xx-color-management-v4.xml create mode 100644 src/protocols/ColorManagement.cpp create mode 100644 src/protocols/ColorManagement.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index aa0d4b030dd..4d454844921 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -317,6 +317,7 @@ protocolnew("protocols" "kde-server-decoration" true) protocolnew("protocols" "wlr-data-control-unstable-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolnew("protocols" "xx-color-management-v4" true) protocolnew("protocols" "wayland-drm" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) diff --git a/protocols/meson.build b/protocols/meson.build index 2c0d06d1221..7a8973a242b 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -33,6 +33,7 @@ protocols = [ 'wayland-drm.xml', 'wlr-data-control-unstable-v1.xml', 'wlr-screencopy-unstable-v1.xml', + 'xx-color-management-v4.xml', hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', diff --git a/protocols/xx-color-management-v4.xml b/protocols/xx-color-management-v4.xml new file mode 100644 index 00000000000..eab84dfd992 --- /dev/null +++ b/protocols/xx-color-management-v4.xml @@ -0,0 +1,1453 @@ + + + + Copyright 2019 Sebastian Wick + Copyright 2019 Erwin Burema + Copyright 2020 AMD + Copyright 2020-2024 Collabora, Ltd. + Copyright 2024 Xaver Hugl + + 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. Doing this enables a compositor + to perform automatic color management of content for different outputs + according to how content is intended to look like. + + 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 includes SDR and HDR colorimetry and encoding, HDR + metadata, and viewing environment parameters. 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. + + Recommendation ITU-T H.273 + "Coding-independent code points for video signal type identification" + shall be referred to as simply H.273 here. + + 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. + + + + + A 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. + + + + + Destroy the xx_color_manager_v4 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. + + + + + + + + + + + + + + + + + + + + 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. H.273 + is the authority, when it comes to the exact values of primaries and + authoritative specifications, where an equivalent code point exists. + + Descriptions do list the specifications for convenience. + + + + + 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 + Equivalent to H.273 ColourPrimaries code point 1. + + + + + 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) + Equivalent to H.273 ColourPrimaries code point 4. + + + + + 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 + Equivalent to H.273 ColourPrimaries code point 5. + + + + + 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) + Equivalent to H.273 ColourPrimaries code point 6 and 7. + + + + + Color primaries as defined by H.273 for generic film. + Equivalent to H.273 ColourPrimaries code point 8. + + + + + Color primaries as defined by + - Rec. ITU-R BT.2020-2 + - Rec. ITU-R BT.2100-0 + Equivalent to H.273 ColourPrimaries code point 9. + + + + + 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) + Equivalent to H.273 ColourPrimaries code point 10. + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE RP 431-2 (2011). Equivalent to H.273 ColourPrimaries code point + 11. + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE EG 432-1 (2010). + Equivalent to H.273 ColourPrimaries code point 12. + + + + + Color primaries as defined by Adobe as "Adobe RGB" and later published + by ISO 12640-4 (2011). + + + + + + + Named transfer functions used to encode well-known transfer + characteristics. H.273 is the authority, when it comes to the exact + formulas and authoritative specifications, where an equivalent code + point exists. + + Descriptions do list the specifications for convenience. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.709-6 + - Rec. ITU-R BT.1361-0 conventional colour gamut system (historical) + Equivalent to H.273 TransferCharacteristics code point 1, 6, 14, 15. + + + + + 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 + Equivalent to H.273 TransferCharacteristics code point 4. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.470-6 System B, G (historical) + Equivalent to H.273 TransferCharacteristics code point 5. + + + + + Transfer characteristics as defined by + - SMPTE ST 240 (1999) + Equivalent to H.273 TransferCharacteristics code point 7. + + + + + Linear transfer characteristics. + Equivalent to H.273 TransferCharacteristics code point 8. + + + + + Logarithmic transfer characteristic (100:1 range). + Equivalent to H.273 TransferCharacteristics code point 9. + + + + + Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range). + Equivalent to H.273 TransferCharacteristics code point 10. + + + + + Transfer characteristics as defined by + - IEC 61966-2-4 + Equivalent to H.273 TransferCharacteristics code point 11. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.1361-0 extended colour gamut system (historical) + Equivalent to H.273 TransferCharacteristics code point 12. + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sRGB + Equivalent to H.273 TransferCharacteristics code point 13 with + MatrixCoefficients set to 0. + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sYCC + Equivalent to H.273 TransferCharacteristics code point 13 with + MatrixCoefficients set to anything but 0. + + + + + 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 + Equivalent to H.273 TransferCharacteristics code point 16. + + 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² + + + + + Transfer characteristics as defined by + - SMPTE ST 428-1 (2019) + Equivalent to H.273 TransferCharacteristics code point 17. + + + + + Transfer characteristics as defined by + - ARIB STD-B67 (2015) + - Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system + Equivalent to H.273 TransferCharacteristics code point 18. + + 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² + Note: HLG is a scene referred signal. All absolute luminance values + used here for HLG assume a 1000 cd/m² display. + + + + + + + This creates a new xx_color_management_output_v4 object for the + given wl_output. + + See the xx_color_management_output_v4 interface for more details. + + + + + + + + + If a xx_color_management_surface_v4 object already exists for the given + wl_surface, the protocol error surface_exists is raised. + + This creates a new color xx_color_management_surface_v4 object for the + given wl_surface. + + See the xx_color_management_surface_v4 interface for more details. + + + + + + + + + This creates a new color xx_color_management_feedback_surface_v4 object + for the given wl_surface. + + See the xx_color_management_feedback_surface_v4 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 xx_image_description_v4 object. + + This request can be used when the compositor advertises + xx_color_manager_v4.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 xx_image_description_v4 object. + + This request can be used when the compositor advertises + xx_color_manager_v4.feature.parametric. + Otherwise this request raises the protocol error unsupported_feature. + + + + + + + + When this object is created, it shall immediately send this event once + for each rendering intent the compositor supports. + + + + + + + + When this object is created, it shall immediately send this event once + for each compositor supported feature listed in the enumeration. + + + + + + + + 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. + + + + + + + + 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 xx_color_management_output_v4 describes the color properties of an + output. + + The xx_color_management_output_v4 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 xx_color_management_output_v4 object inert. + + + + + Destroy the color xx_color_management_output_v4 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 xx_image_description_v4 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 xx_color_management_output_v4 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 xx_image_description_v4 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 xx_image_description_v4.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 + xx_image_description_v4.failed event with the low_version cause. + + Otherwise the object shall immediately deliver the ready event. + + + + + + + + + A xx_color_management_surface_v4 allows the client to set the color + space and HDR properties of a surface. + + If the wl_surface associated with the xx_color_management_surface_v4 is + destroyed, the xx_color_management_surface_v4 object becomes inert. + + + + + Destroy the xx_color_management_surface_v4 object and do the same as + unset_image_description. + + + + + + + + + + + + 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 description whose creation gracefully failed (received + xx_image_description_v4.failed) are forbidden in this request, and in + such case the protocol error image_description is raised. + + All image descriptions whose creation succeeded (received + xx_image_description_v4.ready) are allowed and must always be accepted + by the compositor. + + A rendering intent provides the client's preference on how content + colors should be mapped to each output. The render_intent value must + be one advertised by the compositor with + xx_color_manager_v4.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. + + + + + + + + + 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 xx_color_management_feedback_surface_v4 allows the client to get the + preferred color description of a surface. + + If the wl_surface associated with this object is destroyed, the + xx_color_management_feedback_surface_v4 object becomes inert. + + + + + Destroy the xx_color_management_feedback_surface_v4 object. + + + + + + + + + + + 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 is merely a notification. When the 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 + + + + + + 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 xx_image_description_v4 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 xx_color_management_feedback_surface_v4 object + if the client is capable of adapting to image descriptions. + + The created xx_image_description_v4 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 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 + xx_image_description_v4.failed event with the low_version cause, + otherwise the object shall immediately deliver the ready event. + + + + + + + + + This type of object is used for collecting all the information required + to create a xx_image_description_v4 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. + + + + + + + + + + + + + + + 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 xx_image_description_v4.failed event with the + 'unsupported' cause. If a valid image description was created from the + information, the xx_image_description_v4.ready event will eventually + be sent instead. + + This request destroys the xx_image_description_creator_icc_v4 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 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 xx_image_description_v4.failed event on the + created xx_image_description_v4 with the 'operating_system' cause. + + The maximum size of the ICC profile is 4 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 xx_image_description_v4 object + delivers either failed or ready event; or + - if create request was not issued, this + xx_image_description_creator_icc_v4 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 + xx_image_description_v4.failed event on the created + xx_image_description_v4 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 xx_image_description_v4 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 + - 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. + + + + + + + + + + + + + + + + + + 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. + + Also, the combination of the parameter set is verified. If the set is + not consistent, the protocol error inconsistent_set is raised. + + If the particular combination of the parameter set is not supported + by the compositor, the resulting image description object shall + immediately deliver the xx_image_description_v4.failed event with the + 'unsupported' cause. If a valid image description was created from the + parameter set, the xx_image_description_v4.ready event will eventually + be sent instead. + + This request destroys the xx_image_description_creator_params_v4 + 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 encoded and decoded according to the industry standard + practices for the transfer characteristic. + + Only names advertised with xx_color_manager_v4 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. This curve represents the conversion from electrical + to optical pixel or color values. + + When the resulting image description is attached to an image, the + content should be encoded with the inverse of the power curve. + + 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 + xx_color_manager_v4.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 xx_color_manager_v4 event + supported_primaries_named are allowed. Other values shall raise the + protocol error invalid_primaries. + + 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 10000 to get the argument value + to carry precision of 4 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 + xx_color_manager_v4.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. + + The default luminances 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. + + '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. + + If 'max_lum' is less than the 'reference_lum', or 'reference_lum' is + 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 + xx_color_manager_v4.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 define the target color volume. + + If mastering display primaries are not explicitly set, the target color + volume is assumed to be equal to 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 10000 to get the argument value + to carry precision of 4 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 + xx_color_manager_v4.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 + xx_color_manager_v4.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. This is + compatible with the SMPTE ST 2086 definition of HDR static metadata. + + The mastering luminance range is undefined by default. + + 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. + + + + + + + + + Sets the maximum content light level (max_cll) as defined by CTA-861-H. + + This can only be set when set_tf_cicp is used to set the transfer + characteristic to Rec. ITU-R BT.2100-2 perceptual quantization system. + Otherwise, 'create' request shall raise inconsistent_set protocol + error. + + max_cll is undefined by default. + + + + + + + + Sets the maximum frame-average light level (max_fall) as defined by + CTA-861-H. + + This can only be set when set_tf_cicp is used to set the transfer + characteristic to Rec. ITU-R BT.2100-2 perceptual quantization system. + Otherwise, 'create' request shall raise inconsistent_set protocol error. + + max_fall is undefined by default. + + + + + + + + + An image description carries information about the color encoding used on + a surface when attached to a wl_surface via + xx_color_management_surface_v4.set_image_description. A compositor can use + this information to decode pixel values into colorimetrically meaningful + quantities. + + Note, that the xx_image_description_v4 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 + xx_image_description_v4 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 xx_image_description_v4 object has no side-effects, not + even if a xx_color_management_surface_v4.set_image_description has not + yet been followed by a wl_surface.commit. + + + + + + + + + + + + + + + + + + + + + + If creating a xx_image_description_v4 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 xx_image_description_v4 object will + never become ready and it can only be destroyed. + + + + + + + + + Once this event has been sent, the xx_image_description_v4 object is + deemed "ready". Ready objects can be used to send requests and can be + used through other interfaces. + + Every ready xx_image_description_v4 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. + + 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. + + 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. + + This identity allows clients to de-duplicate image description records + and avoid get_information request if they already have the image + description information. + + + + + + + + Creates a xx_image_description_info_v4 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. + + + + + + + + + Sends all matching events describing an image description object exactly + once and finally sends the 'done' event. + + Once a xx_image_description_info_v4 object has delivered a 'done' event it + is automatically destroyed. + + Every xx_image_description_info_v4 created from the same + xx_image_description_v4 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 10000 to get the argument value + to carry precision of 4 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. + + 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 10000 to get the argument value + to carry precision of 4 decimals. + + + + + + + + + + + + + + + Provides the luminance range that the image description is targeting as + the minimum and maximum absolute luminance L. This is 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. + + + + + + diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index a9ac223a486..3e45d1a6130 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1622,4 +1622,28 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "experimental:wide_color_gamut", + .description = "force wide color gamut for all supported outputs", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "experimental:hdr", + .description = "force static hdr for all supported outputs", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "experimental:hdr_sdr_brightness", + .description = "force sdr brightness with hdr for all supported outputs", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.5, 0, 1}, + }, + SConfigOptionDescription{ + .value = "experimental:xx_color_management_v4", + .description = "enable color management protocol", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, }; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b53ed4d9307..55d60b2e1ba 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -611,6 +612,11 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("ecosystem:no_update_news", Hyprlang::INT{0}); + m_pConfig->addConfigValue("experimental:wide_color_gamut", Hyprlang::INT{0}); + m_pConfig->addConfigValue("experimental:hdr", Hyprlang::INT{0}); + m_pConfig->addConfigValue("experimental:hdr_sdr_brightness", Hyprlang::FLOAT{0.5}); + m_pConfig->addConfigValue("experimental:xx_color_management_v4", Hyprlang::INT{0}); + // devices m_pConfig->addSpecialCategory("device", {"name"}); m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F}); diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index a962b882c21..603b12d4f6d 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -8,6 +8,7 @@ class CSubsurface; class CPopup; class CPointerConstraint; class CWLSurfaceResource; +class CXxColorManagementSurfaceV4; class CWLSurface { public: @@ -95,14 +96,15 @@ class CWLSurface { private: CWLSurface() = default; - bool m_bInert = true; + bool m_bInert = true; - WP m_pResource; + WP m_pResource; - PHLWINDOWREF m_pWindowOwner; - PHLLSREF m_pLayerOwner; - CPopup* m_pPopupOwner = nullptr; - CSubsurface* m_pSubsurfaceOwner = nullptr; + PHLWINDOWREF m_pWindowOwner; + PHLLSREF m_pLayerOwner; + CPopup* m_pPopupOwner = nullptr; + CSubsurface* m_pSubsurfaceOwner = nullptr; + CXxColorManagementSurfaceV4* m_pCMSurface = nullptr; // WP m_pConstraint; @@ -116,4 +118,5 @@ class CWLSurface { } listeners; friend class CPointerConstraint; + friend class CXxColorManagerV4; }; \ No newline at end of file diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index cf517b22a44..3dbc2d83278 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -58,6 +58,7 @@ #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" #include "../Compositor.hpp" +#include "protocols/ColorManagement.hpp" #include #include @@ -81,6 +82,7 @@ void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) { CProtocolManager::CProtocolManager() { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static const auto PENABLEXXCM = CConfigValue("experimental:xx_color_management_v4"); // Outputs are a bit dumb, we have to agree. static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { @@ -160,6 +162,9 @@ CProtocolManager::CProtocolManager() { PROTO::securityContext = std::make_unique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); PROTO::ctm = std::make_unique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); + if (*PENABLEXXCM) + PROTO::colorManagement = std::make_unique(&xx_color_manager_v4_interface, 1, "ColorManagement"); + for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) continue; diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp new file mode 100644 index 00000000000..ddcbab7f104 --- /dev/null +++ b/src/protocols/ColorManagement.cpp @@ -0,0 +1,152 @@ +#include "ColorManagement.hpp" +#include "xx-color-management-v4.hpp" + +CColorManager::CColorManager(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_PARAMETRIC); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_EXTENDED_TARGET_VOLUME); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_PRIMARIES); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_LUMINANCES); + + resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_SRGB); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_NTSC); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM); + resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_BT2020); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB); + + // resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22); + resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB); + resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ); + // resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR); + + resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL); + // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE); + // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_ABSOLUTE); + // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE_BPC); + + resource->setDestroy([](CXxColorManagerV4* r) { LOGM(LOG, "Destroy xx_color_manager at {:x} (generated default)", (void*)r); }); + resource->setGetOutput([](CXxColorManagerV4* r, uint32_t id, wl_resource* output) { + LOGM(LOG, "Get output for id={}, output={}", id, (void*)output); + const auto RESOURCE = + PROTO::colorManagement->m_vOutputs.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vOutputs.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); + resource->setGetSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { LOGM(LOG, "Get surface for id={}, surface={} (FIXME: stub)", id, (void*)surface); }); + resource->setGetFeedbackSurface( + [](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { LOGM(LOG, "Get feedback surface for id={}, surface={} (FIXME: stub)", id, (void*)surface); }); + resource->setNewIccCreator([](CXxColorManagerV4* r, uint32_t id) { + LOGM(LOG, "New ICC creator for id={} (unsupported)", id); + wl_resource_post_error(r->resource(), XX_COLOR_MANAGER_V4_ERROR_UNSUPPORTED_FEATURE, "ICC profiles are not supported"); + }); + resource->setNewParametricCreator([](CXxColorManagerV4* r, uint32_t id) { LOGM(LOG, "New parametric creator for id={} (FIXME: stub)", id); }); + + resource->setOnDestroy([this](CXxColorManagerV4* r) { PROTO::colorManagement->destroyResource(this); }); +} + +bool CColorManager::good() { + return resource->resource(); +} + +CColorManagementOutput::CColorManagementOutput(SP resource_) : resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CXxColorManagementOutputV4* r) { PROTO::colorManagement->destroyResource(this); }); + resource->setOnDestroy([this](CXxColorManagementOutputV4* r) { PROTO::colorManagement->destroyResource(this); }); + + resource->setGetImageDescription([this](CXxColorManagementOutputV4* r, uint32_t id) { + LOGM(LOG, "Get image description for output={}, id={}", (void*)r, id); + if (m_imageDescription) + delete m_imageDescription; + + m_imageDescription = new CColorManagementImageDescription(makeShared(r->client(), r->version(), id), this->self); + + if (!m_imageDescription->good()) { + r->noMemory(); + delete m_imageDescription; + return; + } + }); +} + +CColorManagementOutput::~CColorManagementOutput() { + if (m_imageDescription) + delete m_imageDescription; +} + +bool CColorManagementOutput::good() { + return resource->resource(); +} + +wl_client* CColorManagementOutput::client() { + return pClient; +} + +CColorManagementImageDescription::CColorManagementImageDescription(SP resource_, WP output) : resource(resource_), m_Output(output) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CXxImageDescriptionV4* r) { + // m_Output->resource->sendImageDescriptionChanged(); + if (m_Output->m_imageDescription) + delete m_Output->m_imageDescription; + }); + resource->setOnDestroy([this](CXxImageDescriptionV4* r) { + // m_Output->resource->sendImageDescriptionChanged(); + if (m_Output->m_imageDescription) + delete m_Output->m_imageDescription; + }); + + resource->setGetInformation([](CXxImageDescriptionV4* r, uint32_t id) { LOGM(LOG, "Get image information for image={}, id={} (FIXME: stub)", (void*)r, id); }); +} + +bool CColorManagementImageDescription::good() { + return resource->resource(); +} + +wl_client* CColorManagementImageDescription::client() { + return pClient; +} + +CColorManagementProtocol::CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(LOG, "New xx_color_manager at {:x}", (uintptr_t)RESOURCE.get()); +} + +void CColorManagementProtocol::destroyResource(CColorManager* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementOutput* resource) { + std::erase_if(m_vOutputs, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp new file mode 100644 index 00000000000..a227646e1fa --- /dev/null +++ b/src/protocols/ColorManagement.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "xx-color-management-v4.hpp" + +class CColorManager; +class CColorManagementOutput; +class CColorManagementImageDescription; +class CColorManagementProtocol; + +class CColorManager { + public: + CColorManager(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CColorManagementOutput { + public: + CColorManagementOutput(SP resource_); + ~CColorManagementOutput(); + + bool good(); + wl_client* client(); + + WP self; + + private: + SP resource; + wl_client* pClient = nullptr; + + CColorManagementImageDescription* m_imageDescription = nullptr; + + friend class CColorManagementProtocol; + friend class CColorManagementImageDescription; +}; + +class CColorManagementImageDescription { + public: + CColorManagementImageDescription(SP resource_, WP output); + + bool good(); + wl_client* client(); + + private: + SP resource; + wl_client* pClient = nullptr; + + WP m_Output; + + friend class CColorManagementOutput; +}; + +class CColorManagementProtocol : public IWaylandProtocol { + public: + CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CColorManager* resource); + void destroyResource(CColorManagementOutput* resource); + + std::vector> m_vManagers; + std::vector> m_vOutputs; + + friend class CColorManager; + friend class CColorManagementOutput; + friend class CColorManagementImageDescription; +}; + +namespace PROTO { + inline UP colorManagement; +}; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 89f2a4cbcfe..28cb7e1a4a1 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -449,7 +449,7 @@ void CWLSurfaceResource::commitPendingState() { // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. if (current.buffer->buffer->isSynchronous()) { - dropCurrentBuffer(); + //dropCurrentBuffer(); dropPendingBuffer(); // pending atm is just a copied ref of the current, drop it too to send a release } } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 4edd5a0ce62..e469c2a95e9 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" @@ -1523,6 +1524,46 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) { } } +static const auto BT709 = Aquamarine::IOutput::SChromaticityCoords{ + .red = Aquamarine::IOutput::xy{0.64, 0.33}, + .green = Aquamarine::IOutput::xy{0.30, 0.60}, + .blue = Aquamarine::IOutput::xy{0.15, 0.06}, + .white = Aquamarine::IOutput::xy{0.3127, 0.3290}, +}; + +const hdr_output_metadata createHDRMetadataFromEdid(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid, float brightness = 1) { + if (eotf == 0) { + return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR + } + const auto toNits = [](float value) { return uint16_t(std::round(value)); }; + const auto to16Bit = [](float value) { return uint16_t(std::round(value * 50000)); }; + const auto colorimetry = edid.chromaticityCoords.value_or(BT709); + + Debug::log(TRACE, "primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, colorimetry.blue.y, + colorimetry.white.x, colorimetry.white.y); + Debug::log(TRACE, "max avg {}, min {}, max {}, brightness {}", edid.hdrMetadata->desiredMaxFrameAverageLuminance, edid.hdrMetadata->desiredContentMinLuminance, + edid.hdrMetadata->desiredContentMaxLuminance, brightness); + return hdr_output_metadata{ + .metadata_type = 0, + .hdmi_metadata_type1 = + hdr_metadata_infoframe{ + .eotf = uint8_t(eotf), + .metadata_type = 0, + .display_primaries = + { + {to16Bit(colorimetry.red.x), to16Bit(colorimetry.red.y)}, + {to16Bit(colorimetry.green.x), to16Bit(colorimetry.green.y)}, + {to16Bit(colorimetry.blue.x), to16Bit(colorimetry.blue.y)}, + }, + .white_point = {to16Bit(colorimetry.white.x), to16Bit(colorimetry.white.y)}, + .max_display_mastering_luminance = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance * brightness), + .min_display_mastering_luminance = toNits(edid.hdrMetadata->desiredContentMinLuminance * 10000 * brightness), + .max_cll = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance * brightness), + .max_fall = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance * brightness), + }, + }; +} + bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { // apply timelines for explicit sync // save inFD otherwise reset will reset it @@ -1531,6 +1572,16 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { if (inFD >= 0) pMonitor->output->state->setExplicitInFence(inFD); + static auto PWIDE = CConfigValue("experimental:wide_color_gamut"); + if (pMonitor->output->state->state().wideColorGamut != *PWIDE) + Debug::log(TRACE, "Setting wide color gamut {}", *PWIDE ? "on" : "off"); + pMonitor->output->state->setWideColorGamut(*PWIDE); + + static auto PHDR = CConfigValue("experimental:hdr"); + static auto PHDR_SDR = CConfigValue("experimental:hdr_sdr_brightness"); + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadataFromEdid(2, pMonitor->output->parsedEDID, *PHDR_SDR) : + createHDRMetadataFromEdid(0, pMonitor->output->parsedEDID)); + if (pMonitor->ctmUpdated) { pMonitor->ctmUpdated = false; pMonitor->output->state->setCTM(pMonitor->ctm); From 7e1801748a8ccecde68922800378210cf63d0cbd Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Sat, 14 Dec 2024 14:46:50 +0300 Subject: [PATCH 02/12] clang tidy --- src/render/Renderer.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index e469c2a95e9..ea4cd21ea88 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1525,13 +1525,13 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) { } static const auto BT709 = Aquamarine::IOutput::SChromaticityCoords{ - .red = Aquamarine::IOutput::xy{0.64, 0.33}, - .green = Aquamarine::IOutput::xy{0.30, 0.60}, - .blue = Aquamarine::IOutput::xy{0.15, 0.06}, - .white = Aquamarine::IOutput::xy{0.3127, 0.3290}, + .red = Aquamarine::IOutput::xy{.x = 0.64, .y = 0.33}, + .green = Aquamarine::IOutput::xy{.x = 0.30, .y = 0.60}, + .blue = Aquamarine::IOutput::xy{.x = 0.15, .y = 0.06}, + .white = Aquamarine::IOutput::xy{.x = 0.3127, .y = 0.3290}, }; -const hdr_output_metadata createHDRMetadataFromEdid(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid, float brightness = 1) { +static hdr_output_metadata createHDRMetadataFromEdid(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid, float brightness = 1) { if (eotf == 0) { return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR } @@ -1547,15 +1547,15 @@ const hdr_output_metadata createHDRMetadataFromEdid(uint8_t eotf, Aquamarine::IO .metadata_type = 0, .hdmi_metadata_type1 = hdr_metadata_infoframe{ - .eotf = uint8_t(eotf), + .eotf = eotf, .metadata_type = 0, .display_primaries = { - {to16Bit(colorimetry.red.x), to16Bit(colorimetry.red.y)}, - {to16Bit(colorimetry.green.x), to16Bit(colorimetry.green.y)}, - {to16Bit(colorimetry.blue.x), to16Bit(colorimetry.blue.y)}, + {.x = to16Bit(colorimetry.red.x), .y = to16Bit(colorimetry.red.y)}, + {.x = to16Bit(colorimetry.green.x), .y = to16Bit(colorimetry.green.y)}, + {.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)}, }, - .white_point = {to16Bit(colorimetry.white.x), to16Bit(colorimetry.white.y)}, + .white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)}, .max_display_mastering_luminance = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance * brightness), .min_display_mastering_luminance = toNits(edid.hdrMetadata->desiredContentMinLuminance * 10000 * brightness), .max_cll = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance * brightness), From 4254f968b464c577d4f3b9059d7b089f86c6923b Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Sat, 14 Dec 2024 23:04:19 +0300 Subject: [PATCH 03/12] implement most stuff & debug logging --- protocols/xx-color-management-v4.xml | 294 ++++++++++++----------- src/managers/ProtocolManager.cpp | 1 + src/protocols/ColorManagement.cpp | 346 ++++++++++++++++++++++++--- src/protocols/ColorManagement.hpp | 133 ++++++++-- src/protocols/core/Compositor.hpp | 2 + 5 files changed, 580 insertions(+), 196 deletions(-) diff --git a/protocols/xx-color-management-v4.xml b/protocols/xx-color-management-v4.xml index eab84dfd992..23ff716ed2f 100644 --- a/protocols/xx-color-management-v4.xml +++ b/protocols/xx-color-management-v4.xml @@ -20,7 +20,7 @@ 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 + 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 @@ -83,9 +83,9 @@ + summary="request not supported" /> + summary="color management surface exists already" /> @@ -101,30 +101,30 @@ + summary="perceptual" /> + summary="media-relative colorimetric" /> + summary="saturation" /> + summary="ICC-absolute colorimetric" /> + summary="media-relative colorimetric + black point compensation" /> - + + summary="new_icc_creator request" /> + summary="new_parametric_creator request" /> + summary="parametric set_primaries request" /> + summary="parametric set_tf_power request" /> + summary="parametric set_luminances request" /> The compositor supports set_mastering_display_primaries request with a @@ -152,15 +152,16 @@ - + 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) + 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 + (1993) Annex B Equivalent to H.273 ColourPrimaries code point 1. @@ -169,9 +170,9 @@ 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 + Recommendation for transmission standards for color television - United States Federal Communications Commission (2003) Title 47 Code - of Federal Regulations 73.682 (a)(20) + of Federal Regulations 73.682 (a)(20) Equivalent to H.273 ColourPrimaries code point 4. @@ -220,21 +221,24 @@ - + Color primaries as defined by Digital Cinema System and published in SMPTE RP 431-2 (2011). Equivalent to H.273 ColourPrimaries code point 11. - + Color primaries as defined by Digital Cinema System and published in SMPTE EG 432-1 (2010). Equivalent to H.273 ColourPrimaries code point 12. - + Color primaries as defined by Adobe as "Adobe RGB" and later published by ISO 12640-4 (2011). @@ -264,9 +268,9 @@ 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 + Recommendation for transmission standards for color television - United States Federal Communications Commission (2003) Title 47 Code - of Federal Regulations 73.682 (a) (20) + of Federal Regulations 73.682 (a) (20) - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM Equivalent to H.273 TransferCharacteristics code point 4. @@ -378,8 +382,8 @@ See the xx_color_management_output_v4 interface for more details. - - + + @@ -393,8 +397,8 @@ See the xx_color_management_surface_v4 interface for more details. - - + + @@ -407,8 +411,8 @@ - + interface="xx_color_management_feedback_surface_v4" /> + @@ -424,8 +428,8 @@ + type="new_id" interface="xx_image_description_creator_icc_v4" + summary="the new creator object" /> @@ -441,8 +445,8 @@ + type="new_id" interface="xx_image_description_creator_params_v4" + summary="the new creator object" /> @@ -452,7 +456,7 @@ + summary="rendering intent" /> @@ -462,7 +466,7 @@ + summary="supported feature" /> @@ -473,7 +477,7 @@ + summary="Named transfer function" /> @@ -484,7 +488,7 @@ + summary="Named color primaries" /> @@ -554,17 +558,17 @@ + type="new_id" interface="xx_image_description_v4" /> - A xx_color_management_surface_v4 allows the client to set the color - space and HDR properties of a surface. + A xx_color_management_surface_v4 allows the client to set the color + space and HDR properties of a surface. - If the wl_surface associated with the xx_color_management_surface_v4 is - destroyed, the xx_color_management_surface_v4 object becomes inert. + If the wl_surface associated with the xx_color_management_surface_v4 is + destroyed, the xx_color_management_surface_v4 object becomes inert. @@ -575,11 +579,11 @@ - + + summary="unsupported rendering intent" /> + summary="invalid image description" /> @@ -615,10 +619,10 @@ + type="object" interface="xx_image_description_v4" /> + type="uint" enum="xx_color_manager_v4.render_intent" + summary="rendering intent" /> @@ -633,11 +637,11 @@ - A xx_color_management_feedback_surface_v4 allows the client to get the - preferred color description of a surface. + A xx_color_management_feedback_surface_v4 allows the client to get the + preferred color description of a surface. - If the wl_surface associated with this object is destroyed, the - xx_color_management_feedback_surface_v4 object becomes inert. + If the wl_surface associated with this object is destroyed, the + xx_color_management_feedback_surface_v4 object becomes inert. @@ -647,9 +651,9 @@ - + + summary="forbidden request on inert object" /> @@ -704,7 +708,7 @@ + type="new_id" interface="xx_image_description_v4" /> @@ -727,18 +731,18 @@ - + + summary="incomplete parameter set" /> + summary="property already set" /> + summary="fd not seekable and readable" /> + summary="no or too much data" /> + summary="offset + length exceeds file size" /> @@ -765,7 +769,7 @@ + type="new_id" interface="xx_image_description_v4" /> @@ -788,9 +792,9 @@ 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 xx_image_description_v4 object - delivers either failed or ready event; or + delivers either failed or ready event; or - if create request was not issued, this - xx_image_description_creator_icc_v4 object is destroyed. + xx_image_description_creator_icc_v4 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 @@ -812,11 +816,11 @@ + summary="ICC profile" /> + summary="byte offset in fd to start of ICC data" /> + summary="length of ICC data in bytes" /> @@ -849,24 +853,24 @@ - + + summary="incomplete parameter set" /> + summary="invalid combination of parameters" /> + summary="property already set" /> + summary="request not supported" /> + summary="invalid transfer characteristic" /> + summary="invalid primaries or white point" /> + summary="invalid luminance value or range" /> + summary="invalid mastering information" /> @@ -896,7 +900,7 @@ + type="new_id" interface="xx_image_description_v4" /> @@ -916,7 +920,7 @@ + summary="named transfer function" /> @@ -942,7 +946,7 @@ the protocol error unsupported_feature. - + @@ -960,7 +964,7 @@ + summary="named primaries" /> @@ -980,14 +984,14 @@ the protocol error unsupported_feature. - - - - - - - - + + + + + + + + @@ -1036,11 +1040,11 @@ + summary="minimum luminance (cd/m²) * 10000" /> + summary="maximum luminance (cd/m²)" /> + summary="reference white luminance (cd/m²)" /> @@ -1092,14 +1096,14 @@ description gracefully, but it may as well result in color artifacts. - - - - - - - - + + + + + + + + @@ -1117,8 +1121,8 @@ and carry precision of 4 decimals. Max L value is unscaled for max_lum. - - + + @@ -1133,7 +1137,7 @@ max_cll is undefined by default. - + @@ -1148,7 +1152,7 @@ max_fall is undefined by default. - + @@ -1186,25 +1190,25 @@ - + + summary="attempted to use an object which is not ready" /> + summary="get_information not allowed" /> - + + summary="interface version too low" /> + summary="unsupported image description data" /> + summary="error independent of the client" /> + summary="the relevant output no longer exists" /> @@ -1222,9 +1226,9 @@ + summary="generic reason" /> + summary="ad hoc human-readable explanation" /> @@ -1257,7 +1261,7 @@ description information. - + @@ -1272,7 +1276,7 @@ + type="new_id" interface="xx_image_description_info_v4" /> @@ -1306,8 +1310,8 @@ kind of a profile. - - + + @@ -1320,14 +1324,14 @@ to carry precision of 4 decimals. - - - - - - - - + + + + + + + + @@ -1337,7 +1341,7 @@ + summary="named primaries" /> @@ -1351,7 +1355,7 @@ value to carry the precision of 4 decimals. - + @@ -1361,7 +1365,7 @@ + summary="named transfer function" /> @@ -1375,11 +1379,11 @@ + summary="minimum luminance (cd/m²) * 10000" /> + summary="maximum luminance (cd/m²)" /> + summary="reference white luminance (cd/m²)" /> @@ -1397,14 +1401,14 @@ to carry precision of 4 decimals. - - - - - - - - + + + + + + + + @@ -1420,8 +1424,8 @@ carry precision of 4 decimals. Max L value is unscaled for max_lum. - - + + @@ -1434,7 +1438,7 @@ + summary="Maximum content light-level (cd/m²)" /> @@ -1447,7 +1451,7 @@ + summary="Maximum frame-average light level (cd/m²)" /> - + \ No newline at end of file diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 3dbc2d83278..f8aedfe46ff 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -62,6 +62,7 @@ #include #include +#include void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) { const bool ISMIRROR = pMonitor->isMirror(); diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index ddcbab7f104..58050f99e36 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -32,9 +32,9 @@ CColorManager::CColorManager(SP resource_) : resource(resourc // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_ABSOLUTE); // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE_BPC); - resource->setDestroy([](CXxColorManagerV4* r) { LOGM(LOG, "Destroy xx_color_manager at {:x} (generated default)", (void*)r); }); + resource->setDestroy([](CXxColorManagerV4* r) { LOGM(TRACE, "Destroy xx_color_manager at {:x} (generated default)", (uintptr_t)r); }); resource->setGetOutput([](CXxColorManagerV4* r, uint32_t id, wl_resource* output) { - LOGM(LOG, "Get output for id={}, output={}", id, (void*)output); + LOGM(TRACE, "Get output for id={}, output={}", id, (uintptr_t)output); const auto RESOURCE = PROTO::colorManagement->m_vOutputs.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); @@ -46,14 +46,72 @@ CColorManager::CColorManager(SP resource_) : resource(resourc RESOURCE->self = RESOURCE; }); - resource->setGetSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { LOGM(LOG, "Get surface for id={}, surface={} (FIXME: stub)", id, (void*)surface); }); - resource->setGetFeedbackSurface( - [](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { LOGM(LOG, "Get feedback surface for id={}, surface={} (FIXME: stub)", id, (void*)surface); }); + resource->setGetSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { + LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->colorManagement) { + r->error(XX_COLOR_MANAGER_V4_ERROR_SURFACE_EXISTS, "CM Surface already exists"); + return; + } + + const auto RESOURCE = + PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id), SURF)); + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + SURF->colorManagement = RESOURCE; + }); + resource->setGetFeedbackSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { + LOGM(TRACE, "Get feedback surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + const auto RESOURCE = PROTO::colorManagement->m_vFeedbackSurfaces.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), SURF)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vFeedbackSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); resource->setNewIccCreator([](CXxColorManagerV4* r, uint32_t id) { - LOGM(LOG, "New ICC creator for id={} (unsupported)", id); - wl_resource_post_error(r->resource(), XX_COLOR_MANAGER_V4_ERROR_UNSUPPORTED_FEATURE, "ICC profiles are not supported"); + LOGM(WARN, "New ICC creator for id={} (unsupported)", id); + r->error(XX_COLOR_MANAGER_V4_ERROR_UNSUPPORTED_FEATURE, "ICC profiles are not supported"); + }); + resource->setNewParametricCreator([](CXxColorManagerV4* r, uint32_t id) { + LOGM(TRACE, "New parametric creator for id={}", id); + + const auto RESOURCE = PROTO::colorManagement->m_vParametricCreators.emplace_back( + makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vParametricCreators.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; }); - resource->setNewParametricCreator([](CXxColorManagerV4* r, uint32_t id) { LOGM(LOG, "New parametric creator for id={} (FIXME: stub)", id); }); resource->setOnDestroy([this](CXxColorManagerV4* r) { PROTO::colorManagement->destroyResource(this); }); } @@ -72,23 +130,21 @@ CColorManagementOutput::CColorManagementOutput(SP re resource->setOnDestroy([this](CXxColorManagementOutputV4* r) { PROTO::colorManagement->destroyResource(this); }); resource->setGetImageDescription([this](CXxColorManagementOutputV4* r, uint32_t id) { - LOGM(LOG, "Get image description for output={}, id={}", (void*)r, id); - if (m_imageDescription) - delete m_imageDescription; + LOGM(TRACE, "Get image description for output={}, id={}", (uintptr_t)r, id); + if (imageDescription.valid()) + PROTO::colorManagement->destroyResource(imageDescription.get()); - m_imageDescription = new CColorManagementImageDescription(makeShared(r->client(), r->version(), id), this->self); + const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id))); - if (!m_imageDescription->good()) { + if (!RESOURCE->good()) { r->noMemory(); - delete m_imageDescription; + PROTO::colorManagement->m_vImageDescriptions.pop_back(); return; } - }); -} -CColorManagementOutput::~CColorManagementOutput() { - if (m_imageDescription) - delete m_imageDescription; + RESOURCE->self = RESOURCE; + }); } bool CColorManagementOutput::good() { @@ -99,34 +155,246 @@ wl_client* CColorManagementOutput::client() { return pClient; } -CColorManagementImageDescription::CColorManagementImageDescription(SP resource_, WP output) : resource(resource_), m_Output(output) { +CColorManagementSurface::CColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; pClient = resource->client(); - resource->setDestroy([this](CXxImageDescriptionV4* r) { - // m_Output->resource->sendImageDescriptionChanged(); - if (m_Output->m_imageDescription) - delete m_Output->m_imageDescription; + resource->setDestroy([this](CXxColorManagementSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface); + PROTO::colorManagement->destroyResource(this); }); - resource->setOnDestroy([this](CXxImageDescriptionV4* r) { - // m_Output->resource->sendImageDescriptionChanged(); - if (m_Output->m_imageDescription) - delete m_Output->m_imageDescription; + resource->setOnDestroy([this](CXxColorManagementSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface); + PROTO::colorManagement->destroyResource(this); }); - resource->setGetInformation([](CXxImageDescriptionV4* r, uint32_t id) { LOGM(LOG, "Get image information for image={}, id={} (FIXME: stub)", (void*)r, id); }); + resource->setSetImageDescription([](CXxColorManagementSurfaceV4* r, wl_resource* image_description, uint32_t render_intent) { + LOGM(TRACE, "Set image description for surface={}, desc={}, intent={} (FIXME: stub)", (uintptr_t)r, (uintptr_t)image_description, render_intent); + }); + resource->setUnsetImageDescription([](CXxColorManagementSurfaceV4* r) { LOGM(TRACE, "Unset image description for surface={} (FIXME: stub)", (uintptr_t)r); }); } -bool CColorManagementImageDescription::good() { +bool CColorManagementSurface::good() { + return resource->resource(); +} + +wl_client* CColorManagementSurface::client() { + return pClient; +} + +CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP resource_, SP surface_) : + surface(surface_), resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); + PROTO::colorManagement->destroyResource(this); + }); + resource->setOnDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); + PROTO::colorManagement->destroyResource(this); + }); + + resource->setGetPreferred([](CXxColorManagementFeedbackSurfaceV4* r, uint32_t id) { LOGM(TRACE, "Get preferred for id {} (FIXME: stub)", id); }); +} + +bool CColorManagementFeedbackSurface::good() { + return resource->resource(); +} + +wl_client* CColorManagementFeedbackSurface::client() { + return pClient; +} + +CColorManagementParametricCreator::CColorManagementParametricCreator(SP resource_) : resource(resource_) { + if (!good()) + return; + // + pClient = resource->client(); + + resource->setOnDestroy([this](CXxImageDescriptionCreatorParamsV4* r) { PROTO::colorManagement->destroyResource(this); }); + + resource->setCreate([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t id) { + LOGM(TRACE, "Create image description from params for id {}", id); + + // FIXME actually check completeness + if (!this->valuesSet) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCOMPLETE_SET, "Missing required settings"); + return; + } + + // FIXME actually check consistency + if (!this->valuesSet) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCONSISTENT_SET, "Set is not consistent"); + return; + } + + const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vImageDescriptions.pop_back(); + return; + } + + // FIXME actually check support + if (!this->valuesSet) { + RESOURCE->resource()->sendFailed(XX_IMAGE_DESCRIPTION_V4_CAUSE_UNSUPPORTED, "unsupported"); + return; + } + + RESOURCE->self = RESOURCE; + RESOURCE->settings = this->settings; + RESOURCE->resource()->sendReady(id); + + PROTO::colorManagement->destroyResource(this); + }); + resource->setSetTfNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t tf) { + LOGM(TRACE, "Set image description transfer function to {}", tf); + if (this->valuesSet & PC_TF) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function already set"); + return; + } + + switch (tf) { + case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB: break; + case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ: break; + default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF, "Unsupported transfer function"); return; + } + + this->settings.transferFunction = (xxColorManagerV4TransferFunction)tf; + this->valuesSet |= PC_TF; + }); + resource->setSetTfPower([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t eexp) { + LOGM(TRACE, "Set image description tf power to {}", eexp); + if (this->valuesSet & PC_TF_POWER) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function power already set"); + return; + } + this->settings.transferFunctionPower = eexp / 10000.0f; + this->valuesSet |= PC_TF_POWER; + }); + resource->setSetPrimariesNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t primaries) { + LOGM(TRACE, "Set image description primaries by name {} (FIXME: stub)", primaries); + if (this->valuesSet & PC_PRIMARIES) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); + return; + } + + switch (primaries) { + case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB: break; + case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020: break; + default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, "Unsupported primaries"); + } + }); + resource->setSetPrimaries( + [this](CXxImageDescriptionCreatorParamsV4* r, 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) { + LOGM(TRACE, "Set image description primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); + if (this->valuesSet & PC_PRIMARIES) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); + return; + } + this->settings.primaries = + SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; + this->valuesSet |= PC_PRIMARIES; + }); + resource->setSetLuminances([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum) { + auto min = min_lum / 10000.0f; + LOGM(TRACE, "Set image description luminances to {} - {} ({})", min, max_lum, reference_lum); + if (this->valuesSet & PC_LUMINANCES) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Luminances already set"); + return; + } + if (max_lum < reference_lum || reference_lum <= min) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); + return; + } + this->settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum}; + this->valuesSet |= PC_LUMINANCES; + }); + resource->setSetMasteringDisplayPrimaries( + [this](CXxImageDescriptionCreatorParamsV4* r, 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) { + LOGM(TRACE, "Set image description mastering primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); + // if (this->valuesSet & PC_MASTERING_PRIMARIES) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering primaries already set"); + // return; + // } + this->settings.masteringPrimaries = + SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; + this->valuesSet |= PC_MASTERING_PRIMARIES; + }); + resource->setSetMasteringLuminance([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum) { + auto min = min_lum / 10000.0f; + LOGM(TRACE, "Set image description mastering luminances to {} - {}", min, max_lum); + // if (this->valuesSet & PC_MASTERING_LUMINANCES) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering luminances already set"); + // return; + // } + if (min > 0 && max_lum > 0 && max_lum <= min) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); + return; + } + this->settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min, .max = max_lum}; + this->valuesSet |= PC_MASTERING_LUMINANCES; + }); + resource->setSetMaxCll([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_cll) { + LOGM(TRACE, "Set image description max content light level to {}", max_cll); + // if (this->valuesSet & PC_CLL) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max CLL already set"); + // return; + // } + this->settings.maxCLL = max_cll; + this->valuesSet |= PC_CLL; + }); + resource->setSetMaxFall([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_fall) { + LOGM(TRACE, "Set image description max frame-average light level to {}", max_fall); + // if (this->valuesSet & PC_FALL) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max FALL already set"); + // return; + // } + this->settings.maxFALL = max_fall; + this->valuesSet |= PC_FALL; + }); +} + +bool CColorManagementParametricCreator::good() { return resource->resource(); } +wl_client* CColorManagementParametricCreator::client() { + return pClient; +} + +CColorManagementImageDescription::CColorManagementImageDescription(SP resource_) : m_resource(resource_) { + if (!good()) + return; + + pClient = m_resource->client(); + + m_resource->setDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); }); + m_resource->setOnDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); }); + + m_resource->setGetInformation([](CXxImageDescriptionV4* r, uint32_t id) { LOGM(TRACE, "Get image information for image={}, id={} (FIXME: stub)", (uintptr_t)r, id); }); +} + +bool CColorManagementImageDescription::good() { + return m_resource->resource(); +} + wl_client* CColorManagementImageDescription::client() { return pClient; } +SP CColorManagementImageDescription::resource() { + return m_resource; +} + CColorManagementProtocol::CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -140,7 +408,7 @@ void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32 return; } - LOGM(LOG, "New xx_color_manager at {:x}", (uintptr_t)RESOURCE.get()); + LOGM(TRACE, "New xx_color_manager at {:x}", (uintptr_t)RESOURCE.get()); } void CColorManagementProtocol::destroyResource(CColorManager* resource) { @@ -150,3 +418,19 @@ void CColorManagementProtocol::destroyResource(CColorManager* resource) { void CColorManagementProtocol::destroyResource(CColorManagementOutput* resource) { std::erase_if(m_vOutputs, [&](const auto& other) { return other.get() == resource; }); } + +void CColorManagementProtocol::destroyResource(CColorManagementSurface* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementFeedbackSurface* resource) { + std::erase_if(m_vFeedbackSurfaces, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementParametricCreator* resource) { + std::erase_if(m_vParametricCreators, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementImageDescription* resource) { + std::erase_if(m_vImageDescriptions, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp index a227646e1fa..2fb912d9042 100644 --- a/src/protocols/ColorManagement.hpp +++ b/src/protocols/ColorManagement.hpp @@ -4,6 +4,7 @@ #include #include #include "WaylandProtocol.hpp" +#include "protocols/core/Compositor.hpp" #include "xx-color-management-v4.hpp" class CColorManager; @@ -24,35 +25,116 @@ class CColorManager { class CColorManagementOutput { public: CColorManagementOutput(SP resource_); - ~CColorManagementOutput(); - bool good(); - wl_client* client(); + bool good(); + wl_client* client(); - WP self; + WP self; + WP imageDescription; private: - SP resource; - wl_client* pClient = nullptr; - - CColorManagementImageDescription* m_imageDescription = nullptr; + SP resource; + wl_client* pClient = nullptr; friend class CColorManagementProtocol; friend class CColorManagementImageDescription; }; -class CColorManagementImageDescription { +class CColorManagementSurface { public: - CColorManagementImageDescription(SP resource_, WP output); + CColorManagementSurface(SP resource_, SP surface_); - bool good(); - wl_client* client(); + bool good(); + wl_client* client(); + + WP self; + WP surface; private: - SP resource; - wl_client* pClient = nullptr; + SP resource; + wl_client* pClient = nullptr; +}; + +class CColorManagementFeedbackSurface { + public: + CColorManagementFeedbackSurface(SP resource_, SP surface_); + + bool good(); + wl_client* client(); + + WP self; + WP surface; + + private: + SP resource; + wl_client* pClient = nullptr; +}; + +struct SImageDescription { + xxColorManagerV4TransferFunction transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + float transferFunctionPower = 1.0f; + struct SPCPRimaries { + struct { + uint32_t x = 0; + uint32_t y = 0; + } red, green, blue, white; + } primaries, masteringPrimaries; + struct SPCLuminances { + float min = 0.2f; + uint32_t max = 80; + uint32_t reference = 80; + } luminances; + struct SPCMasteringLuminances { + float min = 0.0f; + uint32_t max = 0; + } masteringLuminances; + uint32_t maxCLL = 0; + uint32_t maxFALL = 0; +}; + +class CColorManagementParametricCreator { + public: + CColorManagementParametricCreator(SP resource_); - WP m_Output; + bool good(); + wl_client* client(); + + WP self; + + SImageDescription settings; + + private: + enum eValuesSet : uint32_t { + PC_TF = (1 << 0), + PC_TF_POWER = (1 << 1), + PC_PRIMARIES = (1 << 2), + PC_LUMINANCES = (1 << 3), + PC_MASTERING_PRIMARIES = (1 << 4), + PC_MASTERING_LUMINANCES = (1 << 5), + PC_CLL = (1 << 6), + PC_FALL = (1 << 7), + }; + + SP resource; + wl_client* pClient = nullptr; + uint32_t valuesSet = 0; // enum eValuesSet +}; + +class CColorManagementImageDescription { + public: + CColorManagementImageDescription(SP resource_); + + bool good(); + wl_client* client(); + SP resource(); + + WP self; + + SImageDescription settings; + + private: + SP m_resource; + wl_client* pClient = nullptr; friend class CColorManagementOutput; }; @@ -64,14 +146,25 @@ class CColorManagementProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); private: - void destroyResource(CColorManager* resource); - void destroyResource(CColorManagementOutput* resource); - - std::vector> m_vManagers; - std::vector> m_vOutputs; + void destroyResource(CColorManager* resource); + void destroyResource(CColorManagementOutput* resource); + void destroyResource(CColorManagementSurface* resource); + void destroyResource(CColorManagementFeedbackSurface* resource); + void destroyResource(CColorManagementParametricCreator* resource); + void destroyResource(CColorManagementImageDescription* resource); + + std::vector> m_vManagers; + std::vector> m_vOutputs; + std::vector> m_vSurfaces; + std::vector> m_vFeedbackSurfaces; + std::vector> m_vParametricCreators; + std::vector> m_vImageDescriptions; friend class CColorManager; friend class CColorManagementOutput; + friend class CColorManagementSurface; + friend class CColorManagementFeedbackSurface; + friend class CColorManagementParametricCreator; friend class CColorManagementImageDescription; }; diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index c036041a74a..4174c386693 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -25,6 +25,7 @@ class CWLSurfaceResource; class CWLSubsurfaceResource; class CViewportResource; class CDRMSyncobjSurfaceResource; +class CColorManagementSurface; class CWLCallbackResource { public: @@ -121,6 +122,7 @@ class CWLSurfaceResource { SP role; WP viewportResource; WP syncobj; // may not be present + WP colorManagement; void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); From 507998bc54ff16f228d18cf0ba53689c2c0d5799 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Sun, 15 Dec 2024 22:42:07 +0300 Subject: [PATCH 04/12] add frog cm support --- CMakeLists.txt | 1 + protocols/frog-color-management-v1.xml | 366 +++++++++++++++++++++++++ protocols/meson.build | 1 + src/managers/ProtocolManager.cpp | 10 +- src/protocols/ColorManagement.cpp | 5 +- src/protocols/ColorManagement.hpp | 9 +- src/protocols/FrogColorManagement.cpp | 119 ++++++++ src/protocols/FrogColorManagement.hpp | 56 ++++ src/protocols/core/Compositor.hpp | 2 + src/render/Renderer.cpp | 67 ++++- 10 files changed, 618 insertions(+), 18 deletions(-) create mode 100644 protocols/frog-color-management-v1.xml create mode 100644 src/protocols/FrogColorManagement.cpp create mode 100644 src/protocols/FrogColorManagement.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d454844921..2962443859d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -318,6 +318,7 @@ protocolnew("protocols" "wlr-data-control-unstable-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) protocolnew("protocols" "xx-color-management-v4" true) +protocolnew("protocols" "frog-color-management-v1" true) protocolnew("protocols" "wayland-drm" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) diff --git a/protocols/frog-color-management-v1.xml b/protocols/frog-color-management-v1.xml new file mode 100644 index 00000000000..aab235a7e4f --- /dev/null +++ b/protocols/frog-color-management-v1.xml @@ -0,0 +1,366 @@ + + + + + Copyright © 2023 Joshua Ashton for Valve Software + Copyright © 2023 Xaver Hugl + + 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 this color management extension is to get HDR games working quickly, + and have an easy way to test implementations in the wild before the upstream + protocol is ready to be merged. + For that purpose it's intentionally limited and cut down and does not serve + all uses cases. + + + + + The color management factory singleton creates color managed surface objects. + + + + + + + + + + + + + + + + Interface for changing surface color management and HDR state. + + An implementation must: support every part of the version + of the frog_color_managed_surface interface it exposes. + Including all known enums associated with a given version. + + + + + Destroying the color managed surface resets all known color + state for the surface back to 'undefined' implementation-specific + values. + + + + + + Extended information on the transfer functions described + here can be found in the Khronos Data Format specification: + https://registry.khronos.org/DataFormat/specs/1.3/dataformat.1.3.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extended information on render intents described + here can be found in ICC.1:2022: + + https://www.color.org/specification/ICC.1-2022-05.pdf + + + + + + + NOTE: On a surface with "perceptual" (default) render intent, handling of the container's + color volume + is implementation-specific, and may differ between different transfer functions it is paired + with: + ie. sRGB + 709 rendering may have it's primaries widened to more of the available display's + gamut + to be be more pleasing for the viewer. + Compared to scRGB Linear + 709 being treated faithfully as 709 + (including utilizing negatives out of the 709 gamut triangle) + + + + + + + Forwards HDR metadata from the client to the compositor. + + HDR Metadata Infoframe as per CTA 861.G spec. + + Usage of this HDR metadata is implementation specific and + outside of the scope of this protocol. + + + + Mastering Red Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Red Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Green Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Green Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Blue Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Blue Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering White Point X Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering White Point Y Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Max Mastering Display Luminance. + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + Min Mastering Display Luminance. + This value is coded as an unsigned 16-bit value in units of + 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF + represents 6.5535 cd/m2. + + + + + Max Content Light Level. + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + Max Frame Average Light Level. + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + + + Current preferred metadata for a surface. + The application should use this information to tone-map its buffers + to this target before committing. + + This metadata does not necessarily correspond to any physical output, but + rather what the compositor thinks would be best for a given surface. + + + + Specifies a known transfer function that corresponds to the + output the surface is targeting. + + + + + Output Red Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Red Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Green Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Green Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Blue Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Blue Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output White Point X Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output White Point Y Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Max Output Luminance + The max luminance in nits that the output is capable of rendering in small areas. + Content should: not exceed this value to avoid clipping. + + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + Min Output Luminance + The min luminance that the output is capable of rendering. + Content should: not exceed this value to avoid clipping. + + This value is coded as an unsigned 16-bit value in units of + 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF + represents 6.5535 cd/m2. + + + + + Max Full Frame Luminance + The max luminance in nits that the output is capable of rendering for the + full frame sustained. + + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + \ No newline at end of file diff --git a/protocols/meson.build b/protocols/meson.build index 7a8973a242b..2b39617a986 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -34,6 +34,7 @@ protocols = [ 'wlr-data-control-unstable-v1.xml', 'wlr-screencopy-unstable-v1.xml', 'xx-color-management-v4.xml', + 'frog-color-management-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index f8aedfe46ff..feb4a5d8056 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -54,11 +54,13 @@ #include "../protocols/core/Subcompositor.hpp" #include "../protocols/core/Output.hpp" #include "../protocols/core/Shm.hpp" +#include "../protocols/ColorManagement.hpp" +#include "../protocols/FrogColorManagement.hpp" #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" #include "../Compositor.hpp" -#include "protocols/ColorManagement.hpp" +#include "frog-color-management-v1.hpp" #include #include @@ -163,8 +165,10 @@ CProtocolManager::CProtocolManager() { PROTO::securityContext = std::make_unique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); PROTO::ctm = std::make_unique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); - if (*PENABLEXXCM) - PROTO::colorManagement = std::make_unique(&xx_color_manager_v4_interface, 1, "ColorManagement"); + if (*PENABLEXXCM) { + PROTO::colorManagement = std::make_unique(&xx_color_manager_v4_interface, 1, "ColorManagement"); + PROTO::frogColorManagement = std::make_unique(&frog_color_management_factory_v1_interface, 1, "FrogColorManagement"); + } for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index 58050f99e36..f6f55a8c56e 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -1,5 +1,4 @@ #include "ColorManagement.hpp" -#include "xx-color-management-v4.hpp" CColorManager::CColorManager(SP resource_) : resource(resource_) { if (!good()) @@ -315,7 +314,7 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPerror(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); return; } - this->settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum}; + this->settings.luminances = SImageDescription::SPCLuminances{.min = min_lum, .max = max_lum, .reference = reference_lum}; this->valuesSet |= PC_LUMINANCES; }); resource->setSetMasteringDisplayPrimaries( @@ -340,7 +339,7 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPerror(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); return; } - this->settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min, .max = max_lum}; + this->settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min_lum, .max = max_lum}; this->valuesSet |= PC_MASTERING_LUMINANCES; }); resource->setSetMaxCll([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_cll) { diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp index 2fb912d9042..d5a3e31a401 100644 --- a/src/protocols/ColorManagement.hpp +++ b/src/protocols/ColorManagement.hpp @@ -71,6 +71,7 @@ class CColorManagementFeedbackSurface { }; struct SImageDescription { + bool drmCoded = false; // values are ready to pass to hdr_output_metadata as is xxColorManagerV4TransferFunction transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; float transferFunctionPower = 1.0f; struct SPCPRimaries { @@ -80,12 +81,12 @@ struct SImageDescription { } red, green, blue, white; } primaries, masteringPrimaries; struct SPCLuminances { - float min = 0.2f; - uint32_t max = 80; - uint32_t reference = 80; + uint32_t min = 2000; // 0.2 cd/m² + uint32_t max = 80; // 80 cd/m² + uint32_t reference = 80; // 80 cd/m² } luminances; struct SPCMasteringLuminances { - float min = 0.0f; + uint32_t min = 0; uint32_t max = 0; } masteringLuminances; uint32_t maxCLL = 0; diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp new file mode 100644 index 00000000000..2dffacb2991 --- /dev/null +++ b/src/protocols/FrogColorManagement.cpp @@ -0,0 +1,119 @@ +#include "FrogColorManagement.hpp" + +CFrogColorManager::CFrogColorManager(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([](CFrogColorManagementFactoryV1* r) { LOGM(TRACE, "Destroy frog_color_management at {:x} (generated default)", (uintptr_t)r); }); + resource->setOnDestroy([this](CFrogColorManagementFactoryV1* r) { PROTO::frogColorManagement->destroyResource(this); }); + + resource->setGetColorManagedSurface([](CFrogColorManagementFactoryV1* r, wl_resource* surface, uint32_t id) { + LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + const auto RESOURCE = PROTO::frogColorManagement->m_vSurfaces.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), SURF)); + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::frogColorManagement->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + SURF->frogColorManagement = RESOURCE; + }); +} + +bool CFrogColorManager::good() { + return resource->resource(); +} + +CFrogColorManagementSurface::CFrogColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm surface {}", (uintptr_t)surface); + PROTO::frogColorManagement->destroyResource(this); + }); + resource->setOnDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm surface {}", (uintptr_t)surface); + PROTO::frogColorManagement->destroyResource(this); + }); + + resource->setSetKnownTransferFunction([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceTransferFunction tf) { + LOGM(TRACE, "Set frog cm transfer function {}", (uint32_t)tf); + switch (tf) { + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_ST2084_PQ: + this->settings.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + break; + ; + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_UNDEFINED: + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22: + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(WARN, "FIXME: add tf support"); + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SRGB: this->settings.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + } + }); + resource->setSetKnownContainerColorVolume([](CFrogColorManagedSurface* r, frogColorManagedSurfacePrimaries primariesName) { + LOGM(TRACE, "Set frog cm primaries {} (FIXME: stub)", (uint32_t)primariesName); + switch (primariesName) { + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_UNDEFINED: + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020:; + } + }); + resource->setSetRenderIntent([](CFrogColorManagedSurface* r, frogColorManagedSurfaceRenderIntent intent) { LOGM(TRACE, "Set frog cm intent {} (noop)", (uint32_t)intent); }); + resource->setSetHdrMetadata([this](CFrogColorManagedSurface* r, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y, + uint32_t max_lum, uint32_t min_lum, uint32_t cll, uint32_t fall) { + LOGM(TRACE, "Set frog mastering primaries r:{},{} g:{},{} b:{},{} w:{},{} luminances {} - {} cll {} fall {}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y, min_lum, max_lum, cll, + fall); + this->settings.masteringPrimaries = + SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; + this->settings.masteringLuminances.min = min_lum; + this->settings.masteringLuminances.max = max_lum; + this->settings.maxCLL = cll; + this->settings.maxFALL = fall; + this->settings.drmCoded = true; + }); +} + +bool CFrogColorManagementSurface::good() { + return resource->resource(); +} + +wl_client* CFrogColorManagementSurface::client() { + return pClient; +} + +CFrogColorManagementProtocol::CFrogColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CFrogColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(TRACE, "New frog_color_management at {:x}", (uintptr_t)RESOURCE.get()); +} + +void CFrogColorManagementProtocol::destroyResource(CFrogColorManager* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CFrogColorManagementProtocol::destroyResource(CFrogColorManagementSurface* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/FrogColorManagement.hpp b/src/protocols/FrogColorManagement.hpp new file mode 100644 index 00000000000..f472b469f35 --- /dev/null +++ b/src/protocols/FrogColorManagement.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include "WaylandProtocol.hpp" +#include "protocols/ColorManagement.hpp" +#include "protocols/core/Compositor.hpp" +#include "frog-color-management-v1.hpp" + +class CFrogColorManager { + public: + CFrogColorManager(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CFrogColorManagementSurface { + public: + CFrogColorManagementSurface(SP resource_, SP surface_); + + bool good(); + wl_client* client(); + + WP self; + WP surface; + + SImageDescription settings; + + private: + SP resource; + wl_client* pClient = nullptr; +}; + +class CFrogColorManagementProtocol : public IWaylandProtocol { + public: + CFrogColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CFrogColorManager* resource); + void destroyResource(CFrogColorManagementSurface* resource); + + std::vector> m_vManagers; + std::vector> m_vSurfaces; + + friend class CFrogColorManager; + friend class CFrogColorManagementSurface; +}; + +namespace PROTO { + inline UP frogColorManagement; +}; diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 4174c386693..6d8e2544586 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -26,6 +26,7 @@ class CWLSubsurfaceResource; class CViewportResource; class CDRMSyncobjSurfaceResource; class CColorManagementSurface; +class CFrogColorManagementSurface; class CWLCallbackResource { public: @@ -123,6 +124,7 @@ class CWLSurfaceResource { WP viewportResource; WP syncobj; // may not be present WP colorManagement; + WP frogColorManagement; void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index ea4cd21ea88..336edad0785 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -22,6 +22,8 @@ #include "../protocols/LinuxDMABUF.hpp" #include "../helpers/sync/SyncTimeline.hpp" #include "debug/Log.hpp" +#include "protocols/ColorManagement.hpp" +#include "protocols/FrogColorManagement.hpp" #include using namespace Hyprutils::Utils; @@ -1531,17 +1533,17 @@ static const auto BT709 = Aquamarine::IOutput::SChromaticityCoords{ .white = Aquamarine::IOutput::xy{.x = 0.3127, .y = 0.3290}, }; -static hdr_output_metadata createHDRMetadataFromEdid(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid, float brightness = 1) { - if (eotf == 0) { +static hdr_output_metadata createHDRMetadata(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid, float brightness = 1) { + if (eotf == 0) return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR - } + const auto toNits = [](float value) { return uint16_t(std::round(value)); }; const auto to16Bit = [](float value) { return uint16_t(std::round(value * 50000)); }; const auto colorimetry = edid.chromaticityCoords.value_or(BT709); - Debug::log(TRACE, "primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, colorimetry.blue.y, - colorimetry.white.x, colorimetry.white.y); - Debug::log(TRACE, "max avg {}, min {}, max {}, brightness {}", edid.hdrMetadata->desiredMaxFrameAverageLuminance, edid.hdrMetadata->desiredContentMinLuminance, + Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, + colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y); + Debug::log(TRACE, "ColorManagement max avg {}, min {}, max {}, brightness {}", edid.hdrMetadata->desiredMaxFrameAverageLuminance, edid.hdrMetadata->desiredContentMinLuminance, edid.hdrMetadata->desiredContentMaxLuminance, brightness); return hdr_output_metadata{ .metadata_type = 0, @@ -1564,6 +1566,41 @@ static hdr_output_metadata createHDRMetadataFromEdid(uint8_t eotf, Aquamarine::I }; } +static hdr_output_metadata createHDRMetadata(SImageDescription settings) { + if (settings.transferFunction != XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ) + return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR + + const auto toNits = [settings](uint32_t value) { return settings.drmCoded ? uint16_t(value) : uint16_t(std::round(value)); }; + const auto to16Bit = [settings](uint32_t value) { return settings.drmCoded ? uint16_t(value * 5) : uint16_t(std::round(value * 50000)); }; + + auto colorimetry = settings.drmCoded || !settings.primaries.white.x ? settings.masteringPrimaries : settings.primaries; + + Debug::log(TRACE, "ColorManagement creating hdr metadata from {} cm values", settings.drmCoded ? "frog" : "xx"); + Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, + colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y); + Debug::log(TRACE, "ColorManagement min {}, max {}, cll {}, fall {}", settings.drmCoded ? settings.masteringLuminances.min : settings.luminances.min, + settings.drmCoded ? settings.masteringLuminances.max : settings.luminances.max, settings.maxCLL, settings.maxFALL); + return hdr_output_metadata{ + .metadata_type = 0, + .hdmi_metadata_type1 = + hdr_metadata_infoframe{ + .eotf = 2, + .metadata_type = 0, + .display_primaries = + { + {.x = to16Bit(colorimetry.red.x), .y = to16Bit(colorimetry.red.y)}, + {.x = to16Bit(colorimetry.green.x), .y = to16Bit(colorimetry.green.y)}, + {.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)}, + }, + .white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)}, + .max_display_mastering_luminance = toNits(settings.drmCoded ? settings.masteringLuminances.max : settings.luminances.max), + .min_display_mastering_luminance = toNits(settings.drmCoded ? settings.masteringLuminances.min : settings.luminances.min), + .max_cll = toNits(settings.maxCLL || (settings.drmCoded ? settings.masteringLuminances.max : settings.luminances.max) / 2), + .max_fall = toNits(settings.maxFALL || (settings.drmCoded ? settings.masteringLuminances.max : settings.luminances.max) / 2), + }, + }; +} + bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { // apply timelines for explicit sync // save inFD otherwise reset will reset it @@ -1579,8 +1616,22 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { static auto PHDR = CConfigValue("experimental:hdr"); static auto PHDR_SDR = CConfigValue("experimental:hdr_sdr_brightness"); - pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadataFromEdid(2, pMonitor->output->parsedEDID, *PHDR_SDR) : - createHDRMetadataFromEdid(0, pMonitor->output->parsedEDID)); + + Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, pMonitor->output->parsedEDID.hdrMetadata->supportsPQ); + if (pMonitor->output->parsedEDID.supportsBT2020 && pMonitor->output->parsedEDID.hdrMetadata->supportsPQ) { + if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { + const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); + const auto SURF = WINDOW->m_pWLSurface->resource(); + if (SURF->frogColorManagement.valid()) + pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->frogColorManagement.get()->settings)); + // else if (SURF->colorManagement.valid()) + // pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->settings)); + // ; + else + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID, *PHDR_SDR) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + } else + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID, *PHDR_SDR) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + } if (pMonitor->ctmUpdated) { pMonitor->ctmUpdated = false; From 5b55cc748135951cff09ebabca582c54d2f8a7ca Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Sun, 15 Dec 2024 23:39:56 +0300 Subject: [PATCH 05/12] fix(?) frog tf setting --- src/protocols/FrogColorManagement.cpp | 33 +++++++++++++++++++++------ src/protocols/FrogColorManagement.hpp | 1 + 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp index 2dffacb2991..ca3f32c8e0d 100644 --- a/src/protocols/FrogColorManagement.cpp +++ b/src/protocols/FrogColorManagement.cpp @@ -35,6 +35,16 @@ bool CFrogColorManager::good() { return resource->resource(); } +static const auto BT709 = SImageDescription::SPCPRimaries{.red = {.x = 0.64 * 50000, .y = 0.33 * 50000}, + .green = {.x = 0.30 * 50000, .y = 0.60 * 50000}, + .blue = {.x = 0.15 * 50000, .y = 0.06 * 50000}, + .white = {.x = 0.3127 * 50000, .y = 0.3290 * 50000}}; + +static const auto BT2020 = SImageDescription::SPCPRimaries{.red = {.x = 0.708 * 50000, .y = 0.292 * 50000}, + .green = {.x = 0.170 * 50000, .y = 0.797 * 50000}, + .blue = {.x = 0.131 * 50000, .y = 0.046 * 50000}, + .white = {.x = 0.3127 * 50000, .y = 0.3290 * 50000}}; + CFrogColorManagementSurface::CFrogColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; @@ -57,21 +67,30 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPsettings.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; break; ; - case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_UNDEFINED: case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22: - case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(WARN, "FIXME: add tf support"); + if (this->pqIntentSent) { + LOGM(TRACE, + "FIXME: assuming broken enum value 2 (FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22) referring to eotf value 2 (TRANSFER_FUNCTION_ST2084_PQ)"); + this->settings.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + break; + }; + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_UNDEFINED: + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(TRACE, std::format("FIXME: add tf support for {}", (uint32_t)tf)); case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SRGB: this->settings.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; } }); - resource->setSetKnownContainerColorVolume([](CFrogColorManagedSurface* r, frogColorManagedSurfacePrimaries primariesName) { - LOGM(TRACE, "Set frog cm primaries {} (FIXME: stub)", (uint32_t)primariesName); + resource->setSetKnownContainerColorVolume([this](CFrogColorManagedSurface* r, frogColorManagedSurfacePrimaries primariesName) { + LOGM(TRACE, "Set frog cm primaries {}", (uint32_t)primariesName); switch (primariesName) { case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_UNDEFINED: - case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: - case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020:; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: this->settings.masteringPrimaries = BT709; break; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020: this->settings.masteringPrimaries = BT2020; break; } }); - resource->setSetRenderIntent([](CFrogColorManagedSurface* r, frogColorManagedSurfaceRenderIntent intent) { LOGM(TRACE, "Set frog cm intent {} (noop)", (uint32_t)intent); }); + resource->setSetRenderIntent([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceRenderIntent intent) { + LOGM(TRACE, "Set frog cm intent {}", (uint32_t)intent); + this->pqIntentSent = intent == FROG_COLOR_MANAGED_SURFACE_RENDER_INTENT_PERCEPTUAL; + }); resource->setSetHdrMetadata([this](CFrogColorManagedSurface* r, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y, uint32_t max_lum, uint32_t min_lum, uint32_t cll, uint32_t fall) { LOGM(TRACE, "Set frog mastering primaries r:{},{} g:{},{} b:{},{} w:{},{} luminances {} - {} cll {} fall {}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y, min_lum, max_lum, cll, diff --git a/src/protocols/FrogColorManagement.hpp b/src/protocols/FrogColorManagement.hpp index f472b469f35..75880bc01bb 100644 --- a/src/protocols/FrogColorManagement.hpp +++ b/src/protocols/FrogColorManagement.hpp @@ -28,6 +28,7 @@ class CFrogColorManagementSurface { WP surface; SImageDescription settings; + bool pqIntentSent = false; private: SP resource; From 27b76176cad62c9a2cad0f59dc5bd961807d2965 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 19 Dec 2024 00:37:01 +0300 Subject: [PATCH 06/12] implement xx cm missing bits --- src/Compositor.cpp | 19 +++ src/Compositor.hpp | 4 + src/config/ConfigDescriptions.hpp | 6 - src/config/ConfigManager.cpp | 1 - src/managers/ProtocolManager.cpp | 3 + src/protocols/ColorManagement.cpp | 160 ++++++++++++++++++++++++-- src/protocols/ColorManagement.hpp | 101 ++++++++++++---- src/protocols/FrogColorManagement.cpp | 83 +++++++------ src/protocols/FrogColorManagement.hpp | 2 - src/protocols/core/Compositor.hpp | 1 - src/render/Renderer.cpp | 48 ++++---- 11 files changed, 322 insertions(+), 106 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index f341f9e7b6f..f55749cf0ca 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -29,6 +29,7 @@ #include "protocols/XDGShell.hpp" #include "protocols/XDGOutput.hpp" #include "protocols/SecurityContext.hpp" +#include "protocols/ColorManagement.hpp" #include "protocols/core/Compositor.hpp" #include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" @@ -2992,4 +2993,22 @@ void CCompositor::onNewMonitor(SP output) { g_pHyprRenderer->damageMonitor(PNEWMONITOR); PNEWMONITOR->onMonitorFrame(); + + if (PROTO::colorManagement && shouldChangePreferredImageDescription()) + PROTO::colorManagement->onImagePreferredChanged(); +} + +SImageDescription CCompositor::getPreferredImageDescription() { + if (!PROTO::colorManagement) { + Debug::log(ERR, "FIXME: color management protocol is not enabled, returning empty image description"); + return SImageDescription{}; + } + Debug::log(WARN, "FIXME: color management protocol is enabled, determine correct preferred image description"); + // should determine some common settings to avoid unnecessary transformations while keeping maximum displayable precision + return SImageDescription{.primaries = Primaries::BT709}; +} + +bool CCompositor::shouldChangePreferredImageDescription() { + Debug::log(WARN, "FIXME: color management protocol is enabled and outputs changed, check preferred image description changes"); + return false; } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 90ac393ca68..000e5d4a56a 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -33,6 +33,7 @@ #include #include +struct SImageDescription; class CWLSurfaceResource; enum eManagersInitStage : uint8_t { @@ -171,6 +172,9 @@ class CCompositor { PHLWINDOW windowForCPointer(CWindow*); void onNewMonitor(SP output); + SImageDescription getPreferredImageDescription(); + bool shouldChangePreferredImageDescription(); + std::string explicitConfigPath; private: diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 3e45d1a6130..7ae63f8b40b 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1634,12 +1634,6 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, - SConfigOptionDescription{ - .value = "experimental:hdr_sdr_brightness", - .description = "force sdr brightness with hdr for all supported outputs", - .type = CONFIG_OPTION_FLOAT, - .data = SConfigOptionDescription::SFloatData{0.5, 0, 1}, - }, SConfigOptionDescription{ .value = "experimental:xx_color_management_v4", .description = "enable color management protocol", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 55d60b2e1ba..7c52ac2d074 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -614,7 +614,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("experimental:wide_color_gamut", Hyprlang::INT{0}); m_pConfig->addConfigValue("experimental:hdr", Hyprlang::INT{0}); - m_pConfig->addConfigValue("experimental:hdr_sdr_brightness", Hyprlang::FLOAT{0.5}); m_pConfig->addConfigValue("experimental:xx_color_management_v4", Hyprlang::INT{0}); // devices diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index feb4a5d8056..3f65395771b 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -80,6 +80,9 @@ void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) { PROTO::outputs.erase(pMonitor->szName); PROTO::outputs.emplace(pMonitor->szName, makeShared(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock())); } + + if (PROTO::colorManagement && g_pCompositor->shouldChangePreferredImageDescription()) + PROTO::colorManagement->onImagePreferredChanged(); } CProtocolManager::CProtocolManager() { diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index f6f55a8c56e..6a33035d50d 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -154,6 +154,10 @@ wl_client* CColorManagementOutput::client() { return pClient; } +CColorManagementSurface::CColorManagementSurface(SP surface_) : surface(surface_) { + // only for frog cm untill wayland cm is adopted +} + CColorManagementSurface::CColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; @@ -169,20 +173,54 @@ CColorManagementSurface::CColorManagementSurface(SP PROTO::colorManagement->destroyResource(this); }); - resource->setSetImageDescription([](CXxColorManagementSurfaceV4* r, wl_resource* image_description, uint32_t render_intent) { - LOGM(TRACE, "Set image description for surface={}, desc={}, intent={} (FIXME: stub)", (uintptr_t)r, (uintptr_t)image_description, render_intent); + resource->setSetImageDescription([this](CXxColorManagementSurfaceV4* r, wl_resource* image_description, uint32_t render_intent) { + LOGM(TRACE, "Set image description for surface={}, desc={}, intent={}", (uintptr_t)r, (uintptr_t)image_description, render_intent); + + const auto PO = (CXxImageDescriptionV4*)wl_resource_get_user_data(image_description); + if (!PO) { // FIXME check validity + r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION, "Image description creation failed"); + return; + } + if (render_intent != XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL) { + r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_RENDER_INTENT, "Unsupported render intent"); + return; + } + + const auto imageDescription = std::find_if(PROTO::colorManagement->m_vImageDescriptions.begin(), PROTO::colorManagement->m_vImageDescriptions.end(), + [&](const auto& other) { return other->resource()->resource() == image_description; }); + if (imageDescription == PROTO::colorManagement->m_vImageDescriptions.end()) { + r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION, "Image description not found"); + return; + } + + this->m_hasImageDescription = true; + this->m_imageDescription = imageDescription->get()->settings; + }); + resource->setUnsetImageDescription([this](CXxColorManagementSurfaceV4* r) { + LOGM(TRACE, "Unset image description for surface={}", (uintptr_t)r); + this->m_imageDescription = SImageDescription{}; + this->m_hasImageDescription = false; }); - resource->setUnsetImageDescription([](CXxColorManagementSurfaceV4* r) { LOGM(TRACE, "Unset image description for surface={} (FIXME: stub)", (uintptr_t)r); }); } bool CColorManagementSurface::good() { - return resource->resource(); + return resource && resource->resource(); } wl_client* CColorManagementSurface::client() { return pClient; } +const SImageDescription& CColorManagementSurface::imageDescription() { + if (!hasImageDescription()) + LOGM(WARN, "Reading imageDescription while none set. Returns default or empty values"); + return m_imageDescription; +} + +bool CColorManagementSurface::hasImageDescription() { + return m_hasImageDescription; +} + CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) @@ -192,14 +230,39 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SPsetDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); + if (this->m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(this->m_currentPreferred.get()); PROTO::colorManagement->destroyResource(this); }); resource->setOnDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); + if (this->m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(this->m_currentPreferred.get()); PROTO::colorManagement->destroyResource(this); }); - resource->setGetPreferred([](CXxColorManagementFeedbackSurfaceV4* r, uint32_t id) { LOGM(TRACE, "Get preferred for id {} (FIXME: stub)", id); }); + resource->setGetPreferred([this](CXxColorManagementFeedbackSurfaceV4* r, uint32_t id) { + LOGM(TRACE, "Get preferred for id {}", id); + + if (m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(m_currentPreferred.get()); + + const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), true)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vImageDescriptions.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + m_currentPreferred = RESOURCE; + + m_currentPreferred->settings = g_pCompositor->getPreferredImageDescription(); + + RESOURCE->resource()->sendReady(id); + }); } bool CColorManagementFeedbackSurface::good() { @@ -280,15 +343,25 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPvaluesSet |= PC_TF_POWER; }); resource->setSetPrimariesNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t primaries) { - LOGM(TRACE, "Set image description primaries by name {} (FIXME: stub)", primaries); + LOGM(TRACE, "Set image description primaries by name {}", primaries); if (this->valuesSet & PC_PRIMARIES) { r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); return; } switch (primaries) { - case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB: break; - case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020: break; + case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB: + this->settings.primariesNameSet = true; + this->settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; + this->settings.primaries = Primaries::BT709; + this->valuesSet |= PC_PRIMARIES; + break; + case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020: + this->settings.primariesNameSet = true; + this->settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_BT2020; + this->settings.primaries = Primaries::BT2020; + this->valuesSet |= PC_PRIMARIES; + break; default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, "Unsupported primaries"); } }); @@ -299,6 +372,7 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPerror(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); return; } + this->settings.primariesNameSet = false; this->settings.primaries = SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; this->valuesSet |= PC_PRIMARIES; @@ -314,7 +388,7 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPerror(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); return; } - this->settings.luminances = SImageDescription::SPCLuminances{.min = min_lum, .max = max_lum, .reference = reference_lum}; + this->settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum}; this->valuesSet |= PC_LUMINANCES; }); resource->setSetMasteringDisplayPrimaries( @@ -339,7 +413,7 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPerror(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); return; } - this->settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min_lum, .max = max_lum}; + this->settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min, .max = max_lum}; this->valuesSet |= PC_MASTERING_LUMINANCES; }); resource->setSetMaxCll([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_cll) { @@ -370,7 +444,8 @@ wl_client* CColorManagementParametricCreator::client() { return pClient; } -CColorManagementImageDescription::CColorManagementImageDescription(SP resource_) : m_resource(resource_) { +CColorManagementImageDescription::CColorManagementImageDescription(SP resource_, bool allowGetInformation) : + m_resource(resource_), m_allowGetInformation(allowGetInformation) { if (!good()) return; @@ -379,7 +454,23 @@ CColorManagementImageDescription::CColorManagementImageDescription(SPsetDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); }); m_resource->setOnDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); }); - m_resource->setGetInformation([](CXxImageDescriptionV4* r, uint32_t id) { LOGM(TRACE, "Get image information for image={}, id={} (FIXME: stub)", (uintptr_t)r, id); }); + m_resource->setGetInformation([this](CXxImageDescriptionV4* r, uint32_t id) { + LOGM(TRACE, "Get image information for image={}, id={}", (uintptr_t)r, id); + if (!this->m_allowGetInformation) { + r->error(XX_IMAGE_DESCRIPTION_V4_ERROR_NO_INFORMATION, "Image descriptions doesn't allow get_information request"); + return; + } + + const auto RESOURCE = new CColorManagementImageDescriptionInfo(makeShared(r->client(), r->version(), id), this->settings); + + if (!RESOURCE->good()) { + r->noMemory(); + } + + // CColorManagementImageDescriptionInfo should send everything in the constructor and be ready for destroying at this point + + delete RESOURCE; + }); } bool CColorManagementImageDescription::good() { @@ -394,6 +485,46 @@ SP CColorManagementImageDescription::resource() { return m_resource; } +CColorManagementImageDescriptionInfo::CColorManagementImageDescriptionInfo(SP resource_, const SImageDescription& settings_) : + m_resource(resource_), settings(settings_) { + if (!good()) + return; + + pClient = m_resource->client(); + + const auto toProto = [](float value) { return int32_t(std::round(value * 10000)); }; + + if (settings.iccFd >= 0) + m_resource->sendIccFile(settings.iccFd, settings.iccSize); + + // send preferred client paramateres + m_resource->sendPrimaries(toProto(settings.primaries.red.x), toProto(settings.primaries.red.y), toProto(settings.primaries.green.x), toProto(settings.primaries.green.y), + toProto(settings.primaries.blue.x), toProto(settings.primaries.blue.y), toProto(settings.primaries.white.x), toProto(settings.primaries.white.y)); + if (settings.primariesNameSet) + m_resource->sendPrimariesNamed(settings.primariesNamed); + m_resource->sendTfPower(std::round(settings.transferFunctionPower * 10000)); + m_resource->sendTfNamed(settings.transferFunction); + m_resource->sendLuminances(std::round(settings.luminances.min * 10000), settings.luminances.max, settings.luminances.reference); + + // send expexted display paramateres + m_resource->sendTargetPrimaries(toProto(settings.masteringPrimaries.red.x), toProto(settings.masteringPrimaries.red.y), toProto(settings.masteringPrimaries.green.x), + toProto(settings.masteringPrimaries.green.y), toProto(settings.masteringPrimaries.blue.x), toProto(settings.masteringPrimaries.blue.y), + toProto(settings.masteringPrimaries.white.x), toProto(settings.masteringPrimaries.white.y)); + m_resource->sendTargetLuminance(std::round(settings.masteringLuminances.min * 10000), settings.masteringLuminances.max); + m_resource->sendTargetMaxCll(settings.maxCLL); + m_resource->sendTargetMaxFall(settings.maxFALL); + + m_resource->sendDone(); +} + +bool CColorManagementImageDescriptionInfo::good() { + return m_resource->resource(); +} + +wl_client* CColorManagementImageDescriptionInfo::client() { + return pClient; +} + CColorManagementProtocol::CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -410,6 +541,11 @@ void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32 LOGM(TRACE, "New xx_color_manager at {:x}", (uintptr_t)RESOURCE.get()); } +void CColorManagementProtocol::onImagePreferredChanged() { + for (auto const& feedback : m_vFeedbackSurfaces) + feedback->resource->sendPreferredChanged(); +} + void CColorManagementProtocol::destroyResource(CColorManager* resource) { std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); } diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp index d5a3e31a401..1f23ce8e264 100644 --- a/src/protocols/ColorManagement.hpp +++ b/src/protocols/ColorManagement.hpp @@ -12,6 +12,50 @@ class CColorManagementOutput; class CColorManagementImageDescription; class CColorManagementProtocol; +struct SImageDescription { + int iccFd = -1; + uint32_t iccSize = 0; + + xxColorManagerV4TransferFunction transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + float transferFunctionPower = 1.0f; + + bool primariesNameSet = false; + xxColorManagerV4Primaries primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; + // primaries are stored as FP values with the same scale as standard defines (0.0 - 1.0) + // wayland protocol expects int32_t values multiplied by 10000 + // drm expects uint16_t values multiplied by 50000 + // frog protocol expects drm values + struct SPCPRimaries { + struct { + float x = 0; + float y = 0; + } red, green, blue, white; + } primaries, masteringPrimaries; + + // luminances in cd/m² + // protos and drm expect min * 10000 + struct SPCLuminances { + float min = 0.2; // 0.2 cd/m² + uint32_t max = 80; // 80 cd/m² + uint32_t reference = 80; // 80 cd/m² + } luminances; + struct SPCMasteringLuminances { + float min = 0; + uint32_t max = 0; + } masteringLuminances; + + uint32_t maxCLL = 0; + uint32_t maxFALL = 0; +}; + +namespace Primaries { //NOLINT + static const auto BT709 = + SImageDescription::SPCPRimaries{.red = {.x = 0.64, .y = 0.33}, .green = {.x = 0.30, .y = 0.60}, .blue = {.x = 0.15, .y = 0.06}, .white = {.x = 0.3127, .y = 0.3290}}; + + static const auto BT2020 = + SImageDescription::SPCPRimaries{.red = {.x = 0.708, .y = 0.292}, .green = {.x = 0.170, .y = 0.797}, .blue = {.x = 0.131, .y = 0.046}, .white = {.x = 0.3127, .y = 0.3290}}; +} + class CColorManager { public: CColorManager(SP resource_); @@ -42,6 +86,7 @@ class CColorManagementOutput { class CColorManagementSurface { public: + CColorManagementSurface(SP surface_); // temporary interface for frog CM CColorManagementSurface(SP resource_, SP surface_); bool good(); @@ -50,9 +95,16 @@ class CColorManagementSurface { WP self; WP surface; + const SImageDescription& imageDescription(); + bool hasImageDescription(); + private: SP resource; wl_client* pClient = nullptr; + SImageDescription m_imageDescription; + bool m_hasImageDescription = false; + + friend class CFrogColorManagementSurface; }; class CColorManagementFeedbackSurface { @@ -68,29 +120,10 @@ class CColorManagementFeedbackSurface { private: SP resource; wl_client* pClient = nullptr; -}; -struct SImageDescription { - bool drmCoded = false; // values are ready to pass to hdr_output_metadata as is - xxColorManagerV4TransferFunction transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; - float transferFunctionPower = 1.0f; - struct SPCPRimaries { - struct { - uint32_t x = 0; - uint32_t y = 0; - } red, green, blue, white; - } primaries, masteringPrimaries; - struct SPCLuminances { - uint32_t min = 2000; // 0.2 cd/m² - uint32_t max = 80; // 80 cd/m² - uint32_t reference = 80; // 80 cd/m² - } luminances; - struct SPCMasteringLuminances { - uint32_t min = 0; - uint32_t max = 0; - } masteringLuminances; - uint32_t maxCLL = 0; - uint32_t maxFALL = 0; + WP m_currentPreferred; + + friend class CColorManagementProtocol; }; class CColorManagementParametricCreator { @@ -105,7 +138,7 @@ class CColorManagementParametricCreator { SImageDescription settings; private: - enum eValuesSet : uint32_t { + enum eValuesSet : uint32_t { // NOLINT PC_TF = (1 << 0), PC_TF_POWER = (1 << 1), PC_PRIMARIES = (1 << 2), @@ -123,7 +156,7 @@ class CColorManagementParametricCreator { class CColorManagementImageDescription { public: - CColorManagementImageDescription(SP resource_); + CColorManagementImageDescription(SP resource_, bool allowGetInformation = false); bool good(); wl_client* client(); @@ -135,17 +168,33 @@ class CColorManagementImageDescription { private: SP m_resource; - wl_client* pClient = nullptr; + wl_client* pClient = nullptr; + bool m_allowGetInformation = false; friend class CColorManagementOutput; }; +class CColorManagementImageDescriptionInfo { + public: + CColorManagementImageDescriptionInfo(SP resource_, const SImageDescription& settings_); + + bool good(); + wl_client* client(); + + private: + SP m_resource; + wl_client* pClient = nullptr; + SImageDescription settings; +}; + class CColorManagementProtocol : public IWaylandProtocol { public: CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + void onImagePreferredChanged(); + private: void destroyResource(CColorManager* resource); void destroyResource(CColorManagementOutput* resource); @@ -167,6 +216,8 @@ class CColorManagementProtocol : public IWaylandProtocol { friend class CColorManagementFeedbackSurface; friend class CColorManagementParametricCreator; friend class CColorManagementImageDescription; + + friend class CFrogColorManagementSurface; }; namespace PROTO { diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp index ca3f32c8e0d..1165b2554e4 100644 --- a/src/protocols/FrogColorManagement.cpp +++ b/src/protocols/FrogColorManagement.cpp @@ -1,4 +1,5 @@ #include "FrogColorManagement.hpp" +#include "protocols/ColorManagement.hpp" CFrogColorManager::CFrogColorManager(SP resource_) : resource(resource_) { if (!good()) @@ -26,8 +27,6 @@ CFrogColorManager::CFrogColorManager(SP resource_ } RESOURCE->self = RESOURCE; - - SURF->frogColorManagement = RESOURCE; }); } @@ -35,73 +34,91 @@ bool CFrogColorManager::good() { return resource->resource(); } -static const auto BT709 = SImageDescription::SPCPRimaries{.red = {.x = 0.64 * 50000, .y = 0.33 * 50000}, - .green = {.x = 0.30 * 50000, .y = 0.60 * 50000}, - .blue = {.x = 0.15 * 50000, .y = 0.06 * 50000}, - .white = {.x = 0.3127 * 50000, .y = 0.3290 * 50000}}; - -static const auto BT2020 = SImageDescription::SPCPRimaries{.red = {.x = 0.708 * 50000, .y = 0.292 * 50000}, - .green = {.x = 0.170 * 50000, .y = 0.797 * 50000}, - .blue = {.x = 0.131 * 50000, .y = 0.046 * 50000}, - .white = {.x = 0.3127 * 50000, .y = 0.3290 * 50000}}; - CFrogColorManagementSurface::CFrogColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; pClient = resource->client(); + if (!surface->colorManagement.valid()) { + const auto RESOURCE = PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared(surface_)); + if (!RESOURCE) { + resource->noMemory(); + PROTO::colorManagement->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + surface->colorManagement = RESOURCE; + + resource->setOnDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm and xx cm for surface {}", (uintptr_t)surface); + if (this->surface.valid()) + PROTO::colorManagement->destroyResource(this->surface->colorManagement.get()); + PROTO::frogColorManagement->destroyResource(this); + }); + } else + resource->setOnDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm surface {}", (uintptr_t)surface); + PROTO::frogColorManagement->destroyResource(this); + }); + resource->setDestroy([this](CFrogColorManagedSurface* r) { LOGM(TRACE, "Destroy frog cm surface {}", (uintptr_t)surface); PROTO::frogColorManagement->destroyResource(this); }); - resource->setOnDestroy([this](CFrogColorManagedSurface* r) { - LOGM(TRACE, "Destroy frog cm surface {}", (uintptr_t)surface); - PROTO::frogColorManagement->destroyResource(this); - }); resource->setSetKnownTransferFunction([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceTransferFunction tf) { LOGM(TRACE, "Set frog cm transfer function {}", (uint32_t)tf); switch (tf) { case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_ST2084_PQ: - this->settings.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + this->surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; break; ; case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22: if (this->pqIntentSent) { LOGM(TRACE, "FIXME: assuming broken enum value 2 (FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22) referring to eotf value 2 (TRANSFER_FUNCTION_ST2084_PQ)"); - this->settings.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + this->surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; break; - }; + }; // intended fall through case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_UNDEFINED: - case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(TRACE, std::format("FIXME: add tf support for {}", (uint32_t)tf)); - case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SRGB: this->settings.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(TRACE, std::format("FIXME: add tf support for {}", (uint32_t)tf)); // intended fall through + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SRGB: + this->surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + + this->surface->colorManagement->m_hasImageDescription = true; } }); resource->setSetKnownContainerColorVolume([this](CFrogColorManagedSurface* r, frogColorManagedSurfacePrimaries primariesName) { LOGM(TRACE, "Set frog cm primaries {}", (uint32_t)primariesName); switch (primariesName) { case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_UNDEFINED: - case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: this->settings.masteringPrimaries = BT709; break; - case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020: this->settings.masteringPrimaries = BT2020; break; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: this->surface->colorManagement->m_imageDescription.masteringPrimaries = Primaries::BT709; break; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020: this->surface->colorManagement->m_imageDescription.masteringPrimaries = Primaries::BT2020; break; } + + this->surface->colorManagement->m_hasImageDescription = true; }); resource->setSetRenderIntent([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceRenderIntent intent) { LOGM(TRACE, "Set frog cm intent {}", (uint32_t)intent); - this->pqIntentSent = intent == FROG_COLOR_MANAGED_SURFACE_RENDER_INTENT_PERCEPTUAL; + this->pqIntentSent = intent == FROG_COLOR_MANAGED_SURFACE_RENDER_INTENT_PERCEPTUAL; + this->surface->colorManagement->m_hasImageDescription = true; }); resource->setSetHdrMetadata([this](CFrogColorManagedSurface* r, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y, uint32_t max_lum, uint32_t min_lum, uint32_t cll, uint32_t fall) { - LOGM(TRACE, "Set frog mastering primaries r:{},{} g:{},{} b:{},{} w:{},{} luminances {} - {} cll {} fall {}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y, min_lum, max_lum, cll, - fall); - this->settings.masteringPrimaries = - SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; - this->settings.masteringLuminances.min = min_lum; - this->settings.masteringLuminances.max = max_lum; - this->settings.maxCLL = cll; - this->settings.maxFALL = fall; - this->settings.drmCoded = true; + LOGM(TRACE, "Set frog primaries r:{},{} g:{},{} b:{},{} w:{},{} luminances {} - {} cll {} fall {}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y, min_lum, max_lum, cll, fall); + this->surface->colorManagement->m_imageDescription.primaries = SImageDescription::SPCPRimaries{.red = {.x = r_x / 50000.0f, .y = r_y / 50000.0f}, + .green = {.x = g_x / 50000.0f, .y = g_y / 50000.0f}, + .blue = {.x = b_x / 50000.0f, .y = b_y / 50000.0f}, + .white = {.x = w_x / 50000.0f, .y = w_y / 50000.0f}}; + this->surface->colorManagement->m_imageDescription.luminances.min = min_lum / 10000.0f; + this->surface->colorManagement->m_imageDescription.luminances.max = max_lum; + this->surface->colorManagement->m_imageDescription.maxCLL = cll; + this->surface->colorManagement->m_imageDescription.maxFALL = fall; + + this->surface->colorManagement->m_hasImageDescription = true; }); } diff --git a/src/protocols/FrogColorManagement.hpp b/src/protocols/FrogColorManagement.hpp index 75880bc01bb..6c00e38d830 100644 --- a/src/protocols/FrogColorManagement.hpp +++ b/src/protocols/FrogColorManagement.hpp @@ -3,7 +3,6 @@ #include #include #include "WaylandProtocol.hpp" -#include "protocols/ColorManagement.hpp" #include "protocols/core/Compositor.hpp" #include "frog-color-management-v1.hpp" @@ -27,7 +26,6 @@ class CFrogColorManagementSurface { WP self; WP surface; - SImageDescription settings; bool pqIntentSent = false; private: diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 6d8e2544586..59f475f5e19 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -124,7 +124,6 @@ class CWLSurfaceResource { WP viewportResource; WP syncobj; // may not be present WP colorManagement; - WP frogColorManagement; void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 336edad0785..336ed0c4db9 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -245,6 +245,8 @@ static void renderSurface(SP surface, int x, int y, void* da DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ && (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; + if (surface->colorManagement.valid()) + Debug::log(TRACE, "FIXME: rendering surface with color management enabled, should apply necessary transformations"); g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->pMonitor->self.lock(), RDATA->surface == surface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); // check for fractional scale surfaces misaligning the buffer size @@ -1533,7 +1535,7 @@ static const auto BT709 = Aquamarine::IOutput::SChromaticityCoords{ .white = Aquamarine::IOutput::xy{.x = 0.3127, .y = 0.3290}, }; -static hdr_output_metadata createHDRMetadata(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid, float brightness = 1) { +static hdr_output_metadata createHDRMetadata(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid) { if (eotf == 0) return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR @@ -1543,8 +1545,8 @@ static hdr_output_metadata createHDRMetadata(uint8_t eotf, Aquamarine::IOutput:: Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y); - Debug::log(TRACE, "ColorManagement max avg {}, min {}, max {}, brightness {}", edid.hdrMetadata->desiredMaxFrameAverageLuminance, edid.hdrMetadata->desiredContentMinLuminance, - edid.hdrMetadata->desiredContentMaxLuminance, brightness); + Debug::log(TRACE, "ColorManagement max avg {}, min {}, max {}", edid.hdrMetadata->desiredMaxFrameAverageLuminance, edid.hdrMetadata->desiredContentMinLuminance, + edid.hdrMetadata->desiredContentMaxLuminance); return hdr_output_metadata{ .metadata_type = 0, .hdmi_metadata_type1 = @@ -1558,10 +1560,10 @@ static hdr_output_metadata createHDRMetadata(uint8_t eotf, Aquamarine::IOutput:: {.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)}, }, .white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)}, - .max_display_mastering_luminance = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance * brightness), - .min_display_mastering_luminance = toNits(edid.hdrMetadata->desiredContentMinLuminance * 10000 * brightness), - .max_cll = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance * brightness), - .max_fall = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance * brightness), + .max_display_mastering_luminance = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance), + .min_display_mastering_luminance = toNits(edid.hdrMetadata->desiredContentMinLuminance * 10000), + .max_cll = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance), + .max_fall = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance), }, }; } @@ -1570,16 +1572,14 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings) { if (settings.transferFunction != XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ) return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR - const auto toNits = [settings](uint32_t value) { return settings.drmCoded ? uint16_t(value) : uint16_t(std::round(value)); }; - const auto to16Bit = [settings](uint32_t value) { return settings.drmCoded ? uint16_t(value * 5) : uint16_t(std::round(value * 50000)); }; + const auto toNits = [](uint32_t value) { return uint16_t(std::round(value)); }; + const auto to16Bit = [](uint32_t value) { return uint16_t(std::round(value * 50000)); }; - auto colorimetry = settings.drmCoded || !settings.primaries.white.x ? settings.masteringPrimaries : settings.primaries; + auto colorimetry = settings.primaries; - Debug::log(TRACE, "ColorManagement creating hdr metadata from {} cm values", settings.drmCoded ? "frog" : "xx"); Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y); - Debug::log(TRACE, "ColorManagement min {}, max {}, cll {}, fall {}", settings.drmCoded ? settings.masteringLuminances.min : settings.luminances.min, - settings.drmCoded ? settings.masteringLuminances.max : settings.luminances.max, settings.maxCLL, settings.maxFALL); + Debug::log(TRACE, "ColorManagement min {}, max {}, cll {}, fall {}", settings.luminances.min, settings.luminances.max, settings.maxCLL, settings.maxFALL); return hdr_output_metadata{ .metadata_type = 0, .hdmi_metadata_type1 = @@ -1593,10 +1593,10 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings) { {.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)}, }, .white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)}, - .max_display_mastering_luminance = toNits(settings.drmCoded ? settings.masteringLuminances.max : settings.luminances.max), - .min_display_mastering_luminance = toNits(settings.drmCoded ? settings.masteringLuminances.min : settings.luminances.min), - .max_cll = toNits(settings.maxCLL || (settings.drmCoded ? settings.masteringLuminances.max : settings.luminances.max) / 2), - .max_fall = toNits(settings.maxFALL || (settings.drmCoded ? settings.masteringLuminances.max : settings.luminances.max) / 2), + .max_display_mastering_luminance = toNits(settings.luminances.max), + .min_display_mastering_luminance = toNits(settings.luminances.min * 10000), + .max_cll = toNits(settings.maxCLL), + .max_fall = toNits(settings.maxFALL), }, }; } @@ -1614,23 +1614,19 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { Debug::log(TRACE, "Setting wide color gamut {}", *PWIDE ? "on" : "off"); pMonitor->output->state->setWideColorGamut(*PWIDE); - static auto PHDR = CConfigValue("experimental:hdr"); - static auto PHDR_SDR = CConfigValue("experimental:hdr_sdr_brightness"); + static auto PHDR = CConfigValue("experimental:hdr"); Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, pMonitor->output->parsedEDID.hdrMetadata->supportsPQ); if (pMonitor->output->parsedEDID.supportsBT2020 && pMonitor->output->parsedEDID.hdrMetadata->supportsPQ) { if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); const auto SURF = WINDOW->m_pWLSurface->resource(); - if (SURF->frogColorManagement.valid()) - pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->frogColorManagement.get()->settings)); - // else if (SURF->colorManagement.valid()) - // pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->settings)); - // ; + if (SURF->colorManagement.valid() && SURF->colorManagement->hasImageDescription()) + pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->imageDescription())); else - pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID, *PHDR_SDR) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); } else - pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID, *PHDR_SDR) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); } if (pMonitor->ctmUpdated) { From dcc2e12b7ee65afdcd7daaf57420c38dfef6f14a Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 19 Dec 2024 20:53:27 +0300 Subject: [PATCH 07/12] cleanup --- src/config/ConfigManager.cpp | 1 - src/managers/ProtocolManager.cpp | 2 -- src/protocols/core/Compositor.cpp | 2 +- src/render/Renderer.cpp | 2 -- 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 7c52ac2d074..e823168649a 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 3f65395771b..3440220b87b 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -60,11 +60,9 @@ #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" #include "../Compositor.hpp" -#include "frog-color-management-v1.hpp" #include #include -#include void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) { const bool ISMIRROR = pMonitor->isMirror(); diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 28cb7e1a4a1..89f2a4cbcfe 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -449,7 +449,7 @@ void CWLSurfaceResource::commitPendingState() { // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. if (current.buffer->buffer->isSynchronous()) { - //dropCurrentBuffer(); + dropCurrentBuffer(); dropPendingBuffer(); // pending atm is just a copied ref of the current, drop it too to send a release } } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 336ed0c4db9..18b30366e20 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" @@ -23,7 +22,6 @@ #include "../helpers/sync/SyncTimeline.hpp" #include "debug/Log.hpp" #include "protocols/ColorManagement.hpp" -#include "protocols/FrogColorManagement.hpp" #include using namespace Hyprutils::Utils; From a831876fe48999c731bb8149b76e54b738718411 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Fri, 20 Dec 2024 18:47:41 +0300 Subject: [PATCH 08/12] fix for latest git --- src/protocols/ColorManagement.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index 6a33035d50d..0819ce9e258 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -1,4 +1,5 @@ #include "ColorManagement.hpp" +#include "Compositor.hpp" CColorManager::CColorManager(SP resource_) : resource(resource_) { if (!good()) From e8f1172f7365debc7751bcac8d42682c08c8fcdd Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Sun, 22 Dec 2024 19:32:51 +0300 Subject: [PATCH 09/12] fix latest git --- src/render/pass/SurfacePassElement.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index 38de521080b..7139f3d65ce 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -78,6 +78,8 @@ void CSurfacePassElement::draw(const CRegion& damage) { DELTALESSTHAN(windowBox.height, data.surface->current.bufferSize.y, 3) /* off by one-or-two */ && (!data.pWindow || (!data.pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; + if (data.surface->colorManagement.valid()) + Debug::log(TRACE, "FIXME: rendering surface with color management enabled, should apply necessary transformations"); g_pHyprRenderer->calculateUVForSurface(data.pWindow, data.surface, data.pMonitor->self.lock(), data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); // check for fractional scale surfaces misaligning the buffer size From a44487f81a3d026efed8cf5f5ca5e4da540f1646 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Sun, 29 Dec 2024 11:32:08 +0300 Subject: [PATCH 10/12] handle subsurfaces & defaults --- src/protocols/FrogColorManagement.cpp | 26 +++++++++++++++----------- src/render/Renderer.cpp | 13 ++++++++----- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp index 1165b2554e4..7a8e53d78bd 100644 --- a/src/protocols/FrogColorManagement.cpp +++ b/src/protocols/FrogColorManagement.cpp @@ -1,5 +1,6 @@ #include "FrogColorManagement.hpp" #include "protocols/ColorManagement.hpp" +#include "protocols/core/Subcompositor.hpp" CFrogColorManager::CFrogColorManager(SP resource_) : resource(resource_) { if (!good()) @@ -18,6 +19,9 @@ CFrogColorManager::CFrogColorManager(SP resource_ return; } + if (SURF->role->role() == SURFACE_ROLE_SUBSURFACE) + SURF = ((CSubsurfaceRole*)SURF->role.get())->subsurface->t1Parent(); + const auto RESOURCE = PROTO::frogColorManagement->m_vSurfaces.emplace_back( makeShared(makeShared(r->client(), r->version(), id), SURF)); if (!RESOURCE->good()) { @@ -70,7 +74,7 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPsetSetKnownTransferFunction([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceTransferFunction tf) { - LOGM(TRACE, "Set frog cm transfer function {}", (uint32_t)tf); + LOGM(TRACE, "Set frog cm transfer function {} for {}", (uint32_t)tf, this->surface->id()); switch (tf) { case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_ST2084_PQ: this->surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; @@ -95,8 +99,8 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPsurface->colorManagement->m_imageDescription.masteringPrimaries = Primaries::BT709; break; - case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020: this->surface->colorManagement->m_imageDescription.masteringPrimaries = Primaries::BT2020; break; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: this->surface->colorManagement->m_imageDescription.primaries = Primaries::BT709; break; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020: this->surface->colorManagement->m_imageDescription.primaries = Primaries::BT2020; break; } this->surface->colorManagement->m_hasImageDescription = true; @@ -109,14 +113,14 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPsetSetHdrMetadata([this](CFrogColorManagedSurface* r, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y, uint32_t max_lum, uint32_t min_lum, uint32_t cll, uint32_t fall) { LOGM(TRACE, "Set frog primaries r:{},{} g:{},{} b:{},{} w:{},{} luminances {} - {} cll {} fall {}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y, min_lum, max_lum, cll, fall); - this->surface->colorManagement->m_imageDescription.primaries = SImageDescription::SPCPRimaries{.red = {.x = r_x / 50000.0f, .y = r_y / 50000.0f}, - .green = {.x = g_x / 50000.0f, .y = g_y / 50000.0f}, - .blue = {.x = b_x / 50000.0f, .y = b_y / 50000.0f}, - .white = {.x = w_x / 50000.0f, .y = w_y / 50000.0f}}; - this->surface->colorManagement->m_imageDescription.luminances.min = min_lum / 10000.0f; - this->surface->colorManagement->m_imageDescription.luminances.max = max_lum; - this->surface->colorManagement->m_imageDescription.maxCLL = cll; - this->surface->colorManagement->m_imageDescription.maxFALL = fall; + this->surface->colorManagement->m_imageDescription.masteringPrimaries = SImageDescription::SPCPRimaries{.red = {.x = r_x / 50000.0f, .y = r_y / 50000.0f}, + .green = {.x = g_x / 50000.0f, .y = g_y / 50000.0f}, + .blue = {.x = b_x / 50000.0f, .y = b_y / 50000.0f}, + .white = {.x = w_x / 50000.0f, .y = w_y / 50000.0f}}; + this->surface->colorManagement->m_imageDescription.masteringLuminances.min = min_lum / 10000.0f; + this->surface->colorManagement->m_imageDescription.masteringLuminances.max = max_lum; + this->surface->colorManagement->m_imageDescription.maxCLL = cll; + this->surface->colorManagement->m_imageDescription.maxFALL = fall; this->surface->colorManagement->m_hasImageDescription = true; }); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 78178570656..dad52caa6cc 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1418,7 +1418,7 @@ static hdr_output_metadata createHDRMetadata(uint8_t eotf, Aquamarine::IOutput:: }; } -static hdr_output_metadata createHDRMetadata(SImageDescription settings) { +static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamarine::IOutput::SParsedEDID edid) { if (settings.transferFunction != XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ) return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR @@ -1426,10 +1426,13 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings) { const auto to16Bit = [](uint32_t value) { return uint16_t(std::round(value * 50000)); }; auto colorimetry = settings.primaries; + auto luminances = settings.masteringLuminances.max > 0 ? + settings.masteringLuminances : + SImageDescription::SPCMasteringLuminances{.min = edid.hdrMetadata->desiredContentMinLuminance, .max = edid.hdrMetadata->desiredContentMaxLuminance}; Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y); - Debug::log(TRACE, "ColorManagement min {}, max {}, cll {}, fall {}", settings.luminances.min, settings.luminances.max, settings.maxCLL, settings.maxFALL); + Debug::log(TRACE, "ColorManagement min {}, max {}, cll {}, fall {}", luminances.min, luminances.max, settings.maxCLL, settings.maxFALL); return hdr_output_metadata{ .metadata_type = 0, .hdmi_metadata_type1 = @@ -1443,8 +1446,8 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings) { {.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)}, }, .white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)}, - .max_display_mastering_luminance = toNits(settings.luminances.max), - .min_display_mastering_luminance = toNits(settings.luminances.min * 10000), + .max_display_mastering_luminance = toNits(luminances.max), + .min_display_mastering_luminance = toNits(luminances.min * 10000), .max_cll = toNits(settings.maxCLL), .max_fall = toNits(settings.maxFALL), }, @@ -1472,7 +1475,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); const auto SURF = WINDOW->m_pWLSurface->resource(); if (SURF->colorManagement.valid() && SURF->colorManagement->hasImageDescription()) - pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->imageDescription())); + pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->imageDescription(), pMonitor->output->parsedEDID)); else pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); } else From 7f3638c95eaa9407aed0242a87a6df9b725ba3a7 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Mon, 6 Jan 2025 21:41:10 +0300 Subject: [PATCH 11/12] cleanups --- src/Compositor.cpp | 2 +- src/Compositor.hpp | 2 +- src/desktop/WLSurface.hpp | 14 ++-- src/protocols/ColorManagement.cpp | 105 +++++++++++++------------- src/protocols/ColorManagement.hpp | 2 +- src/protocols/FrogColorManagement.cpp | 46 +++++------ 6 files changed, 84 insertions(+), 87 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 3dde403e70d..551ba2cd77e 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2992,7 +2992,7 @@ SImageDescription CCompositor::getPreferredImageDescription() { } Debug::log(WARN, "FIXME: color management protocol is enabled, determine correct preferred image description"); // should determine some common settings to avoid unnecessary transformations while keeping maximum displayable precision - return SImageDescription{.primaries = Primaries::BT709}; + return SImageDescription{.primaries = NColorPrimaries::BT709}; } bool CCompositor::shouldChangePreferredImageDescription() { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 80544805d9b..ea38c040bc8 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -23,6 +23,7 @@ #include "helpers/Monitor.hpp" #include "desktop/Workspace.hpp" #include "desktop/Window.hpp" +#include "protocols/ColorManagement.hpp" #include "render/Renderer.hpp" #include "render/OpenGL.hpp" #include "hyprerror/HyprError.hpp" @@ -32,7 +33,6 @@ #include #include -struct SImageDescription; class CWLSurfaceResource; enum eManagersInitStage : uint8_t { diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 40e4b0b1847..057a6f90571 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -8,7 +8,6 @@ class CSubsurface; class CPopup; class CPointerConstraint; class CWLSurfaceResource; -class CXxColorManagementSurfaceV4; class CWLSurface { public: @@ -99,15 +98,14 @@ class CWLSurface { private: CWLSurface() = default; - bool m_bInert = true; + bool m_bInert = true; - WP m_pResource; + WP m_pResource; - PHLWINDOWREF m_pWindowOwner; - PHLLSREF m_pLayerOwner; - CPopup* m_pPopupOwner = nullptr; - CSubsurface* m_pSubsurfaceOwner = nullptr; - CXxColorManagementSurfaceV4* m_pCMSurface = nullptr; + PHLWINDOWREF m_pWindowOwner; + PHLLSREF m_pLayerOwner; + CPopup* m_pPopupOwner = nullptr; + CSubsurface* m_pSubsurfaceOwner = nullptr; // WP m_pConstraint; diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index 0819ce9e258..7ff4db4f2b8 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -194,13 +194,13 @@ CColorManagementSurface::CColorManagementSurface(SP return; } - this->m_hasImageDescription = true; - this->m_imageDescription = imageDescription->get()->settings; + m_hasImageDescription = true; + m_imageDescription = imageDescription->get()->settings; }); resource->setUnsetImageDescription([this](CXxColorManagementSurfaceV4* r) { LOGM(TRACE, "Unset image description for surface={}", (uintptr_t)r); - this->m_imageDescription = SImageDescription{}; - this->m_hasImageDescription = false; + m_imageDescription = SImageDescription{}; + m_hasImageDescription = false; }); } @@ -231,14 +231,14 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SPsetDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); - if (this->m_currentPreferred.valid()) - PROTO::colorManagement->destroyResource(this->m_currentPreferred.get()); + if (m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(m_currentPreferred.get()); PROTO::colorManagement->destroyResource(this); }); resource->setOnDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); - if (this->m_currentPreferred.valid()) - PROTO::colorManagement->destroyResource(this->m_currentPreferred.get()); + if (m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(m_currentPreferred.get()); PROTO::colorManagement->destroyResource(this); }); @@ -286,13 +286,13 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPvaluesSet) { + if (!valuesSet) { r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCOMPLETE_SET, "Missing required settings"); return; } // FIXME actually check consistency - if (!this->valuesSet) { + if (!valuesSet) { r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCONSISTENT_SET, "Set is not consistent"); return; } @@ -307,20 +307,20 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPvaluesSet) { + if (!valuesSet) { RESOURCE->resource()->sendFailed(XX_IMAGE_DESCRIPTION_V4_CAUSE_UNSUPPORTED, "unsupported"); return; } RESOURCE->self = RESOURCE; - RESOURCE->settings = this->settings; + RESOURCE->settings = settings; RESOURCE->resource()->sendReady(id); PROTO::colorManagement->destroyResource(this); }); resource->setSetTfNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t tf) { LOGM(TRACE, "Set image description transfer function to {}", tf); - if (this->valuesSet & PC_TF) { + if (valuesSet & PC_TF) { r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function already set"); return; } @@ -331,37 +331,37 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPerror(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF, "Unsupported transfer function"); return; } - this->settings.transferFunction = (xxColorManagerV4TransferFunction)tf; - this->valuesSet |= PC_TF; + settings.transferFunction = (xxColorManagerV4TransferFunction)tf; + valuesSet |= PC_TF; }); resource->setSetTfPower([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t eexp) { LOGM(TRACE, "Set image description tf power to {}", eexp); - if (this->valuesSet & PC_TF_POWER) { + if (valuesSet & PC_TF_POWER) { r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function power already set"); return; } - this->settings.transferFunctionPower = eexp / 10000.0f; - this->valuesSet |= PC_TF_POWER; + settings.transferFunctionPower = eexp / 10000.0f; + valuesSet |= PC_TF_POWER; }); resource->setSetPrimariesNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t primaries) { LOGM(TRACE, "Set image description primaries by name {}", primaries); - if (this->valuesSet & PC_PRIMARIES) { + if (valuesSet & PC_PRIMARIES) { r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); return; } switch (primaries) { case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB: - this->settings.primariesNameSet = true; - this->settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; - this->settings.primaries = Primaries::BT709; - this->valuesSet |= PC_PRIMARIES; + settings.primariesNameSet = true; + settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; + settings.primaries = NColorPrimaries::BT709; + valuesSet |= PC_PRIMARIES; break; case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020: - this->settings.primariesNameSet = true; - this->settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_BT2020; - this->settings.primaries = Primaries::BT2020; - this->valuesSet |= PC_PRIMARIES; + settings.primariesNameSet = true; + settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_BT2020; + settings.primaries = NColorPrimaries::BT2020; + valuesSet |= PC_PRIMARIES; break; default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, "Unsupported primaries"); } @@ -369,19 +369,19 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPsetSetPrimaries( [this](CXxImageDescriptionCreatorParamsV4* r, 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) { LOGM(TRACE, "Set image description primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); - if (this->valuesSet & PC_PRIMARIES) { + if (valuesSet & PC_PRIMARIES) { r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); return; } - this->settings.primariesNameSet = false; - this->settings.primaries = + settings.primariesNameSet = false; + settings.primaries = SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; - this->valuesSet |= PC_PRIMARIES; + valuesSet |= PC_PRIMARIES; }); resource->setSetLuminances([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum) { auto min = min_lum / 10000.0f; LOGM(TRACE, "Set image description luminances to {} - {} ({})", min, max_lum, reference_lum); - if (this->valuesSet & PC_LUMINANCES) { + if (valuesSet & PC_LUMINANCES) { r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Luminances already set"); return; } @@ -389,24 +389,24 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPerror(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); return; } - this->settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum}; - this->valuesSet |= PC_LUMINANCES; + settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum}; + valuesSet |= PC_LUMINANCES; }); resource->setSetMasteringDisplayPrimaries( [this](CXxImageDescriptionCreatorParamsV4* r, 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) { LOGM(TRACE, "Set image description mastering primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); - // if (this->valuesSet & PC_MASTERING_PRIMARIES) { + // if (valuesSet & PC_MASTERING_PRIMARIES) { // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering primaries already set"); // return; // } - this->settings.masteringPrimaries = + settings.masteringPrimaries = SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; - this->valuesSet |= PC_MASTERING_PRIMARIES; + valuesSet |= PC_MASTERING_PRIMARIES; }); resource->setSetMasteringLuminance([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum) { auto min = min_lum / 10000.0f; LOGM(TRACE, "Set image description mastering luminances to {} - {}", min, max_lum); - // if (this->valuesSet & PC_MASTERING_LUMINANCES) { + // if (valuesSet & PC_MASTERING_LUMINANCES) { // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering luminances already set"); // return; // } @@ -414,26 +414,26 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPerror(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); return; } - this->settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min, .max = max_lum}; - this->valuesSet |= PC_MASTERING_LUMINANCES; + settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min, .max = max_lum}; + valuesSet |= PC_MASTERING_LUMINANCES; }); resource->setSetMaxCll([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_cll) { LOGM(TRACE, "Set image description max content light level to {}", max_cll); - // if (this->valuesSet & PC_CLL) { + // if (valuesSet & PC_CLL) { // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max CLL already set"); // return; // } - this->settings.maxCLL = max_cll; - this->valuesSet |= PC_CLL; + settings.maxCLL = max_cll; + valuesSet |= PC_CLL; }); resource->setSetMaxFall([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_fall) { LOGM(TRACE, "Set image description max frame-average light level to {}", max_fall); - // if (this->valuesSet & PC_FALL) { + // if (valuesSet & PC_FALL) { // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max FALL already set"); // return; // } - this->settings.maxFALL = max_fall; - this->valuesSet |= PC_FALL; + settings.maxFALL = max_fall; + valuesSet |= PC_FALL; }); } @@ -457,20 +457,18 @@ CColorManagementImageDescription::CColorManagementImageDescription(SPsetGetInformation([this](CXxImageDescriptionV4* r, uint32_t id) { LOGM(TRACE, "Get image information for image={}, id={}", (uintptr_t)r, id); - if (!this->m_allowGetInformation) { + if (!m_allowGetInformation) { r->error(XX_IMAGE_DESCRIPTION_V4_ERROR_NO_INFORMATION, "Image descriptions doesn't allow get_information request"); return; } - const auto RESOURCE = new CColorManagementImageDescriptionInfo(makeShared(r->client(), r->version(), id), this->settings); + auto RESOURCE = makeShared(makeShared(r->client(), r->version(), id), settings); - if (!RESOURCE->good()) { + if (!RESOURCE->good()) r->noMemory(); - } // CColorManagementImageDescriptionInfo should send everything in the constructor and be ready for destroying at this point - - delete RESOURCE; + RESOURCE.reset(); }); } @@ -543,8 +541,9 @@ void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32 } void CColorManagementProtocol::onImagePreferredChanged() { - for (auto const& feedback : m_vFeedbackSurfaces) + for (auto const& feedback : m_vFeedbackSurfaces) { feedback->resource->sendPreferredChanged(); + } } void CColorManagementProtocol::destroyResource(CColorManager* resource) { diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp index 1f23ce8e264..ccc04df3834 100644 --- a/src/protocols/ColorManagement.hpp +++ b/src/protocols/ColorManagement.hpp @@ -48,7 +48,7 @@ struct SImageDescription { uint32_t maxFALL = 0; }; -namespace Primaries { //NOLINT +namespace NColorPrimaries { static const auto BT709 = SImageDescription::SPCPRimaries{.red = {.x = 0.64, .y = 0.33}, .green = {.x = 0.30, .y = 0.60}, .blue = {.x = 0.15, .y = 0.06}, .white = {.x = 0.3127, .y = 0.3290}}; diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp index 7a8e53d78bd..3ea20405b2e 100644 --- a/src/protocols/FrogColorManagement.cpp +++ b/src/protocols/FrogColorManagement.cpp @@ -58,8 +58,8 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPsetOnDestroy([this](CFrogColorManagedSurface* r) { LOGM(TRACE, "Destroy frog cm and xx cm for surface {}", (uintptr_t)surface); - if (this->surface.valid()) - PROTO::colorManagement->destroyResource(this->surface->colorManagement.get()); + if (surface.valid()) + PROTO::colorManagement->destroyResource(surface->colorManagement.get()); PROTO::frogColorManagement->destroyResource(this); }); } else @@ -74,55 +74,55 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPsetSetKnownTransferFunction([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceTransferFunction tf) { - LOGM(TRACE, "Set frog cm transfer function {} for {}", (uint32_t)tf, this->surface->id()); + LOGM(TRACE, "Set frog cm transfer function {} for {}", (uint32_t)tf, surface->id()); switch (tf) { case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_ST2084_PQ: - this->surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; break; ; case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22: - if (this->pqIntentSent) { + if (pqIntentSent) { LOGM(TRACE, "FIXME: assuming broken enum value 2 (FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22) referring to eotf value 2 (TRANSFER_FUNCTION_ST2084_PQ)"); - this->surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; break; }; // intended fall through case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_UNDEFINED: case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(TRACE, std::format("FIXME: add tf support for {}", (uint32_t)tf)); // intended fall through case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SRGB: - this->surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; - this->surface->colorManagement->m_hasImageDescription = true; + surface->colorManagement->m_hasImageDescription = true; } }); resource->setSetKnownContainerColorVolume([this](CFrogColorManagedSurface* r, frogColorManagedSurfacePrimaries primariesName) { LOGM(TRACE, "Set frog cm primaries {}", (uint32_t)primariesName); switch (primariesName) { case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_UNDEFINED: - case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: this->surface->colorManagement->m_imageDescription.primaries = Primaries::BT709; break; - case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020: this->surface->colorManagement->m_imageDescription.primaries = Primaries::BT2020; break; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: surface->colorManagement->m_imageDescription.primaries = NColorPrimaries::BT709; break; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020: surface->colorManagement->m_imageDescription.primaries = NColorPrimaries::BT2020; break; } - this->surface->colorManagement->m_hasImageDescription = true; + surface->colorManagement->m_hasImageDescription = true; }); resource->setSetRenderIntent([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceRenderIntent intent) { LOGM(TRACE, "Set frog cm intent {}", (uint32_t)intent); - this->pqIntentSent = intent == FROG_COLOR_MANAGED_SURFACE_RENDER_INTENT_PERCEPTUAL; - this->surface->colorManagement->m_hasImageDescription = true; + pqIntentSent = intent == FROG_COLOR_MANAGED_SURFACE_RENDER_INTENT_PERCEPTUAL; + surface->colorManagement->m_hasImageDescription = true; }); resource->setSetHdrMetadata([this](CFrogColorManagedSurface* r, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y, uint32_t max_lum, uint32_t min_lum, uint32_t cll, uint32_t fall) { LOGM(TRACE, "Set frog primaries r:{},{} g:{},{} b:{},{} w:{},{} luminances {} - {} cll {} fall {}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y, min_lum, max_lum, cll, fall); - this->surface->colorManagement->m_imageDescription.masteringPrimaries = SImageDescription::SPCPRimaries{.red = {.x = r_x / 50000.0f, .y = r_y / 50000.0f}, - .green = {.x = g_x / 50000.0f, .y = g_y / 50000.0f}, - .blue = {.x = b_x / 50000.0f, .y = b_y / 50000.0f}, - .white = {.x = w_x / 50000.0f, .y = w_y / 50000.0f}}; - this->surface->colorManagement->m_imageDescription.masteringLuminances.min = min_lum / 10000.0f; - this->surface->colorManagement->m_imageDescription.masteringLuminances.max = max_lum; - this->surface->colorManagement->m_imageDescription.maxCLL = cll; - this->surface->colorManagement->m_imageDescription.maxFALL = fall; - - this->surface->colorManagement->m_hasImageDescription = true; + surface->colorManagement->m_imageDescription.masteringPrimaries = SImageDescription::SPCPRimaries{.red = {.x = r_x / 50000.0f, .y = r_y / 50000.0f}, + .green = {.x = g_x / 50000.0f, .y = g_y / 50000.0f}, + .blue = {.x = b_x / 50000.0f, .y = b_y / 50000.0f}, + .white = {.x = w_x / 50000.0f, .y = w_y / 50000.0f}}; + surface->colorManagement->m_imageDescription.masteringLuminances.min = min_lum / 10000.0f; + surface->colorManagement->m_imageDescription.masteringLuminances.max = max_lum; + surface->colorManagement->m_imageDescription.maxCLL = cll; + surface->colorManagement->m_imageDescription.maxFALL = fall; + + surface->colorManagement->m_hasImageDescription = true; }); } From e0627ac9d44811da73dc99f07e6467a197a29c9d Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Tue, 7 Jan 2025 15:12:29 +0300 Subject: [PATCH 12/12] move SImageDescription to types --- src/Compositor.hpp | 2 +- src/protocols/ColorManagement.hpp | 45 +---------------------- src/protocols/types/ColorManagement.hpp | 47 +++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 45 deletions(-) create mode 100644 src/protocols/types/ColorManagement.hpp diff --git a/src/Compositor.hpp b/src/Compositor.hpp index ea38c040bc8..629b71bc0ae 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -23,7 +23,7 @@ #include "helpers/Monitor.hpp" #include "desktop/Workspace.hpp" #include "desktop/Window.hpp" -#include "protocols/ColorManagement.hpp" +#include "protocols/types/ColorManagement.hpp" #include "render/Renderer.hpp" #include "render/OpenGL.hpp" #include "hyprerror/HyprError.hpp" diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp index ccc04df3834..573abf697d8 100644 --- a/src/protocols/ColorManagement.hpp +++ b/src/protocols/ColorManagement.hpp @@ -6,56 +6,13 @@ #include "WaylandProtocol.hpp" #include "protocols/core/Compositor.hpp" #include "xx-color-management-v4.hpp" +#include "types/ColorManagement.hpp" class CColorManager; class CColorManagementOutput; class CColorManagementImageDescription; class CColorManagementProtocol; -struct SImageDescription { - int iccFd = -1; - uint32_t iccSize = 0; - - xxColorManagerV4TransferFunction transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; - float transferFunctionPower = 1.0f; - - bool primariesNameSet = false; - xxColorManagerV4Primaries primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; - // primaries are stored as FP values with the same scale as standard defines (0.0 - 1.0) - // wayland protocol expects int32_t values multiplied by 10000 - // drm expects uint16_t values multiplied by 50000 - // frog protocol expects drm values - struct SPCPRimaries { - struct { - float x = 0; - float y = 0; - } red, green, blue, white; - } primaries, masteringPrimaries; - - // luminances in cd/m² - // protos and drm expect min * 10000 - struct SPCLuminances { - float min = 0.2; // 0.2 cd/m² - uint32_t max = 80; // 80 cd/m² - uint32_t reference = 80; // 80 cd/m² - } luminances; - struct SPCMasteringLuminances { - float min = 0; - uint32_t max = 0; - } masteringLuminances; - - uint32_t maxCLL = 0; - uint32_t maxFALL = 0; -}; - -namespace NColorPrimaries { - static const auto BT709 = - SImageDescription::SPCPRimaries{.red = {.x = 0.64, .y = 0.33}, .green = {.x = 0.30, .y = 0.60}, .blue = {.x = 0.15, .y = 0.06}, .white = {.x = 0.3127, .y = 0.3290}}; - - static const auto BT2020 = - SImageDescription::SPCPRimaries{.red = {.x = 0.708, .y = 0.292}, .green = {.x = 0.170, .y = 0.797}, .blue = {.x = 0.131, .y = 0.046}, .white = {.x = 0.3127, .y = 0.3290}}; -} - class CColorManager { public: CColorManager(SP resource_); diff --git a/src/protocols/types/ColorManagement.hpp b/src/protocols/types/ColorManagement.hpp new file mode 100644 index 00000000000..e18f0b840f5 --- /dev/null +++ b/src/protocols/types/ColorManagement.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "xx-color-management-v4.hpp" + +struct SImageDescription { + int iccFd = -1; + uint32_t iccSize = 0; + + xxColorManagerV4TransferFunction transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + float transferFunctionPower = 1.0f; + + bool primariesNameSet = false; + xxColorManagerV4Primaries primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; + // primaries are stored as FP values with the same scale as standard defines (0.0 - 1.0) + // wayland protocol expects int32_t values multiplied by 10000 + // drm expects uint16_t values multiplied by 50000 + // frog protocol expects drm values + struct SPCPRimaries { + struct { + float x = 0; + float y = 0; + } red, green, blue, white; + } primaries, masteringPrimaries; + + // luminances in cd/m² + // protos and drm expect min * 10000 + struct SPCLuminances { + float min = 0.2; // 0.2 cd/m² + uint32_t max = 80; // 80 cd/m² + uint32_t reference = 80; // 80 cd/m² + } luminances; + struct SPCMasteringLuminances { + float min = 0; + uint32_t max = 0; + } masteringLuminances; + + uint32_t maxCLL = 0; + uint32_t maxFALL = 0; +}; + +namespace NColorPrimaries { + static const auto BT709 = + SImageDescription::SPCPRimaries{.red = {.x = 0.64, .y = 0.33}, .green = {.x = 0.30, .y = 0.60}, .blue = {.x = 0.15, .y = 0.06}, .white = {.x = 0.3127, .y = 0.3290}}; + + static const auto BT2020 = + SImageDescription::SPCPRimaries{.red = {.x = 0.708, .y = 0.292}, .green = {.x = 0.170, .y = 0.797}, .blue = {.x = 0.131, .y = 0.046}, .white = {.x = 0.3127, .y = 0.3290}}; +} \ No newline at end of file