From bde6a60f4060c109656506acc7033e465bf44410 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 5 Dec 2024 00:11:10 +0300 Subject: [PATCH 01/10] hdr & colorspace properties --- include/aquamarine/backend/DRM.hpp | 20 ++++++++++++++++---- src/backend/drm/DRM.cpp | 7 +++++++ src/backend/drm/Props.cpp | 28 ++++++++++++++++++++++++++++ src/backend/drm/Props.hpp | 1 + 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index 3347cda..b5c9c21 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -315,17 +315,29 @@ namespace Aquamarine { uint32_t vrr_capable; // not guaranteed to exist uint32_t subconnector; // not guaranteed to exist uint32_t non_desktop; - uint32_t panel_orientation; // not guaranteed to exist - uint32_t content_type; // not guaranteed to exist - uint32_t max_bpc; // not guaranteed to exist + uint32_t panel_orientation; // not guaranteed to exist + uint32_t content_type; // not guaranteed to exist + uint32_t max_bpc; // not guaranteed to exist + uint32_t Colorspace; // not guaranteed to exist + uint32_t hdr_output_metadata; // not guaranteed to exist // atomic-modesetting only uint32_t crtc_id; }; - uint32_t props[4] = {0}; + uint32_t props[13] = {0}; }; UDRMConnectorProps props; + + union UDRMConnectorColorspace { + struct { + uint32_t Default; + uint32_t BT2020_RGB; + uint32_t BT2020_YCC; + }; + uint32_t props[3] = {0}; + }; + UDRMConnectorColorspace colorspace; }; class IDRMImplementation { diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index f0f37af..f2019fb 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1082,6 +1082,8 @@ bool Aquamarine::SDRMConnector::init(drmModeConnector* connector) { if (!getDRMConnectorProps(backend->gpu->fd, id, &props)) return false; + if (props.Colorspace) + getDRMConnectorColorspace(backend->gpu->fd, props.Colorspace, &colorspace); auto name = drmModeGetConnectorTypeName(connector->connector_type); if (!name) @@ -1188,6 +1190,11 @@ void Aquamarine::SDRMConnector::recheckCRTCProps() { backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Explicit sync {}", output->supportsExplicit ? "supported" : "unsupported")); backend->backend->log(AQ_LOG_DEBUG, std::format("drm: connector {} crtc {} CTM", szName, (crtc->props.ctm ? "supports" : "doesn't support"))); + + backend->backend->log(AQ_LOG_DEBUG, + std::format("drm: connector {} crtc {} HDR ({})", szName, (props.hdr_output_metadata ? "supports" : "doesn't support"), props.hdr_output_metadata)); + + backend->backend->log(AQ_LOG_DEBUG, std::format("drm: connector {} crtc {} Colorspace ({})", szName, (props.Colorspace ? "supports" : "doesn't support"), props.Colorspace)); } void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) { diff --git a/src/backend/drm/Props.cpp b/src/backend/drm/Props.cpp index 3f8128b..9434e51 100644 --- a/src/backend/drm/Props.cpp +++ b/src/backend/drm/Props.cpp @@ -21,8 +21,10 @@ struct prop_info { static const struct prop_info connector_info[] = { #define INDEX(name) (offsetof(SDRMConnector::UDRMConnectorProps, name) / sizeof(uint32_t)) {"CRTC_ID", INDEX(crtc_id)}, + {"Colorspace", INDEX(Colorspace)}, {"DPMS", INDEX(dpms)}, {"EDID", INDEX(edid)}, + {"HDR_OUTPUT_METADATA", INDEX(hdr_output_metadata)}, {"PATH", INDEX(path)}, {"content type", INDEX(content_type)}, {"link-status", INDEX(link_status)}, @@ -34,6 +36,12 @@ static const struct prop_info connector_info[] = { #undef INDEX }; +static const struct prop_info colorspace_info[] = { +#define INDEX(name) (offsetof(SDRMConnector::UDRMConnectorColorspace, name) / sizeof(uint32_t)) + {"BT2020_RGB", INDEX(BT2020_RGB)}, {"BT2020_YCC", INDEX(BT2020_YCC)}, {"Default", INDEX(Default)} +#undef INDEX +}; + static const struct prop_info crtc_info[] = { #define INDEX(name) (offsetof(SDRMCRTC::UDRMCRTCProps, name) / sizeof(uint32_t)) {"ACTIVE", INDEX(active)}, {"CTM", INDEX(ctm)}, @@ -95,10 +103,30 @@ namespace Aquamarine { return true; } + static bool scanPropertyEnum(int fd, uint32_t propertyId, uint32_t* result, const prop_info* info, size_t info_len) { + drmModePropertyRes* prop = drmModeGetProperty(fd, propertyId); + if (!prop) + return false; + + for (uint32_t i = 0; i < prop->count_enums; ++i) { + const prop_info* p = (prop_info*)bsearch(prop->enums[i].name, info, info_len, sizeof(info[0]), comparePropInfo); + if (p) + result[p->index] = prop->enums[i].value; + } + + drmModeFreeProperty(prop); + + return true; + } + bool getDRMConnectorProps(int fd, uint32_t id, SDRMConnector::UDRMConnectorProps* out) { return scanProperties(fd, id, DRM_MODE_OBJECT_CONNECTOR, out->props, connector_info, sizeof(connector_info) / sizeof(connector_info[0])); } + bool getDRMConnectorColorspace(int fd, uint32_t id, SDRMConnector::UDRMConnectorColorspace* out) { + return scanPropertyEnum(fd, id, out->props, colorspace_info, sizeof(colorspace_info) / sizeof(colorspace_info[0])); + } + bool getDRMCRTCProps(int fd, uint32_t id, SDRMCRTC::UDRMCRTCProps* out) { return scanProperties(fd, id, DRM_MODE_OBJECT_CRTC, out->props, crtc_info, sizeof(crtc_info) / sizeof(crtc_info[0])); } diff --git a/src/backend/drm/Props.hpp b/src/backend/drm/Props.hpp index 24a7806..371ff60 100644 --- a/src/backend/drm/Props.hpp +++ b/src/backend/drm/Props.hpp @@ -4,6 +4,7 @@ namespace Aquamarine { bool getDRMConnectorProps(int fd, uint32_t id, SDRMConnector::UDRMConnectorProps* out); + bool getDRMConnectorColorspace(int fd, uint32_t id, SDRMConnector::UDRMConnectorColorspace* out); bool getDRMCRTCProps(int fd, uint32_t id, SDRMCRTC::UDRMCRTCProps* out); bool getDRMPlaneProps(int fd, uint32_t id, SDRMPlane::UDRMPlaneProps* out); bool getDRMProp(int fd, uint32_t obj, uint32_t prop, uint64_t* ret); From 4d7a079729c855acc349c0408c92489d41512f33 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 5 Dec 2024 15:23:06 +0300 Subject: [PATCH 02/10] parse edid hdr metadata --- include/aquamarine/backend/DRM.hpp | 17 +++++++- include/aquamarine/output/Output.hpp | 2 + src/backend/drm/DRM.cpp | 58 ++++++++++++++++++++++++---- 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index b5c9c21..158c68c 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -261,6 +261,20 @@ namespace Aquamarine { void calculateMode(Hyprutils::Memory::CSharedPointer connector); }; + struct HDRMetadata { + bool supported = false; + double desiredContentMinLuminance; + std::optional desiredContentMaxLuminance; + std::optional desiredMaxFrameAverageLuminance; + bool supportsPQ; + bool supportsBT2020; + }; + + struct ParsedEDID { + std::string make, serial, model; + HDRMetadata hdrMetadata = {}; + }; + struct SDRMConnector { ~SDRMConnector(); @@ -269,7 +283,7 @@ namespace Aquamarine { void disconnect(); Hyprutils::Memory::CSharedPointer getCurrentCRTC(const drmModeConnector* connector); drmModeModeInfo* getCurrentMode(); - void parseEDID(std::vector data); + ParsedEDID parseEDID(std::vector data); bool commitState(SDRMConnectorCommitData& data); void applyCommit(const SDRMConnectorCommitData& data); void rollbackCommit(const SDRMConnectorCommitData& data); @@ -287,6 +301,7 @@ namespace Aquamarine { int32_t refresh = 0; uint32_t possibleCrtcs = 0; std::string make, serial, model; + HDRMetadata hdrMetadata; bool canDoVrr = false; bool cursorEnabled = false; diff --git a/include/aquamarine/output/Output.hpp b/include/aquamarine/output/Output.hpp index 1288a1f..96137a8 100644 --- a/include/aquamarine/output/Output.hpp +++ b/include/aquamarine/output/Output.hpp @@ -11,6 +11,7 @@ #include "../allocator/Swapchain.hpp" #include "../buffer/Buffer.hpp" #include "../backend/Misc.hpp" +#include "aquamarine/backend/DRM.hpp" namespace Aquamarine { @@ -133,6 +134,7 @@ namespace Aquamarine { virtual bool destroy(); // not all backends allow this!!! std::string name, description, make, model, serial; + HDRMetadata hdrMetadata; Hyprutils::Math::Vector2D physicalSize; bool enabled = false; bool nonDesktop = false; diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index f2019fb..1df1d7b 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -19,6 +19,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -1149,11 +1150,12 @@ drmModeModeInfo* Aquamarine::SDRMConnector::getCurrentMode() { return modeInfo; } -void Aquamarine::SDRMConnector::parseEDID(std::vector data) { - auto info = di_info_parse_edid(data.data(), data.size()); +ParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { + auto info = di_info_parse_edid(data.data(), data.size()); + ParsedEDID parsed = {}; if (!info) { backend->backend->log(AQ_LOG_ERROR, "drm: failed to parse edid"); - return; + return parsed; } auto edid = di_info_get_edid(info); @@ -1170,7 +1172,48 @@ void Aquamarine::SDRMConnector::parseEDID(std::vector data) { model = mod ? mod : ""; serial = ser ? ser : ""; + parsed.make = make; + parsed.model = model; + parsed.serial = serial; + + // copied from kwin + const di_edid_cta* cta = nullptr; + const di_edid_ext* const* exts = di_edid_get_extensions(edid); + const di_cta_hdr_static_metadata_block* hdr_static_metadata = nullptr; + const di_cta_colorimetry_block* colorimetry = nullptr; + for (; *exts != nullptr; exts++) { + if (!cta && (cta = di_edid_ext_get_cta(*exts))) { + continue; + } + } + if (cta) { + const di_cta_data_block* const* blocks = di_edid_cta_get_data_blocks(cta); + for (; *blocks != nullptr; blocks++) { + if (!hdr_static_metadata && (hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(*blocks))) { + continue; + } + if (!colorimetry && (colorimetry = di_cta_data_block_get_colorimetry(*blocks))) { + continue; + } + } + if (hdr_static_metadata) { + hdrMetadata = parsed.hdrMetadata = HDRMetadata{ + .supported = true, + .desiredContentMinLuminance = hdr_static_metadata->desired_content_min_luminance, + .desiredContentMaxLuminance = + hdr_static_metadata->desired_content_max_luminance > 0 ? std::make_optional(hdr_static_metadata->desired_content_max_luminance) : std::nullopt, + .desiredMaxFrameAverageLuminance = hdr_static_metadata->desired_content_max_frame_avg_luminance > 0 ? + std::make_optional(hdr_static_metadata->desired_content_max_frame_avg_luminance) : + std::nullopt, + .supportsPQ = hdr_static_metadata->eotfs->pq, + .supportsBT2020 = colorimetry && colorimetry->bt2020_rgb, + }; + } + } + di_info_destroy(info); + + return parsed; } void Aquamarine::SDRMConnector::recheckCRTCProps() { @@ -1277,16 +1320,17 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) { uint8_t* edidData = (uint8_t*)getDRMPropBlob(backend->gpu->fd, id, props.edid, &edidLen); std::vector edid{edidData, edidData + edidLen}; - parseEDID(edid); + auto parsedEDID = parseEDID(edid); free(edidData); edid = {}; // TODO: subconnectors - output->make = make; - output->model = model; - output->serial = serial; + output->make = parsedEDID.make; + output->model = parsedEDID.model; + output->serial = parsedEDID.serial; + output->hdrMetadata = parsedEDID.hdrMetadata; output->description = std::format("{} {} {} ({})", make, model, serial, szName); output->needsFrame = true; From d39cdfecb7173a4137f99f3a5167d8813333b365 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 5 Dec 2024 19:51:53 +0300 Subject: [PATCH 03/10] pass hdr metadata blob --- include/aquamarine/backend/DRM.hpp | 4 ++++ include/aquamarine/output/Output.hpp | 7 +++++-- src/backend/drm/DRM.cpp | 15 ++++++++++++++- src/backend/drm/impl/Atomic.cpp | 19 +++++++++++++++++++ src/output/Output.cpp | 9 +++++++++ 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index 158c68c..e942463 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -4,6 +4,7 @@ #include "../allocator/Swapchain.hpp" #include "../output/Output.hpp" #include "../input/Input.hpp" +#include #include #include #include @@ -247,15 +248,18 @@ namespace Aquamarine { bool test = false; drmModeModeInfo modeInfo; std::optional ctm; + std::optional hdrMetadata; struct { uint32_t gammaLut = 0; uint32_t fbDamage = 0; uint32_t modeBlob = 0; uint32_t ctmBlob = 0; + uint32_t hdrBlob = 0; bool blobbed = false; bool gammad = false; bool ctmd = false; + bool hdrd = false; } atomic; void calculateMode(Hyprutils::Memory::CSharedPointer connector); diff --git a/include/aquamarine/output/Output.hpp b/include/aquamarine/output/Output.hpp index 96137a8..5895758 100644 --- a/include/aquamarine/output/Output.hpp +++ b/include/aquamarine/output/Output.hpp @@ -11,7 +11,6 @@ #include "../allocator/Swapchain.hpp" #include "../buffer/Buffer.hpp" #include "../backend/Misc.hpp" -#include "aquamarine/backend/DRM.hpp" namespace Aquamarine { @@ -54,6 +53,7 @@ namespace Aquamarine { AQ_OUTPUT_STATE_EXPLICIT_IN_FENCE = (1 << 8), AQ_OUTPUT_STATE_EXPLICIT_OUT_FENCE = (1 << 9), AQ_OUTPUT_STATE_CTM = (1 << 10), + AQ_OUTPUT_STATE_HDR = (1 << 11), }; struct SInternalState { @@ -71,6 +71,8 @@ namespace Aquamarine { Hyprutils::Memory::CSharedPointer buffer; int32_t explicitInFence = -1, explicitOutFence = -1; Hyprutils::Math::Mat3x3 ctm; + bool wideColorGamut = false; + hdr_output_metadata hdrMetadata; }; const SInternalState& state(); @@ -89,6 +91,8 @@ namespace Aquamarine { void enableExplicitOutFenceForNextCommit(); void resetExplicitFences(); void setCTM(const Hyprutils::Math::Mat3x3& ctm); + void setWideColorGamut(bool wcg); + void setHDRMetadata(hdr_output_metadata& metadata); private: SInternalState internalState; @@ -134,7 +138,6 @@ namespace Aquamarine { virtual bool destroy(); // not all backends allow this!!! std::string name, description, make, model, serial; - HDRMetadata hdrMetadata; Hyprutils::Math::Vector2D physicalSize; bool enabled = false; bool nonDesktop = false; diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 1df1d7b..5b77723 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1177,6 +1177,17 @@ ParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { parsed.serial = serial; // copied from kwin + // const auto chromaticity = di_edid_get_chromaticity_coords(edid); + // if (chromaticity) { + // m_colorimetry = Colorimetry{ + // xy{chromaticity->red_x, chromaticity->red_y}, + // xy{chromaticity->green_x, chromaticity->green_y}, + // xy{chromaticity->blue_x, chromaticity->blue_y}, + // xy{chromaticity->white_x, chromaticity->white_y}, + // }; + // } else { + // m_colorimetry.reset(); + // } const di_edid_cta* cta = nullptr; const di_edid_ext* const* exts = di_edid_get_extensions(edid); const di_cta_hdr_static_metadata_block* hdr_static_metadata = nullptr; @@ -1330,7 +1341,6 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) { output->make = parsedEDID.make; output->model = parsedEDID.model; output->serial = parsedEDID.serial; - output->hdrMetadata = parsedEDID.hdrMetadata; output->description = std::format("{} {} {} ({})", make, model, serial, szName); output->needsFrame = true; @@ -1641,6 +1651,9 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) { if (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_CTM) data.ctm = STATE.ctm; + if (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_HDR) + data.hdrMetadata = STATE.hdrMetadata; + data.blocking = BLOCKING || formatMismatch; data.modeset = NEEDS_RECONFIG || lastCommitNoBuffer || formatMismatch; data.flags = flags; diff --git a/src/backend/drm/impl/Atomic.cpp b/src/backend/drm/impl/Atomic.cpp index 2eae330..21f1c6d 100644 --- a/src/backend/drm/impl/Atomic.cpp +++ b/src/backend/drm/impl/Atomic.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -103,6 +104,12 @@ void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPoint add(connector->crtc->id, connector->crtc->props.active, enable); if (enable) { + if (connector->props.Colorspace && connector->colorspace.BT2020_RGB) + add(connector->id, connector->props.Colorspace, STATE.wideColorGamut ? connector->colorspace.BT2020_RGB : connector->colorspace.Default); + + if (connector->props.hdr_output_metadata && data.atomic.hdrd) + add(connector->id, connector->props.hdr_output_metadata, data.atomic.hdrBlob); + if (connector->output->supportsExplicit && STATE.committed & COutputState::AQ_OUTPUT_STATE_EXPLICIT_OUT_FENCE) add(connector->crtc->id, connector->crtc->props.out_fence_ptr, (uintptr_t)&STATE.explicitOutFence); @@ -295,6 +302,18 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin } } + if ((STATE.committed & COutputState::AQ_OUTPUT_STATE_HDR) && data.hdrMetadata.has_value()) { + if (!connector->props.hdr_output_metadata) + connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to commit hdr metadata: no HDR_OUTPUT_METADATA prop support"); + else { + if (drmModeCreatePropertyBlob(connector->backend->gpu->fd, &data.hdrMetadata.value(), sizeof(hdr_output_metadata), &data.atomic.hdrBlob)) { + connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to create a hdr metadata blob"); + data.atomic.hdrBlob = 0; + } else + data.atomic.hdrd = true; + } + } + if ((STATE.committed & COutputState::AQ_OUTPUT_STATE_DAMAGE) && connector->crtc->primary->props.fb_damage_clips && MODE) { if (STATE.damage.empty()) data.atomic.fbDamage = 0; diff --git a/src/output/Output.cpp b/src/output/Output.cpp index 6186eb1..758bbcd 100644 --- a/src/output/Output.cpp +++ b/src/output/Output.cpp @@ -119,6 +119,15 @@ void Aquamarine::COutputState::setCTM(const Hyprutils::Math::Mat3x3& ctm) { internalState.committed |= AQ_OUTPUT_STATE_CTM; } +void Aquamarine::COutputState::setWideColorGamut(bool wcg) { + internalState.wideColorGamut = wcg; +} + +void Aquamarine::COutputState::setHDRMetadata(hdr_output_metadata& metadata) { + internalState.hdrMetadata = metadata; + internalState.committed |= AQ_OUTPUT_STATE_HDR; +} + void Aquamarine::COutputState::onCommit() { internalState.committed = 0; internalState.damage.clear(); From 9824f1e2c714d20a3cc37b7481edf14cd21e85d6 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 5 Dec 2024 20:52:15 +0300 Subject: [PATCH 04/10] expose edid hdr info --- include/aquamarine/backend/DRM.hpp | 17 +------------- include/aquamarine/output/Output.hpp | 28 +++++++++++++++++++++++ src/backend/drm/DRM.cpp | 34 +++++++++++++++------------- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index e942463..e3e72e7 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -265,20 +265,6 @@ namespace Aquamarine { void calculateMode(Hyprutils::Memory::CSharedPointer connector); }; - struct HDRMetadata { - bool supported = false; - double desiredContentMinLuminance; - std::optional desiredContentMaxLuminance; - std::optional desiredMaxFrameAverageLuminance; - bool supportsPQ; - bool supportsBT2020; - }; - - struct ParsedEDID { - std::string make, serial, model; - HDRMetadata hdrMetadata = {}; - }; - struct SDRMConnector { ~SDRMConnector(); @@ -287,7 +273,7 @@ namespace Aquamarine { void disconnect(); Hyprutils::Memory::CSharedPointer getCurrentCRTC(const drmModeConnector* connector); drmModeModeInfo* getCurrentMode(); - ParsedEDID parseEDID(std::vector data); + IOutput::ParsedEDID parseEDID(std::vector data); bool commitState(SDRMConnectorCommitData& data); void applyCommit(const SDRMConnectorCommitData& data); void rollbackCommit(const SDRMConnectorCommitData& data); @@ -305,7 +291,6 @@ namespace Aquamarine { int32_t refresh = 0; uint32_t possibleCrtcs = 0; std::string make, serial, model; - HDRMetadata hdrMetadata; bool canDoVrr = false; bool cursorEnabled = false; diff --git a/include/aquamarine/output/Output.hpp b/include/aquamarine/output/Output.hpp index 5895758..9ba10a1 100644 --- a/include/aquamarine/output/Output.hpp +++ b/include/aquamarine/output/Output.hpp @@ -124,6 +124,33 @@ namespace Aquamarine { AQ_SCHEDULE_ANIMATION_DAMAGE, }; + struct HDRMetadata { + bool supported = false; + double desiredContentMinLuminance; + std::optional desiredContentMaxLuminance; + std::optional desiredMaxFrameAverageLuminance; + bool supportsPQ; + bool supportsBT2020; + }; + + struct xy { + double x = 0; + double y = 0; + }; + + struct ChromaticityCoords { + xy red; + xy green; + xy blue; + xy white; + }; + + struct ParsedEDID { + std::string make, serial, model; + std::optional hdrMetadata; + std::optional chromaticityCoords; + }; + virtual bool commit() = 0; virtual bool test() = 0; virtual Hyprutils::Memory::CSharedPointer getBackend() = 0; @@ -138,6 +165,7 @@ namespace Aquamarine { virtual bool destroy(); // not all backends allow this!!! std::string name, description, make, model, serial; + ParsedEDID parsedEDID; Hyprutils::Math::Vector2D physicalSize; bool enabled = false; bool nonDesktop = false; diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 5b77723..c482461 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1150,9 +1150,9 @@ drmModeModeInfo* Aquamarine::SDRMConnector::getCurrentMode() { return modeInfo; } -ParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { - auto info = di_info_parse_edid(data.data(), data.size()); - ParsedEDID parsed = {}; +IOutput::ParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { + auto info = di_info_parse_edid(data.data(), data.size()); + IOutput::ParsedEDID parsed = {}; if (!info) { backend->backend->log(AQ_LOG_ERROR, "drm: failed to parse edid"); return parsed; @@ -1177,17 +1177,17 @@ ParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { parsed.serial = serial; // copied from kwin - // const auto chromaticity = di_edid_get_chromaticity_coords(edid); - // if (chromaticity) { - // m_colorimetry = Colorimetry{ - // xy{chromaticity->red_x, chromaticity->red_y}, - // xy{chromaticity->green_x, chromaticity->green_y}, - // xy{chromaticity->blue_x, chromaticity->blue_y}, - // xy{chromaticity->white_x, chromaticity->white_y}, - // }; - // } else { - // m_colorimetry.reset(); - // } + const auto chromaticity = di_edid_get_chromaticity_coords(edid); + if (chromaticity) { + parsed.chromaticityCoords = IOutput::ChromaticityCoords{ + IOutput::xy{chromaticity->red_x, chromaticity->red_y}, + IOutput::xy{chromaticity->green_x, chromaticity->green_y}, + IOutput::xy{chromaticity->blue_x, chromaticity->blue_y}, + IOutput::xy{chromaticity->white_x, chromaticity->white_y}, + }; + } else { + parsed.chromaticityCoords.reset(); + } const di_edid_cta* cta = nullptr; const di_edid_ext* const* exts = di_edid_get_extensions(edid); const di_cta_hdr_static_metadata_block* hdr_static_metadata = nullptr; @@ -1208,8 +1208,7 @@ ParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { } } if (hdr_static_metadata) { - hdrMetadata = parsed.hdrMetadata = HDRMetadata{ - .supported = true, + parsed.hdrMetadata = IOutput::HDRMetadata{ .desiredContentMinLuminance = hdr_static_metadata->desired_content_min_luminance, .desiredContentMaxLuminance = hdr_static_metadata->desired_content_max_luminance > 0 ? std::make_optional(hdr_static_metadata->desired_content_max_luminance) : std::nullopt, @@ -1219,6 +1218,8 @@ ParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { .supportsPQ = hdr_static_metadata->eotfs->pq, .supportsBT2020 = colorimetry && colorimetry->bt2020_rgb, }; + } else { + parsed.hdrMetadata.reset(); } } @@ -1341,6 +1342,7 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) { output->make = parsedEDID.make; output->model = parsedEDID.model; output->serial = parsedEDID.serial; + output->parsedEDID = parsedEDID; output->description = std::format("{} {} {} ({})", make, model, serial, szName); output->needsFrame = true; From edfc44fb19dbb8d12bc066b5f92942bfa9a26b34 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Fri, 6 Dec 2024 20:46:25 +0300 Subject: [PATCH 05/10] styling fixes and rewrites --- include/aquamarine/backend/DRM.hpp | 3 +- include/aquamarine/output/Output.hpp | 25 ++++++----- src/backend/drm/DRM.cpp | 63 ++++++++++++---------------- src/backend/drm/Props.cpp | 4 +- src/backend/drm/impl/Atomic.cpp | 9 ++-- 5 files changed, 48 insertions(+), 56 deletions(-) diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index e3e72e7..4058126 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -4,7 +4,6 @@ #include "../allocator/Swapchain.hpp" #include "../output/Output.hpp" #include "../input/Input.hpp" -#include #include #include #include @@ -273,7 +272,7 @@ namespace Aquamarine { void disconnect(); Hyprutils::Memory::CSharedPointer getCurrentCRTC(const drmModeConnector* connector); drmModeModeInfo* getCurrentMode(); - IOutput::ParsedEDID parseEDID(std::vector data); + IOutput::SParsedEDID parseEDID(std::vector data); bool commitState(SDRMConnectorCommitData& data); void applyCommit(const SDRMConnectorCommitData& data); void rollbackCommit(const SDRMConnectorCommitData& data); diff --git a/include/aquamarine/output/Output.hpp b/include/aquamarine/output/Output.hpp index 9ba10a1..914f1a7 100644 --- a/include/aquamarine/output/Output.hpp +++ b/include/aquamarine/output/Output.hpp @@ -124,13 +124,11 @@ namespace Aquamarine { AQ_SCHEDULE_ANIMATION_DAMAGE, }; - struct HDRMetadata { - bool supported = false; - double desiredContentMinLuminance; - std::optional desiredContentMaxLuminance; - std::optional desiredMaxFrameAverageLuminance; - bool supportsPQ; - bool supportsBT2020; + struct SHDRMetadata { + float desiredContentMaxLuminance = 0; + float desiredMaxFrameAverageLuminance = 0; + float desiredContentMinLuminance = 0; + bool supportsPQ = false; }; struct xy { @@ -138,17 +136,18 @@ namespace Aquamarine { double y = 0; }; - struct ChromaticityCoords { + struct SChromaticityCoords { xy red; xy green; xy blue; xy white; }; - struct ParsedEDID { - std::string make, serial, model; - std::optional hdrMetadata; - std::optional chromaticityCoords; + struct SParsedEDID { + std::string make, serial, model; + std::optional hdrMetadata; + std::optional chromaticityCoords; + bool supportsBT2020 = false; }; virtual bool commit() = 0; @@ -165,7 +164,7 @@ namespace Aquamarine { virtual bool destroy(); // not all backends allow this!!! std::string name, description, make, model, serial; - ParsedEDID parsedEDID; + SParsedEDID parsedEDID; Hyprutils::Math::Vector2D physicalSize; bool enabled = false; bool nonDesktop = false; diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index c482461..895e1b3 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1150,9 +1150,9 @@ drmModeModeInfo* Aquamarine::SDRMConnector::getCurrentMode() { return modeInfo; } -IOutput::ParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { - auto info = di_info_parse_edid(data.data(), data.size()); - IOutput::ParsedEDID parsed = {}; +IOutput::SParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { + auto info = di_info_parse_edid(data.data(), data.size()); + IOutput::SParsedEDID parsed = {}; if (!info) { backend->backend->log(AQ_LOG_ERROR, "drm: failed to parse edid"); return parsed; @@ -1176,50 +1176,39 @@ IOutput::ParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector da parsed.model = model; parsed.serial = serial; - // copied from kwin const auto chromaticity = di_edid_get_chromaticity_coords(edid); if (chromaticity) { - parsed.chromaticityCoords = IOutput::ChromaticityCoords{ + parsed.chromaticityCoords = IOutput::SChromaticityCoords{ IOutput::xy{chromaticity->red_x, chromaticity->red_y}, IOutput::xy{chromaticity->green_x, chromaticity->green_y}, IOutput::xy{chromaticity->blue_x, chromaticity->blue_y}, IOutput::xy{chromaticity->white_x, chromaticity->white_y}, }; - } else { - parsed.chromaticityCoords.reset(); } - const di_edid_cta* cta = nullptr; - const di_edid_ext* const* exts = di_edid_get_extensions(edid); - const di_cta_hdr_static_metadata_block* hdr_static_metadata = nullptr; - const di_cta_colorimetry_block* colorimetry = nullptr; + + auto exts = di_edid_get_extensions(edid); for (; *exts != nullptr; exts++) { - if (!cta && (cta = di_edid_ext_get_cta(*exts))) { - continue; - } - } - if (cta) { - const di_cta_data_block* const* blocks = di_edid_cta_get_data_blocks(cta); - for (; *blocks != nullptr; blocks++) { - if (!hdr_static_metadata && (hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(*blocks))) { - continue; - } - if (!colorimetry && (colorimetry = di_cta_data_block_get_colorimetry(*blocks))) { - continue; + const auto cta = di_edid_ext_get_cta(*exts); + if (cta) { + const di_cta_hdr_static_metadata_block* hdr_static_metadata = nullptr; + const di_cta_colorimetry_block* colorimetry = nullptr; + auto blocks = di_edid_cta_get_data_blocks(cta); + for (; *blocks != nullptr; blocks++) { + if (!hdr_static_metadata && (hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(*blocks))) { + parsed.hdrMetadata = IOutput::SHDRMetadata{ + .desiredContentMaxLuminance = hdr_static_metadata->desired_content_max_luminance, + .desiredMaxFrameAverageLuminance = hdr_static_metadata->desired_content_max_frame_avg_luminance, + .desiredContentMinLuminance = hdr_static_metadata->desired_content_min_luminance, + .supportsPQ = hdr_static_metadata->eotfs->pq, + }; + continue; + } + if (!colorimetry && (colorimetry = di_cta_data_block_get_colorimetry(*blocks))) { + parsed.supportsBT2020 = colorimetry->bt2020_rgb; + continue; + } } - } - if (hdr_static_metadata) { - parsed.hdrMetadata = IOutput::HDRMetadata{ - .desiredContentMinLuminance = hdr_static_metadata->desired_content_min_luminance, - .desiredContentMaxLuminance = - hdr_static_metadata->desired_content_max_luminance > 0 ? std::make_optional(hdr_static_metadata->desired_content_max_luminance) : std::nullopt, - .desiredMaxFrameAverageLuminance = hdr_static_metadata->desired_content_max_frame_avg_luminance > 0 ? - std::make_optional(hdr_static_metadata->desired_content_max_frame_avg_luminance) : - std::nullopt, - .supportsPQ = hdr_static_metadata->eotfs->pq, - .supportsBT2020 = colorimetry && colorimetry->bt2020_rgb, - }; - } else { - parsed.hdrMetadata.reset(); + break; } } diff --git a/src/backend/drm/Props.cpp b/src/backend/drm/Props.cpp index 9434e51..ef777d2 100644 --- a/src/backend/drm/Props.cpp +++ b/src/backend/drm/Props.cpp @@ -38,7 +38,9 @@ static const struct prop_info connector_info[] = { static const struct prop_info colorspace_info[] = { #define INDEX(name) (offsetof(SDRMConnector::UDRMConnectorColorspace, name) / sizeof(uint32_t)) - {"BT2020_RGB", INDEX(BT2020_RGB)}, {"BT2020_YCC", INDEX(BT2020_YCC)}, {"Default", INDEX(Default)} + {"BT2020_RGB", INDEX(BT2020_RGB)}, + {"BT2020_YCC", INDEX(BT2020_YCC)}, + {"Default", INDEX(Default)}, #undef INDEX }; diff --git a/src/backend/drm/impl/Atomic.cpp b/src/backend/drm/impl/Atomic.cpp index 21f1c6d..940c6c8 100644 --- a/src/backend/drm/impl/Atomic.cpp +++ b/src/backend/drm/impl/Atomic.cpp @@ -107,8 +107,8 @@ void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPoint if (connector->props.Colorspace && connector->colorspace.BT2020_RGB) add(connector->id, connector->props.Colorspace, STATE.wideColorGamut ? connector->colorspace.BT2020_RGB : connector->colorspace.Default); - if (connector->props.hdr_output_metadata && data.atomic.hdrd) - add(connector->id, connector->props.hdr_output_metadata, data.atomic.hdrBlob); + if (connector->props.hdr_output_metadata) + add(connector->id, connector->props.hdr_output_metadata, data.atomic.hdrd ? data.atomic.hdrBlob : 0); if (connector->output->supportsExplicit && STATE.committed & COutputState::AQ_OUTPUT_STATE_EXPLICIT_OUT_FENCE) add(connector->crtc->id, connector->crtc->props.out_fence_ptr, (uintptr_t)&STATE.explicitOutFence); @@ -306,7 +306,10 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin if (!connector->props.hdr_output_metadata) connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to commit hdr metadata: no HDR_OUTPUT_METADATA prop support"); else { - if (drmModeCreatePropertyBlob(connector->backend->gpu->fd, &data.hdrMetadata.value(), sizeof(hdr_output_metadata), &data.atomic.hdrBlob)) { + if (!data.hdrMetadata->hdmi_metadata_type1.eotf) { + data.atomic.hdrBlob = 0; + data.atomic.hdrd = false; + } else if (drmModeCreatePropertyBlob(connector->backend->gpu->fd, &data.hdrMetadata.value(), sizeof(hdr_output_metadata), &data.atomic.hdrBlob)) { connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to create a hdr metadata blob"); data.atomic.hdrBlob = 0; } else From 2ff579d88e759d1e29864e1232e69e246c2304a2 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Fri, 13 Dec 2024 20:08:25 +0300 Subject: [PATCH 06/10] debug logging --- include/aquamarine/output/Output.hpp | 2 +- src/backend/drm/impl/Atomic.cpp | 13 ++++++++++++- src/output/Output.cpp | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/aquamarine/output/Output.hpp b/include/aquamarine/output/Output.hpp index 914f1a7..85a9448 100644 --- a/include/aquamarine/output/Output.hpp +++ b/include/aquamarine/output/Output.hpp @@ -92,7 +92,7 @@ namespace Aquamarine { void resetExplicitFences(); void setCTM(const Hyprutils::Math::Mat3x3& ctm); void setWideColorGamut(bool wcg); - void setHDRMetadata(hdr_output_metadata& metadata); + void setHDRMetadata(const hdr_output_metadata& metadata); private: SInternalState internalState; diff --git a/src/backend/drm/impl/Atomic.cpp b/src/backend/drm/impl/Atomic.cpp index 940c6c8..a54798b 100644 --- a/src/backend/drm/impl/Atomic.cpp +++ b/src/backend/drm/impl/Atomic.cpp @@ -312,8 +312,19 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin } else if (drmModeCreatePropertyBlob(connector->backend->gpu->fd, &data.hdrMetadata.value(), sizeof(hdr_output_metadata), &data.atomic.hdrBlob)) { connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to create a hdr metadata blob"); data.atomic.hdrBlob = 0; - } else + } else { data.atomic.hdrd = true; + connector->backend->backend->log( + AQ_LOG_ERROR, + std::format("atomic drm: setting hdr min {}, max {}, avg {}, content {}, primaries {},{} {},{} {},{} {},{}", + data.hdrMetadata->hdmi_metadata_type1.min_display_mastering_luminance, data.hdrMetadata->hdmi_metadata_type1.max_display_mastering_luminance, + data.hdrMetadata->hdmi_metadata_type1.max_fall, data.hdrMetadata->hdmi_metadata_type1.max_cll, + data.hdrMetadata->hdmi_metadata_type1.display_primaries[0].x, data.hdrMetadata->hdmi_metadata_type1.display_primaries[0].y, + data.hdrMetadata->hdmi_metadata_type1.display_primaries[1].x, data.hdrMetadata->hdmi_metadata_type1.display_primaries[1].y, + data.hdrMetadata->hdmi_metadata_type1.display_primaries[2].x, data.hdrMetadata->hdmi_metadata_type1.display_primaries[2].y, + data.hdrMetadata->hdmi_metadata_type1.display_primaries[0].x, data.hdrMetadata->hdmi_metadata_type1.white_point.x, + data.hdrMetadata->hdmi_metadata_type1.white_point.y)); + } } } diff --git a/src/output/Output.cpp b/src/output/Output.cpp index 758bbcd..9916866 100644 --- a/src/output/Output.cpp +++ b/src/output/Output.cpp @@ -123,7 +123,7 @@ void Aquamarine::COutputState::setWideColorGamut(bool wcg) { internalState.wideColorGamut = wcg; } -void Aquamarine::COutputState::setHDRMetadata(hdr_output_metadata& metadata) { +void Aquamarine::COutputState::setHDRMetadata(const hdr_output_metadata& metadata) { internalState.hdrMetadata = metadata; internalState.committed |= AQ_OUTPUT_STATE_HDR; } From ec0b4f9897f68b0f6f52a533447324a69564da00 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Sun, 15 Dec 2024 22:33:28 +0300 Subject: [PATCH 07/10] edid debug --- src/backend/drm/DRM.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 04a5c59..86e2467 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include @@ -1168,7 +1170,17 @@ drmModeModeInfo* Aquamarine::SDRMConnector::getCurrentMode() { return modeInfo; } +std::string vectorTostring(const std::vector& vec) { + std::stringstream result; + for (const auto& v : vec) { + result << std::setfill('0') << std::setw(sizeof(v) * 2) << std::hex << +v; + result << " "; + } + return result.str(); +} + IOutput::SParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { + TRACE(backend->backend->log(AQ_LOG_TRACE, std::format("EDID: parsing {} bytes: {}", data.size(), vectorTostring(data)))); auto info = di_info_parse_edid(data.data(), data.size()); IOutput::SParsedEDID parsed = {}; if (!info) { @@ -1202,17 +1214,29 @@ IOutput::SParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector d IOutput::xy{chromaticity->blue_x, chromaticity->blue_y}, IOutput::xy{chromaticity->white_x, chromaticity->white_y}, }; + TRACE(backend->backend->log(AQ_LOG_TRACE, + std::format("EDID: chromaticity coords {},{} {},{} {},{} {},{}", parsed.chromaticityCoords->red.x, parsed.chromaticityCoords->red.y, + parsed.chromaticityCoords->green.x, parsed.chromaticityCoords->green.y, parsed.chromaticityCoords->blue.x, + parsed.chromaticityCoords->blue.y, parsed.chromaticityCoords->white.y, parsed.chromaticityCoords->white.y))); } auto exts = di_edid_get_extensions(edid); + for (; *exts != nullptr; exts++) { + auto tag = di_edid_ext_get_tag(*exts); + TRACE(backend->backend->log(AQ_LOG_TRACE, std::format("EDID: checking ext {}", (uint32_t)tag))); + if (tag == DI_EDID_EXT_DISPLAYID) + backend->backend->log(AQ_LOG_WARNING, "FIXME: support displayid blocks"); + const auto cta = di_edid_ext_get_cta(*exts); if (cta) { + TRACE(backend->backend->log(AQ_LOG_TRACE, "EDID: found CTA")); const di_cta_hdr_static_metadata_block* hdr_static_metadata = nullptr; const di_cta_colorimetry_block* colorimetry = nullptr; auto blocks = di_edid_cta_get_data_blocks(cta); for (; *blocks != nullptr; blocks++) { if (!hdr_static_metadata && (hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(*blocks))) { + TRACE(backend->backend->log(AQ_LOG_TRACE, std::format("EDID: found HDR {}", hdr_static_metadata->eotfs->pq))); parsed.hdrMetadata = IOutput::SHDRMetadata{ .desiredContentMaxLuminance = hdr_static_metadata->desired_content_max_luminance, .desiredMaxFrameAverageLuminance = hdr_static_metadata->desired_content_max_frame_avg_luminance, @@ -1222,6 +1246,7 @@ IOutput::SParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector d continue; } if (!colorimetry && (colorimetry = di_cta_data_block_get_colorimetry(*blocks))) { + TRACE(backend->backend->log(AQ_LOG_TRACE, std::format("EDID: found colorimetry {}", colorimetry->bt2020_rgb))); parsed.supportsBT2020 = colorimetry->bt2020_rgb; continue; } @@ -1232,6 +1257,8 @@ IOutput::SParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector d di_info_destroy(info); + TRACE(backend->backend->log(AQ_LOG_TRACE, "EDID: parsed")); + return parsed; } From 5fad731c638b21412cab59b3d7e97d2a9a33667b Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 19 Dec 2024 00:29:48 +0300 Subject: [PATCH 08/10] fix incorrect log level --- src/backend/drm/impl/Atomic.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/drm/impl/Atomic.cpp b/src/backend/drm/impl/Atomic.cpp index a54798b..f334c31 100644 --- a/src/backend/drm/impl/Atomic.cpp +++ b/src/backend/drm/impl/Atomic.cpp @@ -314,8 +314,8 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin data.atomic.hdrBlob = 0; } else { data.atomic.hdrd = true; - connector->backend->backend->log( - AQ_LOG_ERROR, + TRACE(connector->backend->backend->log( + AQ_LOG_TRACE, std::format("atomic drm: setting hdr min {}, max {}, avg {}, content {}, primaries {},{} {},{} {},{} {},{}", data.hdrMetadata->hdmi_metadata_type1.min_display_mastering_luminance, data.hdrMetadata->hdmi_metadata_type1.max_display_mastering_luminance, data.hdrMetadata->hdmi_metadata_type1.max_fall, data.hdrMetadata->hdmi_metadata_type1.max_cll, @@ -323,7 +323,7 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin data.hdrMetadata->hdmi_metadata_type1.display_primaries[1].x, data.hdrMetadata->hdmi_metadata_type1.display_primaries[1].y, data.hdrMetadata->hdmi_metadata_type1.display_primaries[2].x, data.hdrMetadata->hdmi_metadata_type1.display_primaries[2].y, data.hdrMetadata->hdmi_metadata_type1.display_primaries[0].x, data.hdrMetadata->hdmi_metadata_type1.white_point.x, - data.hdrMetadata->hdmi_metadata_type1.white_point.y)); + data.hdrMetadata->hdmi_metadata_type1.white_point.y))); } } } From f79e899e5a425f936be288ea3076ff392caf8c44 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 2 Jan 2025 21:23:41 +0300 Subject: [PATCH 09/10] support DEGAMMA_LUT property --- include/aquamarine/backend/DRM.hpp | 25 ++++++++++-------- include/aquamarine/output/Output.hpp | 6 ++++- src/backend/drm/DRM.cpp | 15 +++++++++++ src/backend/drm/Props.cpp | 1 + src/backend/drm/impl/Atomic.cpp | 38 +++++++++++++++++++--------- src/output/Output.cpp | 9 +++++++ 6 files changed, 71 insertions(+), 23 deletions(-) diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index adb527a..7c2ddaa 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -179,6 +179,8 @@ namespace Aquamarine { uint32_t gamma_lut; uint32_t gamma_lut_size; uint32_t ctm; + uint32_t degamma_lut; + uint32_t degamma_lut_size; // atomic-modesetting only @@ -186,7 +188,7 @@ namespace Aquamarine { uint32_t mode_id; uint32_t out_fence_ptr; }; - uint32_t props[7] = {0}; + uint32_t props[9] = {0}; }; UDRMCRTCProps props; }; @@ -203,6 +205,7 @@ namespace Aquamarine { virtual void setCursorVisible(bool visible); virtual Hyprutils::Math::Vector2D cursorPlaneSize(); virtual size_t getGammaSize(); + virtual size_t getDeGammaSize(); virtual std::vector getRenderFormats(); int getConnectorID(); @@ -250,15 +253,17 @@ namespace Aquamarine { std::optional hdrMetadata; struct { - uint32_t gammaLut = 0; - uint32_t fbDamage = 0; - uint32_t modeBlob = 0; - uint32_t ctmBlob = 0; - uint32_t hdrBlob = 0; - bool blobbed = false; - bool gammad = false; - bool ctmd = false; - bool hdrd = false; + uint32_t gammaLut = 0; + uint32_t degammaLut = 0; + uint32_t fbDamage = 0; + uint32_t modeBlob = 0; + uint32_t ctmBlob = 0; + uint32_t hdrBlob = 0; + bool blobbed = false; + bool gammad = false; + bool degammad = false; + bool ctmd = false; + bool hdrd = false; } atomic; void calculateMode(Hyprutils::Memory::CSharedPointer connector); diff --git a/include/aquamarine/output/Output.hpp b/include/aquamarine/output/Output.hpp index 85a9448..5775753 100644 --- a/include/aquamarine/output/Output.hpp +++ b/include/aquamarine/output/Output.hpp @@ -54,6 +54,7 @@ namespace Aquamarine { AQ_OUTPUT_STATE_EXPLICIT_OUT_FENCE = (1 << 9), AQ_OUTPUT_STATE_CTM = (1 << 10), AQ_OUTPUT_STATE_HDR = (1 << 11), + AQ_OUTPUT_STATE_DEGAMMA_LUT = (1 << 12), }; struct SInternalState { @@ -63,7 +64,8 @@ namespace Aquamarine { bool enabled = false; bool adaptiveSync = false; eOutputPresentationMode presentationMode = AQ_OUTPUT_PRESENTATION_VSYNC; - std::vector gammaLut; // Gamma lut in the format [r,g,b]+ + std::vector gammaLut; // Gamma lut in the format [r,g,b]+ + std::vector degammaLut; // Gamma lut in the format [r,g,b]+ Hyprutils::Math::Vector2D lastModeSize; Hyprutils::Memory::CWeakPointer mode; Hyprutils::Memory::CSharedPointer customMode; @@ -83,6 +85,7 @@ namespace Aquamarine { void setAdaptiveSync(bool enabled); void setPresentationMode(eOutputPresentationMode mode); void setGammaLut(const std::vector& lut); + void setDeGammaLut(const std::vector& lut); void setMode(Hyprutils::Memory::CSharedPointer mode); void setCustomMode(Hyprutils::Memory::CSharedPointer mode); void setFormat(uint32_t drmFormat); @@ -161,6 +164,7 @@ namespace Aquamarine { virtual Hyprutils::Math::Vector2D cursorPlaneSize(); // -1, -1 means no set size, 0, 0 means error virtual void scheduleFrame(const scheduleFrameReason reason = AQ_SCHEDULE_UNKNOWN); virtual size_t getGammaSize(); + virtual size_t getDeGammaSize(); virtual bool destroy(); // not all backends allow this!!! std::string name, description, make, model, serial; diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 86e2467..f5566cc 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1868,6 +1868,21 @@ size_t Aquamarine::CDRMOutput::getGammaSize() { return size; } +size_t Aquamarine::CDRMOutput::getDeGammaSize() { + if (!backend->atomic) { + backend->log(AQ_LOG_ERROR, "No support for gamma on the legacy iface"); + return 0; + } + + uint64_t size = 0; + if (!getDRMProp(backend->gpu->fd, connector->crtc->id, connector->crtc->props.degamma_lut_size, &size)) { + backend->log(AQ_LOG_ERROR, "Couldn't get the degamma_size prop"); + return 0; + } + + return size; +} + std::vector Aquamarine::CDRMOutput::getRenderFormats() { if (!connector->crtc || !connector->crtc->primary || connector->crtc->primary->formats.empty()) { backend->log(AQ_LOG_ERROR, "Can't get formats: no crtc"); diff --git a/src/backend/drm/Props.cpp b/src/backend/drm/Props.cpp index ef777d2..961e665 100644 --- a/src/backend/drm/Props.cpp +++ b/src/backend/drm/Props.cpp @@ -47,6 +47,7 @@ static const struct prop_info colorspace_info[] = { static const struct prop_info crtc_info[] = { #define INDEX(name) (offsetof(SDRMCRTC::UDRMCRTCProps, name) / sizeof(uint32_t)) {"ACTIVE", INDEX(active)}, {"CTM", INDEX(ctm)}, + {"DEGAMMA_LUT", INDEX(degamma_lut)}, {"DEGAMMA_LUT_SIZE", INDEX(degamma_lut_size)}, {"GAMMA_LUT", INDEX(gamma_lut)}, {"GAMMA_LUT_SIZE", INDEX(gamma_lut_size)}, {"MODE_ID", INDEX(mode_id)}, {"OUT_FENCE_PTR", INDEX(out_fence_ptr)}, {"VRR_ENABLED", INDEX(vrr_enabled)}, diff --git a/src/backend/drm/impl/Atomic.cpp b/src/backend/drm/impl/Atomic.cpp index f334c31..af53406 100644 --- a/src/backend/drm/impl/Atomic.cpp +++ b/src/backend/drm/impl/Atomic.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -116,6 +117,9 @@ void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPoint if (connector->crtc->props.gamma_lut && data.atomic.gammad) add(connector->crtc->id, connector->crtc->props.gamma_lut, data.atomic.gammaLut); + if (connector->crtc->props.degamma_lut && data.atomic.degammad) + add(connector->crtc->id, connector->crtc->props.degamma_lut, data.atomic.degammaLut); + if (connector->crtc->props.ctm && data.atomic.ctmd) add(connector->crtc->id, connector->crtc->props.ctm, data.atomic.ctmBlob); @@ -253,29 +257,39 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin } } - if (STATE.committed & COutputState::AQ_OUTPUT_STATE_GAMMA_LUT) { - if (!connector->crtc->props.gamma_lut) // TODO: allow this with legacy gamma, perhaps. + static auto prepareGammaBlob = [connector](uint32_t prop, const std::vector& gammaLut, uint32_t* blobId) -> bool { + if (!prop) // TODO: allow this with legacy gamma, perhaps. connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to commit gamma: no gamma_lut prop"); - else if (STATE.gammaLut.empty()) { - data.atomic.gammaLut = 0; - data.atomic.gammad = true; + else if (gammaLut.empty()) { + blobId = 0; + return true; } else { std::vector lut; - lut.resize(STATE.gammaLut.size() / 3); // [r,g,b]+ + lut.resize(gammaLut.size() / 3); // [r,g,b]+ for (size_t i = 0; i < lut.size(); ++i) { - lut.at(i).red = STATE.gammaLut.at(i * 3 + 0); - lut.at(i).green = STATE.gammaLut.at(i * 3 + 1); - lut.at(i).blue = STATE.gammaLut.at(i * 3 + 2); + lut.at(i).red = gammaLut.at(i * 3 + 0); + lut.at(i).green = gammaLut.at(i * 3 + 1); + lut.at(i).blue = gammaLut.at(i * 3 + 2); lut.at(i).reserved = 0; } - if (drmModeCreatePropertyBlob(connector->backend->gpu->fd, lut.data(), lut.size() * sizeof(drm_color_lut), &data.atomic.gammaLut)) { + if (drmModeCreatePropertyBlob(connector->backend->gpu->fd, lut.data(), lut.size() * sizeof(drm_color_lut), blobId)) { connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to create a gamma blob"); - data.atomic.gammaLut = 0; + *blobId = 0; } else - data.atomic.gammad = true; + return true; } + + return false; + }; + + if (STATE.committed & COutputState::AQ_OUTPUT_STATE_GAMMA_LUT) { + data.atomic.gammad = prepareGammaBlob(connector->crtc->props.gamma_lut, STATE.gammaLut, &data.atomic.gammaLut); + } + + if (STATE.committed & COutputState::AQ_OUTPUT_STATE_DEGAMMA_LUT) { + data.atomic.degammad = prepareGammaBlob(connector->crtc->props.degamma_lut, STATE.degammaLut, &data.atomic.degammaLut); } if ((STATE.committed & COutputState::AQ_OUTPUT_STATE_CTM) && data.ctm.has_value()) { diff --git a/src/output/Output.cpp b/src/output/Output.cpp index 9916866..5be02d2 100644 --- a/src/output/Output.cpp +++ b/src/output/Output.cpp @@ -39,6 +39,10 @@ size_t Aquamarine::IOutput::getGammaSize() { return 0; } +size_t Aquamarine::IOutput::getDeGammaSize() { + return 0; +} + bool Aquamarine::IOutput::destroy() { return false; } @@ -77,6 +81,11 @@ void Aquamarine::COutputState::setGammaLut(const std::vector& lut) { internalState.committed |= AQ_OUTPUT_STATE_GAMMA_LUT; } +void Aquamarine::COutputState::setDeGammaLut(const std::vector& lut) { + internalState.gammaLut = lut; + internalState.committed |= AQ_OUTPUT_STATE_DEGAMMA_LUT; +} + void Aquamarine::COutputState::setMode(Hyprutils::Memory::CSharedPointer mode) { internalState.mode = mode; internalState.customMode = nullptr; From 4466cc3f9288caed22b517d0fad7c664fcf744a2 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Sat, 4 Jan 2025 20:04:59 +0300 Subject: [PATCH 10/10] cleanups --- src/backend/drm/DRM.cpp | 10 ---------- src/backend/drm/impl/Atomic.cpp | 8 +++----- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index d99ce9d..cc44501 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1171,17 +1171,7 @@ drmModeModeInfo* Aquamarine::SDRMConnector::getCurrentMode() { return modeInfo; } -std::string vectorTostring(const std::vector& vec) { - std::stringstream result; - for (const auto& v : vec) { - result << std::setfill('0') << std::setw(sizeof(v) * 2) << std::hex << +v; - result << " "; - } - return result.str(); -} - IOutput::SParsedEDID Aquamarine::SDRMConnector::parseEDID(std::vector data) { - TRACE(backend->backend->log(AQ_LOG_TRACE, std::format("EDID: parsing {} bytes: {}", data.size(), vectorTostring(data)))); auto info = di_info_parse_edid(data.data(), data.size()); IOutput::SParsedEDID parsed = {}; if (!info) { diff --git a/src/backend/drm/impl/Atomic.cpp b/src/backend/drm/impl/Atomic.cpp index da17b76..285bba5 100644 --- a/src/backend/drm/impl/Atomic.cpp +++ b/src/backend/drm/impl/Atomic.cpp @@ -257,7 +257,7 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin } } - static auto prepareGammaBlob = [connector](uint32_t prop, const std::vector& gammaLut, uint32_t* blobId) -> bool { + auto prepareGammaBlob = [connector](uint32_t prop, const std::vector& gammaLut, uint32_t* blobId) -> bool { if (!prop) // TODO: allow this with legacy gamma, perhaps. connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to commit gamma: no gamma_lut prop"); else if (gammaLut.empty()) { @@ -284,13 +284,11 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin return false; }; - if (STATE.committed & COutputState::AQ_OUTPUT_STATE_GAMMA_LUT) { + if (STATE.committed & COutputState::AQ_OUTPUT_STATE_GAMMA_LUT) data.atomic.gammad = prepareGammaBlob(connector->crtc->props.gamma_lut, STATE.gammaLut, &data.atomic.gammaLut); - } - if (STATE.committed & COutputState::AQ_OUTPUT_STATE_DEGAMMA_LUT) { + if (STATE.committed & COutputState::AQ_OUTPUT_STATE_DEGAMMA_LUT) data.atomic.degammad = prepareGammaBlob(connector->crtc->props.degamma_lut, STATE.degammaLut, &data.atomic.degammaLut); - } if ((STATE.committed & COutputState::AQ_OUTPUT_STATE_CTM) && data.ctm.has_value()) { if (!connector->crtc->props.ctm)