From 2e5e800e4b334240689df5a4c2c4607f751da908 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Thu, 26 Mar 2026 02:48:06 +0300 Subject: [PATCH] renderer/cm: Support wp-cm-v1 version 2 (#12817) --- CMakeLists.txt | 2 +- hyprtester/CMakeLists.txt | 2 +- src/config/legacy/ConfigManager.cpp | 2 + .../supplementary/ConfigDescriptions.hpp | 11 +++ src/helpers/cm/ColorManagement.cpp | 6 +- src/helpers/cm/ColorManagement.hpp | 20 +++-- src/managers/ProtocolManager.cpp | 3 +- src/protocols/ColorManagement.cpp | 88 ++++++++++++++++--- src/protocols/ColorManagement.hpp | 15 ++-- 9 files changed, 120 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fad578cde..a91e1372d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,7 +246,7 @@ set_source_files_properties(${CMAKE_SOURCE_DIR}/src/version.h PROPERTIES GENERAT set(XKBCOMMON_MINIMUM_VERSION 1.11.0) set(WAYLAND_SERVER_MINIMUM_VERSION 1.22.91) -set(WAYLAND_SERVER_PROTOCOLS_MINIMUM_VERSION 1.45) +set(WAYLAND_SERVER_PROTOCOLS_MINIMUM_VERSION 1.47) set(LIBINPUT_MINIMUM_VERSION 1.28) pkg_check_modules( diff --git a/hyprtester/CMakeLists.txt b/hyprtester/CMakeLists.txt index f17f73b14..599eee585 100644 --- a/hyprtester/CMakeLists.txt +++ b/hyprtester/CMakeLists.txt @@ -48,7 +48,7 @@ pkg_check_modules( IMPORTED_TARGET hyprutils>=0.8.0 wayland-client - wayland-protocols + wayland-protocols>=1.47 ) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) diff --git a/src/config/legacy/ConfigManager.cpp b/src/config/legacy/ConfigManager.cpp index b69db9068..31da257c6 100644 --- a/src/config/legacy/ConfigManager.cpp +++ b/src/config/legacy/ConfigManager.cpp @@ -822,6 +822,8 @@ CConfigManager::CConfigManager() { registerConfigVar("ecosystem:no_donation_nag", Hyprlang::INT{0}); registerConfigVar("ecosystem:enforce_permissions", Hyprlang::INT{0}); + registerConfigVar("experimental:wp_cm_1_2", Hyprlang::INT{0}); + registerConfigVar("quirks:prefer_hdr", Hyprlang::INT{0}); registerConfigVar("quirks:skip_non_kms_dmabuf_formats", Hyprlang::INT{0}); diff --git a/src/config/supplementary/ConfigDescriptions.hpp b/src/config/supplementary/ConfigDescriptions.hpp index 6a87db10e..90ac00319 100644 --- a/src/config/supplementary/ConfigDescriptions.hpp +++ b/src/config/supplementary/ConfigDescriptions.hpp @@ -2208,6 +2208,17 @@ namespace Config::Supplementary { .data = SConfigOptionDescription::SBoolData{.value = true}, }, + /* + * Experimental + */ + + SConfigOptionDescription{ + .value = "experimental:wp_cm_1_2", + .description = "Allow wp-cm-v1 version 2", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + /* * Quirks */ diff --git a/src/helpers/cm/ColorManagement.cpp b/src/helpers/cm/ColorManagement.cpp index bac9f25a4..829adbe7b 100644 --- a/src/helpers/cm/ColorManagement.cpp +++ b/src/helpers/cm/ColorManagement.cpp @@ -72,7 +72,7 @@ const Hyprgraphics::CMatrix3& CPrimaries::convertMatrix(const WPid(); } @@ -87,7 +87,7 @@ PImageDescription CImageDescription::from(const SImageDescription& imageDescript return knownDescriptions.back(); } -PImageDescription CImageDescription::from(const uint32_t imageDescriptionId) { +PImageDescription CImageDescription::from(const uint64_t imageDescriptionId) { ASSERT(imageDescriptionId <= knownDescriptions.size()); return knownDescriptions[imageDescriptionId - 1]; } @@ -102,7 +102,7 @@ const SImageDescription& CImageDescription::value() const { return m_imageDescription; } -uint CImageDescription::id() const { +uint64_t CImageDescription::id() const { return m_id; } diff --git a/src/helpers/cm/ColorManagement.hpp b/src/helpers/cm/ColorManagement.hpp index 0103e2a40..0bb80f425 100644 --- a/src/helpers/cm/ColorManagement.hpp +++ b/src/helpers/cm/ColorManagement.hpp @@ -65,10 +65,16 @@ namespace NColorManagement { return sc(primaries); } inline wpColorManagerV1TransferFunction convertTransferFunction(eTransferFunction tf) { - return sc(tf); + switch (tf) { + case CM_TRANSFER_FUNCTION_SRGB: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_COMPOUND_POWER_2_4; + default: return sc(tf); + } } inline eTransferFunction convertTransferFunction(wpColorManagerV1TransferFunction tf) { - return sc(tf); + switch (tf) { + case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_COMPOUND_POWER_2_4: return CM_TRANSFER_FUNCTION_SRGB; + default: return sc(tf); + } } using SPCPRimaries = Hyprgraphics::SPCPRimaries; @@ -304,19 +310,19 @@ namespace NColorManagement { class CImageDescription { public: static WP from(const SImageDescription& imageDescription); - static WP from(const uint32_t imageDescriptionId); + static WP from(const uint64_t imageDescriptionId); WP with(const SImageDescription::SPCLuminances& luminances) const; const SImageDescription& value() const; - uint32_t id() const; + uint64_t id() const; WP getPrimaries() const; private: - CImageDescription(const SImageDescription& imageDescription, const uint imageDescriptionId); - uint32_t m_id = 0; - uint32_t m_primariesId = 0; + CImageDescription(const SImageDescription& imageDescription, const uint64_t imageDescriptionId); + uint64_t m_id = 0; + uint m_primariesId = 0; SImageDescription m_imageDescription; }; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 34b5962a0..6388ef8a3 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -110,6 +110,7 @@ CProtocolManager::CProtocolManager() { static const auto PENABLECM = CConfigValue("render:cm_enabled"); static const auto PDEBUGCM = CConfigValue("debug:full_cm_proto"); + static const auto PCMV1_2 = CConfigValue("experimental:wp_cm_1_2"); static const auto PENABLECT = CConfigValue("render:commit_timing_enabled"); @@ -208,7 +209,7 @@ CProtocolManager::CProtocolManager() { PROTO::imageCopyCapture = makeUnique(&ext_image_copy_capture_manager_v1_interface, 1, "ImageCopyCapture"); if (*PENABLECM) - PROTO::colorManagement = makeUnique(&wp_color_manager_v1_interface, 1, "ColorManagement", *PDEBUGCM); + PROTO::colorManagement = makeUnique(&wp_color_manager_v1_interface, *PCMV1_2 ? 2 : 1, "ColorManagement", *PDEBUGCM); // ! please read the top of this file before adding another protocol diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index b9c3143b4..bfab02e49 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -37,7 +37,12 @@ CColorManager::CColorManager(SP resource) : m_resource(resour m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB); m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_CIE1931_XYZ); - m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB); + if (m_resource->version() == 1) { + m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB); + m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB); + } else + m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_COMPOUND_POWER_2_4); + m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22); m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28); m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR); @@ -48,7 +53,6 @@ CColorManager::CColorManager(SP resource) : m_resource(resour m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_100); m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_316); m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_XVYCC); - m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB); m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST428); m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL); @@ -57,6 +61,8 @@ CColorManager::CColorManager(SP resource) : m_resource(resour m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION); m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE); m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE_BPC); + if (m_resource->version() > 1) + m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE_NO_ADAPTATION); } m_resource->setDestroy([](CWpColorManagerV1* r) { LOGM(Log::TRACE, "Destroy WP_color_manager at {:x} (generated default)", (uintptr_t)r); }); @@ -171,7 +177,32 @@ CColorManager::CColorManager(SP resource) : m_resource(resour RESOURCE->m_self = RESOURCE; RESOURCE->m_settings = SCRGB_IMAGE_DESCRIPTION; - RESOURCE->resource()->sendReady(RESOURCE->m_settings->id()); + RESOURCE->sendMaybeReady(); + }); + + m_resource->setGetImageDescription([](CWpColorManagerV1* r, uint32_t id, wl_resource* ref) { + LOGM(Log::TRACE, "Get image description for reference={}, id={}", (uintptr_t)ref, id); + + const auto OLD_RES = CColorManagementImageDescription::fromReference(ref); + if (!OLD_RES) { + OLD_RES->resource()->sendFailed(WP_IMAGE_DESCRIPTION_V1_CAUSE_UNSUPPORTED, "Not found"); + return; + } + + const auto RESOURCE = PROTO::colorManagement->m_imageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), OLD_RES->m_allowGetInformation)); + + if UNLIKELY (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_imageDescriptions.pop_back(); + return; + } + + RESOURCE->m_self = RESOURCE; + + RESOURCE->m_settings = OLD_RES->m_settings; + + RESOURCE->sendMaybeReady(); }); m_resource->setOnDestroy([this](CWpColorManagerV1* r) { PROTO::colorManagement->destroyResource(this); }); @@ -216,7 +247,8 @@ CColorManagementOutput::CColorManagementOutput(SP re RESOURCE->m_resource->sendFailed(WP_IMAGE_DESCRIPTION_V1_CAUSE_NO_OUTPUT, "No output"); else { RESOURCE->m_settings = m_output->m_monitor->m_imageDescription; - RESOURCE->m_resource->sendReady(RESOURCE->m_settings->id()); + + RESOURCE->sendMaybeReady(); } }); } @@ -364,7 +396,7 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SPm_self = RESOURCE; RESOURCE->m_settings = m_surface->getPreferredImageDescription(); - RESOURCE->resource()->sendReady(RESOURCE->m_settings->id()); + RESOURCE->sendMaybeReady(); }); m_resource->setGetPreferredParametric([this](CWpColorManagementSurfaceFeedbackV1* r, uint32_t id) { @@ -388,7 +420,13 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SPm_settings = m_surface->getPreferredImageDescription(); m_currentPreferredId = RESOURCE->m_settings->id(); - RESOURCE->resource()->sendReady(m_currentPreferredId); + if (!PROTO::colorManagement->m_debug && RESOURCE->m_settings->value().icc.present) { + LOGM(Log::ERR, "FIXME: send ICC profile data"); + // r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "ICC profiles are not supported"); + // return; + } + + RESOURCE->sendMaybeReady(); }); m_listeners.enter = m_surface->m_events.enter.listen([this](const auto& monitor) { onPreferredChanged(); }); @@ -398,8 +436,14 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SPm_enteredOutputs.size() == 1) { const auto newId = m_surface->getPreferredImageDescription()->id(); - if (m_currentPreferredId != newId) - m_resource->sendPreferredChanged(newId); + if (m_currentPreferredId != newId) { + const uint32_t lo = sc(newId & 0xFFFFFFFF); + const uint32_t hi = sc(newId >> 32); + if (m_resource->version() > 1) + m_resource->sendPreferredChanged2(hi, lo); + else if (!hi) + m_resource->sendPreferredChanged(lo); + } } } @@ -447,7 +491,8 @@ CColorManagementIccCreator::CColorManagementIccCreator(SPm_self = RESOURCE; RESOURCE->m_settings = CImageDescription::from(m_settings); - RESOURCE->resource()->sendReady(RESOURCE->m_settings->id()); + + RESOURCE->sendMaybeReady(); PROTO::colorManagement->destroyResource(this); }); @@ -509,7 +554,8 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPm_self = RESOURCE; RESOURCE->m_settings = CImageDescription::from(m_settings); - RESOURCE->resource()->sendReady(RESOURCE->m_settings->id()); + + RESOURCE->sendMaybeReady(); PROTO::colorManagement->destroyResource(this); }); @@ -534,6 +580,7 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPerror(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_TF, "Unsupported transfer function"); return; } @@ -704,6 +751,11 @@ CColorManagementImageDescription::CColorManagementImageDescription(SP CColorManagementImageDescription::fromReference(wl_resource* res) { + auto data = sc(sc(wl_resource_get_user_data(res))->data()); + return data ? data->m_self.lock() : nullptr; +} + bool CColorManagementImageDescription::good() { return m_resource->resource(); } @@ -716,6 +768,22 @@ SP CColorManagementImageDescription::resource() { return m_resource; } +bool CColorManagementImageDescription::sendMaybeReady() { + const uint32_t lo = sc(m_settings->id() & 0xFFFFFFFF); + const uint32_t hi = sc(m_settings->id() >> 32); + + if (m_resource->version() > 1) + m_resource->sendReady2(hi, lo); + else if (!hi) + m_resource->sendReady(lo); + else { + m_resource->sendFailed(WP_IMAGE_DESCRIPTION_V1_CAUSE_LOW_VERSION, "id is too large"); + return false; + } + + return true; +} + CColorManagementImageDescriptionInfo::CColorManagementImageDescriptionInfo(SP resource, const SImageDescription& settings_) : m_resource(resource), m_settings(settings_) { if UNLIKELY (!good()) diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp index 7cdab37dc..14700c987 100644 --- a/src/protocols/ColorManagement.hpp +++ b/src/protocols/ColorManagement.hpp @@ -87,7 +87,7 @@ class CColorManagementFeedbackSurface { SP m_resource; wl_client* m_client = nullptr; - uint32_t m_currentPreferredId = 0; + uint64_t m_currentPreferredId = 0; struct { CHyprSignalListener enter; @@ -154,20 +154,23 @@ class CColorManagementParametricCreator { class CColorManagementImageDescription { public: CColorManagementImageDescription(SP resource, bool allowGetInformation); + static SP fromReference(wl_resource* res); - bool good(); - wl_client* client(); - SP resource(); + bool good(); + wl_client* client(); + SP resource(); + bool sendMaybeReady(); - WP m_self; + WP m_self; - NColorManagement::PImageDescription m_settings; + NColorManagement::PImageDescription m_settings; private: SP m_resource; wl_client* m_client = nullptr; bool m_allowGetInformation = false; + friend class CColorManager; friend class CColorManagementOutput; };