summaryrefslogtreecommitdiff
path: root/src/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'src/helpers')
-rw-r--r--src/helpers/Drm.cpp2
-rw-r--r--src/helpers/Monitor.cpp70
-rw-r--r--src/helpers/Monitor.hpp4
-rw-r--r--src/helpers/MonitorResources.cpp37
-rw-r--r--src/helpers/MonitorResources.hpp4
-rw-r--r--src/helpers/cm/ColorManagement.cpp30
-rw-r--r--src/helpers/cm/ColorManagement.hpp60
7 files changed, 172 insertions, 35 deletions
diff --git a/src/helpers/Drm.cpp b/src/helpers/Drm.cpp
index f91c5692..4f3119f8 100644
--- a/src/helpers/Drm.cpp
+++ b/src/helpers/Drm.cpp
@@ -32,7 +32,7 @@ std::optional<dev_t> DRM::devIDFromFD(int fd) {
}
bool DRM::sameGpu(int fd1, int fd2) {
- if (fd1 >= 0 && fd1 == fd2)
+ if (fd1 < 0 || fd2 < 0 || fd1 == fd2)
return true;
static std::mutex cacheMutex;
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index eef68c2f..5fb6cf31 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -62,7 +62,7 @@ using namespace NColorManagement;
using namespace Render::GL;
using namespace Monitor;
-CMonitor::CMonitor(SP<Aquamarine::IOutput> output_) : m_state(this), m_output(output_), m_imageDescription(DEFAULT_IMAGE_DESCRIPTION) {
+CMonitor::CMonitor(SP<Aquamarine::IOutput> output_) : m_state(this), m_output(output_), m_imageDescription(getDefaultImageDescription()) {
g_pAnimationManager->createAnimation(0.f, m_specialFade, Config::animationTree()->getAnimationPropertyConfig("specialWorkspaceIn"), AVARDAMAGE_NONE);
m_specialFade->setUpdateCallback([this](auto) { g_pHyprRenderer->damageMonitor(m_self.lock()); });
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
@@ -511,9 +511,9 @@ static NColorManagement::eTransferFunction chooseTF(NTransferFunction::eTF tf) {
const auto sdrEOTF = NTransferFunction::fromConfig();
switch (tf) {
- case NTransferFunction::TF_DEFAULT:
case NTransferFunction::TF_GAMMA22:
case NTransferFunction::TF_FORCED_GAMMA22: return NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
+ case NTransferFunction::TF_DEFAULT:
case NTransferFunction::TF_SRGB: return NColorManagement::CM_TRANSFER_FUNCTION_SRGB;
case NTransferFunction::TF_AUTO: // use global setting
@@ -949,7 +949,7 @@ bool CMonitor::applyMonitorRule(Config::CMonitorRule&& pMonitorRule, bool force)
m_enabled10bit = set10bit;
- m_supportsWideColor = RULE->m_supportsHDR;
+ m_supportsWideColor = RULE->m_supportsWideColor;
m_supportsHDR = RULE->m_supportsHDR;
if (RULE->m_iccFile.empty()) {
@@ -1853,7 +1853,6 @@ bool CMonitor::updateTearing() {
uint16_t CMonitor::isDSBlocked(bool full) {
uint16_t reasons = 0;
static auto PDIRECTSCANOUT = CConfigValue<Hyprlang::INT>("render:direct_scanout");
- static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
static auto PNONSHADER = CConfigValue<Hyprlang::INT>("render:non_shader_cm");
const auto PWORKSPACE = m_activeWorkspace;
@@ -1930,9 +1929,14 @@ uint16_t CMonitor::isDSBlocked(bool full) {
const bool surfaceIsHDR = PSURFACE->m_colorManagement.valid() && PSURFACE->m_colorManagement->isHDR();
const bool surfaceIsScRGB = surfaceIsHDR && PSURFACE->m_colorManagement->isWindowsScRGB();
- if (needsCM() && (*PNONSHADER != CM_NS_IGNORE || surfaceIsScRGB) && !canNoShaderCM() &&
- ((inHDR() && (*PPASS == 0 || !surfaceIsHDR || surfaceIsScRGB)) || (!inHDR() && (*PPASS != 1 || surfaceIsHDR))))
- reasons |= DS_BLOCK_CM;
+ if (surfaceIsScRGB)
+ reasons |= DS_BLOCK_CM; // block scRGB
+ else if (*PNONSHADER != CM_NS_IGNORE) {
+ if (!surfaceIsHDR && needsCM() && !canNoShaderCM(true))
+ reasons |= DS_BLOCK_CM; // block SDR that needs CM while non-shader CM isn't available
+ else if (surfaceIsHDR && !inHDR())
+ reasons |= DS_BLOCK_CM; // block HDR while monitor isn't in HDR mode
+ }
return reasons;
}
@@ -1987,6 +1991,7 @@ bool CMonitor::attemptDirectScanout() {
if (m_lastScanout.expired())
m_prevDrmFormat = m_drmFormat;
+ const bool NEEDS_TEST = !m_lastScanout || m_drmFormat != params.format; // do not retest while it's active
if (m_drmFormat != params.format) {
m_output->state->setFormat(params.format);
m_drmFormat = params.format;
@@ -1997,7 +2002,7 @@ bool CMonitor::attemptDirectScanout() {
m_output->state->setPresentationMode(m_tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
- if (!m_state.test()) {
+ if (NEEDS_TEST && !m_state.test()) {
Log::logger->log(Log::TRACE, "attemptDirectScanout: failed basic test");
return false;
}
@@ -2278,7 +2283,7 @@ std::optional<NColorManagement::PImageDescription> CMonitor::getFSImageDescripti
const auto ROOT_SURF = FS_WINDOW->wlSurface()->resource();
const auto SURF = ROOT_SURF->findWithCM();
- return SURF ? NColorManagement::CImageDescription::from(SURF->m_colorManagement->imageDescription()) : DEFAULT_IMAGE_DESCRIPTION;
+ return SURF ? NColorManagement::CImageDescription::from(SURF->m_colorManagement->imageDescription()) : getDefaultImageDescription();
}
NColorManagement::SPCPRimaries CMonitor::getMasteringPrimaries() {
@@ -2317,8 +2322,20 @@ bool CMonitor::needsCM() {
return SRC_DESC.has_value() && SRC_DESC.value() != m_imageDescription;
}
+static bool isCompatibleTF(eTransferFunction sourceTF, eTransferFunction targetTF) {
+ static auto PNONSHADER = CConfigValue<Hyprlang::INT>("render:non_shader_cm");
+ const auto sdrEOTF = NTransferFunction::fromConfig();
+ return sourceTF == targetTF // same
+ || (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && sourceTF == NColorManagement::CM_TRANSFER_FUNCTION_SRGB // forced source gamma22 to output gamma22
+ && targetTF == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22) //
+ || (*PNONSHADER == CM_NS_ONDEMAND // FIXME incorrect but good enough for DS
+ && (sourceTF == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 || sourceTF == NColorManagement::CM_TRANSFER_FUNCTION_SRGB) //
+ && (targetTF == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 || targetTF == NColorManagement::CM_TRANSFER_FUNCTION_SRGB)) //
+ ;
+}
+
// TODO support more drm properties
-bool CMonitor::canNoShaderCM() {
+bool CMonitor::canNoShaderCM(bool forDSmode) {
static auto PNONSHADER = CConfigValue<Hyprlang::INT>("render:non_shader_cm");
if (*PNONSHADER == CM_NS_DISABLE)
return false;
@@ -2327,22 +2344,22 @@ bool CMonitor::canNoShaderCM() {
if (!SRC_DESC.has_value())
return false;
- if (SRC_DESC.value() == m_imageDescription)
+ const auto& DST_DESC = forDSmode ? m_imageDescription : resources()->m_imageDescription;
+ if (SRC_DESC.value() == DST_DESC)
return true; // no CM needed
- const auto SRC_DESC_VALUE = SRC_DESC.value()->value();
+ const auto& SRC_DESC_VALUE = SRC_DESC.value()->value();
if (m_imageDescription->value().icc.present)
return false;
- const auto sdrEOTF = NTransferFunction::fromConfig();
+ Log::logger->log(Log::TRACE, "CM: can no shder compares src={} to output={}", SRC_DESC_VALUE, m_imageDescription->value());
+
// only primaries differ
return (
- (SRC_DESC_VALUE.transferFunction == m_imageDescription->value().transferFunction ||
- (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && SRC_DESC_VALUE.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB &&
- m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22)) &&
- SRC_DESC_VALUE.transferFunctionPower == m_imageDescription->value().transferFunctionPower &&
- (!inHDR() || SRC_DESC_VALUE.luminances == m_imageDescription->value().luminances)
+ isCompatibleTF(SRC_DESC_VALUE.transferFunction, DST_DESC->value().transferFunction) //
+ && SRC_DESC_VALUE.transferFunctionPower == DST_DESC->value().transferFunctionPower //
+ && (!inHDR() || SRC_DESC_VALUE.luminances == DST_DESC->value().luminances)
// not used by shaders atm
// && SRC_DESC_VALUE.masteringLuminances == m_imageDescription->value().masteringLuminances && SRC_DESC_VALUE.maxCLL == m_imageDescription->value().maxCLL && SRC_DESC_VALUE.maxFALL == m_imageDescription->value().maxFALL
);
@@ -2505,6 +2522,7 @@ bool CMonitor::needsUnmodifiedCopy() {
if (!HAS_MODS)
return false;
+ // TODO handle some FP16 cases
if (m_imageDescription->value().transferFunction != CM_TRANSFER_FUNCTION_ST2084_PQ && m_imageDescription->value().transferFunction != CM_TRANSFER_FUNCTION_HLG)
return false;
@@ -2512,15 +2530,25 @@ bool CMonitor::needsUnmodifiedCopy() {
}
bool CMonitor::useFP16() {
- static const auto PFP16 = CConfigValue<Hyprlang::INT>("render:use_fp16");
- return *PFP16 == 1 || (*PFP16 == 2 && m_imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ);
+ static const auto PFP16 = CConfigValue<Hyprlang::INT>("render:use_fp16");
+ bool shouldUse = *PFP16 == 1 || (*PFP16 == 2 && m_imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ);
+ static bool usedBefore = shouldUse;
+ if (usedBefore != shouldUse) {
+ usedBefore = shouldUse;
+ m_blurFBDirty = true;
+ }
+ return shouldUse;
}
WP<CMonitorResources> CMonitor::resources() {
const auto DRM_FORMAT = useFP16() ? DRM_FORMAT_ABGR16161616F : m_output->state->state().drmFormat;
+ const auto DESC = useFP16() ? LINEAR_IMAGE_DESCRIPTION : m_imageDescription;
if (!m_resources || m_resources->m_drmFormat != DRM_FORMAT || m_resources->m_size != m_pixelSize)
- m_resources = makeUnique<CMonitorResources>(m_self, DRM_FORMAT, m_pixelSize, useFP16() ? LINEAR_IMAGE_DESCRIPTION : m_imageDescription);
+ m_resources = makeUnique<CMonitorResources>(m_self, DRM_FORMAT, m_pixelSize, DESC);
+
+ if (m_resources->m_imageDescription != DESC)
+ m_resources->setImageDescription(DESC);
return m_resources;
}
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 74fe676b..59a64237 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -365,8 +365,8 @@ class CMonitor {
uint32_t getPreferredReadFormat();
bool needsCM();
- /// Can do CM without shader
- bool canNoShaderCM();
+ /// Can do CM without shader (forDSmode ? check output image description : check workbuffer image description)
+ bool canNoShaderCM(bool forDSmode = false);
bool doesNoShaderCM();
bool m_enabled = false;
diff --git a/src/helpers/MonitorResources.cpp b/src/helpers/MonitorResources.cpp
index 6f5c4d33..8e7723c2 100644
--- a/src/helpers/MonitorResources.cpp
+++ b/src/helpers/MonitorResources.cpp
@@ -15,6 +15,7 @@ CMonitorResources::CMonitorResources(WP<CMonitor> monitor, DRMFormat format, Vec
m_blurFB(g_pHyprRenderer->createFB(std::format("Monitor {} blur FB", monitor->m_name))), m_monitor(monitor), m_drmFormat(format), m_size(size),
m_imageDescription(imageDescription) {
initFB(m_blurFB);
+ monitor->m_blurFBDirty = true;
}
void CMonitorResources::initFB(SP<Render::IFramebuffer> fb) {
@@ -23,6 +24,19 @@ void CMonitorResources::initFB(SP<Render::IFramebuffer> fb) {
fb->setImageDescription(m_imageDescription);
}
+void CMonitorResources::setImageDescription(NColorManagement::PImageDescription imageDescription) {
+ if (m_imageDescription == imageDescription)
+ return;
+ m_imageDescription = imageDescription;
+ m_blurFB->setImageDescription(imageDescription);
+ for (const auto& res : m_workBuffers)
+ res.buffer->setImageDescription(imageDescription);
+ if (m_monitorMirrorFB)
+ m_monitorMirrorFB->setImageDescription(NColorManagement::getDefaultImageDescription());
+ if (m_mirrorTex)
+ m_mirrorTex->m_imageDescription = getMirrorTexImageDescription();
+}
+
SP<Render::IFramebuffer> CMonitorResources::getUnusedWorkBuffer() {
std::erase_if(m_workBuffers, [](const auto& res) { return res.lastUsed.getSeconds() >= MAX_UNUSED_SECONDS; });
@@ -65,7 +79,7 @@ SP<Render::IFramebuffer> CMonitorResources::mirrorFB() {
if (!m_monitorMirrorFB->isAllocated()) {
m_monitorMirrorFB->alloc(m_size.x, m_size.y, DRM_FORMAT_XRGB8888);
- m_monitorMirrorFB->setImageDescription(NColorManagement::DEFAULT_IMAGE_DESCRIPTION);
+ m_monitorMirrorFB->setImageDescription(NColorManagement::getDefaultImageDescription());
}
return m_monitorMirrorFB;
@@ -75,13 +89,9 @@ SP<Render::ITexture> CMonitorResources::getMirrorTexture() {
return hasMirrorFB() ? mirrorFB()->getTexture() : nullptr;
}
-void CMonitorResources::enableMirror() {
- if (m_mirrorTex)
- return;
- m_mirrorTex = g_pHyprRenderer->createTexture();
- m_mirrorTex->allocate({m_size.x, m_size.y}, DRM_FORMAT_XRGB8888);
- m_mirrorTex->m_imageDescription = CImageDescription::from(SImageDescription{
- .transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
+NColorManagement::PImageDescription CMonitorResources::getMirrorTexImageDescription() {
+ return CImageDescription::from(SImageDescription{
+ .transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_SRGB,
.primariesNameSet = m_imageDescription->value().primariesNameSet,
.primariesNamed = m_imageDescription->value().primariesNamed,
.primaries = m_imageDescription->value().primaries,
@@ -89,6 +99,17 @@ void CMonitorResources::enableMirror() {
});
}
+void CMonitorResources::enableMirror() {
+ if (m_mirrorTex)
+ return;
+ m_mirrorTex = g_pHyprRenderer->createTexture();
+ m_mirrorTex->allocate({m_size.x, m_size.y}, DRM_FORMAT_XRGB8888);
+ m_mirrorTex->m_imageDescription = getMirrorTexImageDescription();
+ m_monitor->m_blurFBDirty = true;
+}
+
void CMonitorResources::disableMirror() {
+ if (m_mirrorTex)
+ m_monitor->m_blurFBDirty = true;
m_mirrorTex.reset();
}
diff --git a/src/helpers/MonitorResources.hpp b/src/helpers/MonitorResources.hpp
index a5a60fa5..6092b9c9 100644
--- a/src/helpers/MonitorResources.hpp
+++ b/src/helpers/MonitorResources.hpp
@@ -25,7 +25,9 @@ namespace Monitor {
SP<Render::IFramebuffer> m_blurFB;
private:
- void initFB(SP<Render::IFramebuffer> fb);
+ void initFB(SP<Render::IFramebuffer> fb);
+ void setImageDescription(NColorManagement::PImageDescription imageDescription);
+ NColorManagement::PImageDescription getMirrorTexImageDescription();
struct SResource {
SP<Render::IFramebuffer> buffer;
diff --git a/src/helpers/cm/ColorManagement.cpp b/src/helpers/cm/ColorManagement.cpp
index 829adbe7..5e4725d4 100644
--- a/src/helpers/cm/ColorManagement.cpp
+++ b/src/helpers/cm/ColorManagement.cpp
@@ -1,10 +1,12 @@
#include "ColorManagement.hpp"
#include "../../macros.hpp"
+#include "helpers/TransferFunction.hpp"
#include <hyprutils/memory/UniquePtr.hpp>
#include <map>
#include <vector>
using namespace NColorManagement;
+using namespace NTransferFunction;
namespace NColorManagement {
// expected to be small
@@ -110,6 +112,20 @@ WP<const CPrimaries> CImageDescription::getPrimaries() const {
return CPrimaries::from(m_primariesId);
}
+bool CImageDescription::needsCM(WP<const CImageDescription> target) const {
+ if (m_id == target->m_id)
+ return false;
+
+ return m_imageDescription.icc.present || target->m_imageDescription.icc.present // TODO compare ICC
+ || m_imageDescription.transferFunction != target->m_imageDescription.transferFunction //
+ //|| m_imageDescription.transferFunctionPower != target->m_imageDescription.transferFunctionPower // TODO unsupported
+ || m_imageDescription.getPrimaries() != target->m_imageDescription.getPrimaries() //
+ // || m_imageDescription.masteringPrimaries != target->m_imageDescription.masteringPrimaries // TODO unused
+ || m_imageDescription.luminances != target->m_imageDescription.luminances //
+ // || m_imageDescription.masteringLuminances != target->m_imageDescription.masteringLuminances // TODO unused
+ ;
+}
+
static Mat3x3 diag3(const std::array<float, 3>& s) {
return Mat3x3{std::array<float, 9>{s[0], 0, 0, 0, s[1], 0, 0, 0, s[2]}};
}
@@ -190,4 +206,16 @@ Mat3x3 NColorManagement::adaptBradford(Hyprgraphics::CColor::xy srcW, Hyprgraphi
result.multiply(diag3(scale)).multiply(Bradford);
return result;
-} \ No newline at end of file
+}
+
+PImageDescription NColorManagement::getDefaultImageDescription() {
+ const auto TF = fromConfig();
+ switch (TF) {
+ case TF_AUTO:
+ case TF_GAMMA22:
+ case TF_FORCED_GAMMA22: return DEFAULT_GAMMA22_IMAGE_DESCRIPTION;
+ case TF_DEFAULT:
+ case TF_SRGB: return DEFAULT_SRGB_IMAGE_DESCRIPTION;
+ default: UNREACHABLE();
+ }
+}
diff --git a/src/helpers/cm/ColorManagement.hpp b/src/helpers/cm/ColorManagement.hpp
index dccbb972..183a8544 100644
--- a/src/helpers/cm/ColorManagement.hpp
+++ b/src/helpers/cm/ColorManagement.hpp
@@ -1,11 +1,13 @@
#pragma once
#include "color-management-v1.hpp"
+#include <format>
#include <hyprgraphics/color/Color.hpp>
#include "../../helpers/memory/Memory.hpp"
#include "../../helpers/math/Math.hpp"
#include <filesystem>
+#include <string>
#include <vector>
#include <expected>
@@ -78,6 +80,24 @@ namespace NColorManagement {
default: return sc<eTransferFunction>(tf);
}
}
+ inline std::string tfToString(eTransferFunction tf) {
+ switch (tf) {
+ case CM_TRANSFER_FUNCTION_BT1886: return "TF:BT1886";
+ case CM_TRANSFER_FUNCTION_GAMMA22: return "TF:GAMMA22";
+ case CM_TRANSFER_FUNCTION_GAMMA28: return "TF:GAMMA28";
+ case CM_TRANSFER_FUNCTION_ST240: return "TF:ST240";
+ case CM_TRANSFER_FUNCTION_EXT_LINEAR: return "TF:EXT_LINEAR";
+ case CM_TRANSFER_FUNCTION_LOG_100: return "TF:LOG_100";
+ case CM_TRANSFER_FUNCTION_LOG_316: return "TF:LOG_316";
+ case CM_TRANSFER_FUNCTION_XVYCC: return "TF:XVYCC";
+ case CM_TRANSFER_FUNCTION_SRGB: return "TF:SRGB";
+ case CM_TRANSFER_FUNCTION_EXT_SRGB: return "TF:EXT_SRGB";
+ case CM_TRANSFER_FUNCTION_ST2084_PQ: return "TF:ST2084_PQ";
+ case CM_TRANSFER_FUNCTION_ST428: return "TF:ST428";
+ case CM_TRANSFER_FUNCTION_HLG: return "TF:HLG";
+ default: return "TF:ERROR";
+ }
+ }
using SPCPRimaries = Hyprgraphics::SPCPRimaries;
@@ -320,6 +340,7 @@ namespace NColorManagement {
uint64_t id() const;
WP<const CPrimaries> getPrimaries() const;
+ bool needsCM(WP<const CImageDescription> target) const;
private:
CImageDescription(const SImageDescription& imageDescription, const uint64_t imageDescriptionId);
@@ -330,7 +351,9 @@ namespace NColorManagement {
using PImageDescription = WP<const CImageDescription>;
- static const auto DEFAULT_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
+ PImageDescription getDefaultImageDescription();
+
+ static const auto DEFAULT_GAMMA22_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
.primariesNameSet = true,
.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB,
@@ -338,6 +361,14 @@ namespace NColorManagement {
.luminances = {.min = SDR_MIN_LUMINANCE, .max = 80, .reference = 80},
});
+ static const auto DEFAULT_SRGB_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
+ .transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_SRGB,
+ .primariesNameSet = true,
+ .primariesNamed = NColorManagement::CM_PRIMARIES_SRGB,
+ .primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_SRGB),
+ .luminances = {.min = SDR_MIN_LUMINANCE, .max = 80, .reference = 80},
+ });
+
static const auto DEFAULT_HDR_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
.primariesNameSet = true,
@@ -363,3 +394,30 @@ namespace NColorManagement {
.luminances = {.min = 0, .max = 10000, .reference = 80},
});
}
+
+template <typename CharT>
+struct std::formatter<Hyprgraphics::SPCPRimaries, CharT> : std::formatter<CharT> {
+ template <typename FormatContext>
+ auto format(const Hyprgraphics::SPCPRimaries& primaries, FormatContext& ctx) const {
+ return std::format_to(ctx.out(), "[r={},{} g={},{} b={},{} w={},{}]", primaries.red.x, primaries.red.y, primaries.green.x, primaries.green.y, primaries.blue.x,
+ primaries.blue.y, primaries.white.x, primaries.white.y);
+ }
+};
+
+template <typename CharT>
+struct std::formatter<NColorManagement::SImageDescription::SPCLuminances, CharT> : std::formatter<CharT> {
+ template <typename FormatContext>
+ auto format(const NColorManagement::SImageDescription::SPCLuminances& luminances, FormatContext& ctx) const {
+ return std::format_to(ctx.out(), "[{}-{}({})]", luminances.min, luminances.max, luminances.reference);
+ }
+};
+
+template <typename CharT>
+struct std::formatter<NColorManagement::SImageDescription, CharT> : std::formatter<CharT> {
+ template <typename FormatContext>
+ auto format(const NColorManagement::SImageDescription& imageDescription, FormatContext& ctx) const {
+ return std::format_to(ctx.out(), "[{}{}, primaries={}, luminances={}]", NColorManagement::tfToString(imageDescription.transferFunction),
+ imageDescription.transferFunctionPower != 1.0f ? std::format("^{}", imageDescription.transferFunctionPower) : "", imageDescription.getPrimaries(),
+ imageDescription.luminances);
+ }
+};