From d352c0dd980d43a81cfb024c29bde6ab1ad0aa42 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:40:37 +0100 Subject: [PATCH] DRM/Output: Implement CTM support (#92) * flake.lock: update hyprutils --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 2 +- flake.lock | 6 +++--- include/aquamarine/backend/DRM.hpp | 6 ++++++ include/aquamarine/output/Output.hpp | 4 ++++ src/backend/drm/DRM.cpp | 5 +++++ src/backend/drm/Props.cpp | 6 ++++-- src/backend/drm/impl/Atomic.cpp | 29 ++++++++++++++++++++++++++++ src/output/Output.cpp | 5 +++++ 8 files changed, 57 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cadde23..3348f91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ pkg_check_modules( libinput>=1.26.0 wayland-client wayland-protocols - hyprutils>=0.1.5 + hyprutils>=0.2.3 pixman-1 libdrm gbm diff --git a/flake.lock b/flake.lock index a81f22e..569639d 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ ] }, "locked": { - "lastModified": 1724966483, - "narHash": "sha256-WXDgKIbzjYKczxSZOsJplCS1i1yrTUpsDPuJV/xpYLo=", + "lastModified": 1727300645, + "narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "8976e3f6a5357da953a09511d0c7f6a890fb6ec2", + "rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c", "type": "github" }, "original": { diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index 040cad7..40ea97a 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace Aquamarine { class CDRMBackend; @@ -162,6 +163,7 @@ namespace Aquamarine { bool ownModeID = false; uint32_t modeID = 0; uint32_t gammaLut = 0; + uint32_t ctm = 0; } atomic; Hyprutils::Memory::CSharedPointer primary; @@ -175,6 +177,7 @@ namespace Aquamarine { uint32_t vrr_enabled; uint32_t gamma_lut; uint32_t gamma_lut_size; + uint32_t ctm; // atomic-modesetting only @@ -242,13 +245,16 @@ namespace Aquamarine { uint32_t flags = 0; bool test = false; drmModeModeInfo modeInfo; + std::optional ctm; struct { uint32_t gammaLut = 0; uint32_t fbDamage = 0; uint32_t modeBlob = 0; + uint32_t ctmBlob = 0; bool blobbed = false; bool gammad = false; + bool ctmd = false; } atomic; void calculateMode(Hyprutils::Memory::CSharedPointer connector); diff --git a/include/aquamarine/output/Output.hpp b/include/aquamarine/output/Output.hpp index 29e204b..9b0519f 100644 --- a/include/aquamarine/output/Output.hpp +++ b/include/aquamarine/output/Output.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "../allocator/Swapchain.hpp" @@ -51,6 +52,7 @@ namespace Aquamarine { AQ_OUTPUT_STATE_BUFFER = (1 << 7), AQ_OUTPUT_STATE_EXPLICIT_IN_FENCE = (1 << 8), AQ_OUTPUT_STATE_EXPLICIT_OUT_FENCE = (1 << 9), + AQ_OUTPUT_STATE_CTM = (1 << 10), }; struct SInternalState { @@ -67,6 +69,7 @@ namespace Aquamarine { uint32_t drmFormat = DRM_FORMAT_INVALID; Hyprutils::Memory::CSharedPointer buffer; int64_t explicitInFence = -1, explicitOutFence = -1; + Hyprutils::Math::Mat3x3 ctm; }; const SInternalState& state(); @@ -84,6 +87,7 @@ namespace Aquamarine { void setExplicitInFence(int64_t fenceFD); // -1 removes void setExplicitOutFence(int64_t fenceFD); // -1 removes void resetExplicitFences(); + void setCTM(const Hyprutils::Math::Mat3x3& ctm); private: SInternalState internalState; diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 26d5c4b..4176083 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1183,6 +1183,8 @@ void Aquamarine::SDRMConnector::recheckCRTCProps() { output->supportsExplicit = backend->drmProps.supportsTimelines && crtc->props.out_fence_ptr && crtc->primary->props.in_fence_fd; 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"))); } void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) { @@ -1577,6 +1579,9 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) { } } + if (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_CTM) + data.ctm = STATE.ctm; + data.blocking = BLOCKING || formatMismatch; data.modeset = NEEDS_RECONFIG || lastCommitNoBuffer || formatMismatch; data.flags = flags; diff --git a/src/backend/drm/Props.cpp b/src/backend/drm/Props.cpp index e31d4d7..3f8128b 100644 --- a/src/backend/drm/Props.cpp +++ b/src/backend/drm/Props.cpp @@ -36,8 +36,10 @@ static const struct prop_info connector_info[] = { static const struct prop_info crtc_info[] = { #define INDEX(name) (offsetof(SDRMCRTC::UDRMCRTCProps, name) / sizeof(uint32_t)) - {"ACTIVE", INDEX(active)}, {"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)}, + {"ACTIVE", INDEX(active)}, {"CTM", INDEX(ctm)}, + {"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)}, #undef INDEX }; diff --git a/src/backend/drm/impl/Atomic.cpp b/src/backend/drm/impl/Atomic.cpp index 9803f21..b031076 100644 --- a/src/backend/drm/impl/Atomic.cpp +++ b/src/backend/drm/impl/Atomic.cpp @@ -109,6 +109,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.ctm && data.atomic.ctmd) + add(connector->crtc->id, connector->crtc->props.ctm, data.atomic.ctmBlob); + if (connector->crtc->props.vrr_enabled) add(connector->crtc->id, connector->crtc->props.vrr_enabled, (uint64_t)STATE.adaptiveSync); @@ -197,6 +200,7 @@ void Aquamarine::CDRMAtomicRequest::rollback(SDRMConnectorCommitData& data) { if (data.atomic.blobbed) rollbackBlob(&conn->crtc->atomic.modeID, data.atomic.modeBlob); rollbackBlob(&conn->crtc->atomic.gammaLut, data.atomic.gammaLut); + rollbackBlob(&conn->crtc->atomic.ctm, data.atomic.ctmBlob); destroyBlob(data.atomic.fbDamage); } @@ -211,6 +215,7 @@ void Aquamarine::CDRMAtomicRequest::apply(SDRMConnectorCommitData& data) { if (data.atomic.blobbed) commitBlob(&conn->crtc->atomic.modeID, data.atomic.modeBlob); commitBlob(&conn->crtc->atomic.gammaLut, data.atomic.gammaLut); + commitBlob(&conn->crtc->atomic.ctm, data.atomic.ctmBlob); destroyBlob(data.atomic.fbDamage); } @@ -263,6 +268,30 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin } } + if ((STATE.committed & COutputState::AQ_OUTPUT_STATE_CTM) && data.ctm.has_value()) { + if (!connector->crtc->props.ctm) + connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to commit ctm: no ctm prop support"); + else { + static auto doubleToS3132Fixed = [](const double val) -> uint64_t { + const uint64_t result = std::abs(val) * (1ULL << 32); + if (val < 0) + return result | 1ULL << 63; + return result; + }; + + drm_color_ctm ctm = {0}; + for (size_t i = 0; i < 9; ++i) { + ctm.matrix[i] = doubleToS3132Fixed(data.ctm->getMatrix()[i]); + } + + if (drmModeCreatePropertyBlob(connector->backend->gpu->fd, &ctm, sizeof(drm_color_ctm), &data.atomic.ctmBlob)) { + connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to create a ctm blob"); + data.atomic.ctmBlob = 0; + } else + data.atomic.ctmd = 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 374764e..b5d3f3e 100644 --- a/src/output/Output.cpp +++ b/src/output/Output.cpp @@ -115,6 +115,11 @@ void Aquamarine::COutputState::resetExplicitFences() { internalState.explicitOutFence = -1; } +void Aquamarine::COutputState::setCTM(const Hyprutils::Math::Mat3x3& ctm) { + internalState.ctm = ctm; + internalState.committed |= AQ_OUTPUT_STATE_CTM; +} + void Aquamarine::COutputState::onCommit() { internalState.committed = 0; internalState.damage.clear();