Skip to content

Commit 49974d5

Browse files
authored
cm: Use precomputed primaries conversion (#9814)
1 parent 94bc132 commit 49974d5

File tree

10 files changed

+166
-138
lines changed

10 files changed

+166
-138
lines changed

src/protocols/ColorManagement.cpp

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
using namespace NColorManagement;
1010

11-
static uint64_t lastImageID = 0; // FIXME use for deduplication
12-
1311
CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resource) {
1412
if UNLIKELY (!good())
1513
return;
@@ -191,14 +189,13 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
191189
}
192190

193191
RESOURCE->self = RESOURCE;
194-
RESOURCE->settings.id = ++lastImageID;
195192
RESOURCE->settings.windowsScRGB = true;
196193
RESOURCE->settings.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB;
197194
RESOURCE->settings.primariesNameSet = true;
198195
RESOURCE->settings.primaries = NColorPrimaries::BT709;
199196
RESOURCE->settings.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_EXT_LINEAR;
200197
RESOURCE->settings.luminances.reference = 203;
201-
RESOURCE->resource()->sendReady(RESOURCE->settings.id);
198+
RESOURCE->resource()->sendReady(RESOURCE->settings.updateId());
202199
});
203200

204201
m_resource->setOnDestroy([this](CWpColorManagerV1* r) { PROTO::colorManagement->destroyResource(this); });
@@ -239,9 +236,7 @@ CColorManagementOutput::CColorManagementOutput(SP<CWpColorManagementOutputV1> re
239236
RESOURCE->m_resource->sendFailed(WP_IMAGE_DESCRIPTION_V1_CAUSE_NO_OUTPUT, "No output");
240237
else {
241238
RESOURCE->settings = m_monitor->imageDescription;
242-
if (RESOURCE->settings.id)
243-
RESOURCE->settings.id = ++lastImageID;
244-
RESOURCE->m_resource->sendReady(RESOURCE->settings.id); // FIXME: create correct id
239+
RESOURCE->m_resource->sendReady(RESOURCE->settings.updateId());
245240
}
246241
});
247242
}
@@ -383,10 +378,7 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP<CWpColorMana
383378
m_currentPreferred = RESOURCE;
384379

385380
m_currentPreferred->settings = g_pCompositor->getPreferredImageDescription();
386-
if (!m_currentPreferred->settings.id)
387-
m_currentPreferred->settings.id = ++lastImageID;
388-
389-
RESOURCE->resource()->sendReady(++lastImageID); // FIXME: create correct id
381+
RESOURCE->resource()->sendReady(m_currentPreferred->settings.updateId());
390382
});
391383

392384
m_resource->setGetPreferredParametric([this](CWpColorManagementSurfaceFeedbackV1* r, uint32_t id) {
@@ -419,7 +411,7 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP<CWpColorMana
419411
return;
420412
}
421413

422-
RESOURCE->resource()->sendReady(++lastImageID); // FIXME: create correct id
414+
RESOURCE->resource()->sendReady(m_currentPreferred->settings.updateId());
423415
});
424416
}
425417

@@ -467,8 +459,7 @@ CColorManagementIccCreator::CColorManagementIccCreator(SP<CWpImageDescriptionCre
467459

468460
RESOURCE->self = RESOURCE;
469461
RESOURCE->settings = settings;
470-
settings.id = ++lastImageID;
471-
RESOURCE->resource()->sendReady(settings.id); // FIXME: create correct id
462+
RESOURCE->resource()->sendReady(settings.updateId());
472463

473464
PROTO::colorManagement->destroyResource(this);
474465
});
@@ -522,8 +513,7 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CWpImage
522513

523514
RESOURCE->self = RESOURCE;
524515
RESOURCE->settings = settings;
525-
settings.id = ++lastImageID;
526-
RESOURCE->resource()->sendReady(settings.id); // FIXME: create correct id
516+
RESOURCE->resource()->sendReady(settings.updateId());
527517

528518
PROTO::colorManagement->destroyResource(this);
529519
});

src/protocols/types/ColorManagement.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
#include "ColorManagement.hpp"
2+
#include <map>
23

34
namespace NColorManagement {
4-
const SPCPRimaries& getPrimaries(ePrimaries name) {
5+
static uint32_t lastImageID = 0;
6+
static std::map<uint32_t, SImageDescription> knownDescriptionIds; // expected to be small
7+
8+
const SPCPRimaries& getPrimaries(ePrimaries name) {
59
switch (name) {
610
case CM_PRIMARIES_SRGB: return NColorPrimaries::BT709;
711
case CM_PRIMARIES_BT2020: return NColorPrimaries::BT2020;
@@ -17,4 +21,26 @@ namespace NColorManagement {
1721
}
1822
}
1923

24+
// TODO make image descriptions immutable and always set an id
25+
26+
uint32_t SImageDescription::findId() const {
27+
for (auto it = knownDescriptionIds.begin(); it != knownDescriptionIds.end(); ++it) {
28+
if (it->second == *this)
29+
return it->first;
30+
}
31+
32+
const auto newId = ++lastImageID;
33+
knownDescriptionIds.insert(std::make_pair(newId, *this));
34+
return newId;
35+
}
36+
37+
uint32_t SImageDescription::getId() const {
38+
return id > 0 ? id : findId();
39+
}
40+
41+
uint32_t SImageDescription::updateId() {
42+
id = 0;
43+
id = findId();
44+
return id;
45+
}
2046
}

src/protocols/types/ColorManagement.hpp

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
#pragma once
22

33
#include "color-management-v1.hpp"
4+
#include <hyprgraphics/color/Color.hpp>
5+
6+
#define SDR_MIN_LUMINANCE 0.2
7+
#define SDR_MAX_LUMINANCE 80.0
8+
#define HDR_MIN_LUMINANCE 0.005
9+
#define HDR_MAX_LUMINANCE 10000.0
10+
#define HLG_MAX_LUMINANCE 1000.0
411

512
namespace NColorManagement {
613
enum ePrimaries : uint8_t {
@@ -47,19 +54,7 @@ namespace NColorManagement {
4754
return (eTransferFunction)tf;
4855
}
4956

50-
struct SPCPRimaries {
51-
struct xy { //NOLINT(readability-identifier-naming)
52-
float x = 0;
53-
float y = 0;
54-
55-
bool operator==(const xy& p2) const {
56-
return x == p2.x && y == p2.y;
57-
}
58-
} red, green, blue, white;
59-
bool operator==(const SPCPRimaries& p2) const {
60-
return red == p2.red && green == p2.green && blue == p2.blue && white == p2.white;
61-
}
62-
};
57+
typedef Hyprgraphics::SPCPRimaries SPCPRimaries;
6358

6459
namespace NColorPrimaries {
6560
static const auto DEFAULT_PRIMARIES = SPCPRimaries{};
@@ -185,5 +180,46 @@ namespace NColorManagement {
185180
return NColorManagement::getPrimaries(primariesNamed);
186181
return primaries;
187182
}
183+
184+
float getTFMinLuminance() const {
185+
switch (transferFunction) {
186+
case CM_TRANSFER_FUNCTION_EXT_LINEAR: return 0;
187+
case CM_TRANSFER_FUNCTION_ST2084_PQ:
188+
case CM_TRANSFER_FUNCTION_HLG: return HDR_MIN_LUMINANCE;
189+
case CM_TRANSFER_FUNCTION_GAMMA22:
190+
case CM_TRANSFER_FUNCTION_GAMMA28:
191+
case CM_TRANSFER_FUNCTION_BT1886:
192+
case CM_TRANSFER_FUNCTION_ST240:
193+
case CM_TRANSFER_FUNCTION_LOG_100:
194+
case CM_TRANSFER_FUNCTION_LOG_316:
195+
case CM_TRANSFER_FUNCTION_XVYCC:
196+
case CM_TRANSFER_FUNCTION_EXT_SRGB:
197+
case CM_TRANSFER_FUNCTION_ST428:
198+
case CM_TRANSFER_FUNCTION_SRGB:
199+
default: return SDR_MIN_LUMINANCE;
200+
}
201+
};
202+
203+
float getTFMaxLuminance() const {
204+
switch (transferFunction) {
205+
case CM_TRANSFER_FUNCTION_ST2084_PQ: return HDR_MAX_LUMINANCE;
206+
case CM_TRANSFER_FUNCTION_HLG: return HLG_MAX_LUMINANCE;
207+
case CM_TRANSFER_FUNCTION_GAMMA22:
208+
case CM_TRANSFER_FUNCTION_GAMMA28:
209+
case CM_TRANSFER_FUNCTION_BT1886:
210+
case CM_TRANSFER_FUNCTION_ST240:
211+
case CM_TRANSFER_FUNCTION_LOG_100:
212+
case CM_TRANSFER_FUNCTION_LOG_316:
213+
case CM_TRANSFER_FUNCTION_XVYCC:
214+
case CM_TRANSFER_FUNCTION_EXT_SRGB:
215+
case CM_TRANSFER_FUNCTION_ST428:
216+
case CM_TRANSFER_FUNCTION_SRGB:
217+
default: return SDR_MAX_LUMINANCE;
218+
}
219+
};
220+
221+
uint32_t findId() const;
222+
uint32_t getId() const;
223+
uint32_t updateId();
188224
};
189225
}

src/render/OpenGL.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <GLES3/gl32.h>
2+
#include <hyprgraphics/color/Color.hpp>
13
#include <hyprutils/string/String.hpp>
24
#include <hyprutils/path/Path.hpp>
35
#include <random>
@@ -908,13 +910,15 @@ static void getCMShaderUniforms(CShader& shader) {
908910
shader.skipCM = glGetUniformLocation(shader.program, "skipCM");
909911
shader.sourceTF = glGetUniformLocation(shader.program, "sourceTF");
910912
shader.targetTF = glGetUniformLocation(shader.program, "targetTF");
911-
shader.sourcePrimaries = glGetUniformLocation(shader.program, "sourcePrimaries");
913+
shader.srcTFRange = glGetUniformLocation(shader.program, "srcTFRange");
914+
shader.dstTFRange = glGetUniformLocation(shader.program, "dstTFRange");
912915
shader.targetPrimaries = glGetUniformLocation(shader.program, "targetPrimaries");
913916
shader.maxLuminance = glGetUniformLocation(shader.program, "maxLuminance");
914917
shader.dstMaxLuminance = glGetUniformLocation(shader.program, "dstMaxLuminance");
915918
shader.dstRefLuminance = glGetUniformLocation(shader.program, "dstRefLuminance");
916919
shader.sdrSaturation = glGetUniformLocation(shader.program, "sdrSaturation");
917920
shader.sdrBrightness = glGetUniformLocation(shader.program, "sdrBrightnessMultiplier");
921+
shader.convertMatrix = glGetUniformLocation(shader.program, "convertMatrix");
918922
}
919923

920924
// shader has #include "rounding.glsl"
@@ -1437,27 +1441,26 @@ void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, const CBox& box,
14371441
scissor(nullptr);
14381442
}
14391443

1444+
static std::map<std::pair<uint32_t, uint32_t>, std::array<GLfloat, 9>> primariesConversionCache;
1445+
14401446
void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const NColorManagement::SImageDescription& imageDescription,
14411447
const NColorManagement::SImageDescription& targetImageDescription, bool modifySDR) {
14421448
glUniform1i(shader.sourceTF, imageDescription.transferFunction);
14431449
glUniform1i(shader.targetTF, targetImageDescription.transferFunction);
1444-
const auto sourcePrimaries =
1445-
imageDescription.primariesNameSet || imageDescription.primaries == SPCPRimaries{} ? getPrimaries(imageDescription.primariesNamed) : imageDescription.primaries;
1450+
14461451
const auto targetPrimaries = targetImageDescription.primariesNameSet || targetImageDescription.primaries == SPCPRimaries{} ?
14471452
getPrimaries(targetImageDescription.primariesNamed) :
14481453
targetImageDescription.primaries;
14491454

1450-
const GLfloat glSourcePrimaries[8] = {
1451-
sourcePrimaries.red.x, sourcePrimaries.red.y, sourcePrimaries.green.x, sourcePrimaries.green.y,
1452-
sourcePrimaries.blue.x, sourcePrimaries.blue.y, sourcePrimaries.white.x, sourcePrimaries.white.y,
1453-
};
14541455
const GLfloat glTargetPrimaries[8] = {
14551456
targetPrimaries.red.x, targetPrimaries.red.y, targetPrimaries.green.x, targetPrimaries.green.y,
14561457
targetPrimaries.blue.x, targetPrimaries.blue.y, targetPrimaries.white.x, targetPrimaries.white.y,
14571458
};
1458-
glUniformMatrix4x2fv(shader.sourcePrimaries, 1, false, glSourcePrimaries);
14591459
glUniformMatrix4x2fv(shader.targetPrimaries, 1, false, glTargetPrimaries);
14601460

1461+
glUniform2f(shader.srcTFRange, imageDescription.getTFMinLuminance(), imageDescription.getTFMaxLuminance());
1462+
glUniform2f(shader.dstTFRange, targetImageDescription.getTFMinLuminance(), targetImageDescription.getTFMaxLuminance());
1463+
14611464
const float maxLuminance = imageDescription.luminances.max > 0 ? imageDescription.luminances.max : imageDescription.luminances.reference;
14621465
glUniform1f(shader.maxLuminance, maxLuminance * targetImageDescription.luminances.reference / imageDescription.luminances.reference);
14631466
glUniform1f(shader.dstMaxLuminance, targetImageDescription.luminances.max > 0 ? targetImageDescription.luminances.max : 10000);
@@ -1469,7 +1472,19 @@ void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const NColorManageme
14691472
glUniform1f(shader.sdrBrightness,
14701473
modifySDR && m_RenderData.pMonitor->sdrBrightness > 0 && targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
14711474
m_RenderData.pMonitor->sdrBrightness :
1475+
14721476
1.0f);
1477+
const auto cacheKey = std::make_pair(imageDescription.getId(), targetImageDescription.getId());
1478+
if (!primariesConversionCache.contains(cacheKey)) {
1479+
const auto mat = imageDescription.getPrimaries().convertMatrix(targetImageDescription.getPrimaries()).mat();
1480+
const std::array<GLfloat, 9> glConvertMatrix = {
1481+
mat[0][0], mat[1][0], mat[2][0], //
1482+
mat[0][1], mat[1][1], mat[2][1], //
1483+
mat[0][2], mat[1][2], mat[2][2], //
1484+
};
1485+
primariesConversionCache.insert(std::make_pair(cacheKey, glConvertMatrix));
1486+
}
1487+
glUniformMatrix3fv(shader.convertMatrix, 1, false, &primariesConversionCache[cacheKey][0]);
14731488
}
14741489

14751490
void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const SImageDescription& imageDescription) {

src/render/Shader.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ class CShader {
1515
GLint skipCM = -1;
1616
GLint sourceTF = -1;
1717
GLint targetTF = -1;
18-
GLint sourcePrimaries = -1;
18+
GLint srcTFRange = -1;
19+
GLint dstTFRange = -1;
1920
GLint targetPrimaries = -1;
2021
GLint maxLuminance = -1;
2122
GLint dstMaxLuminance = -1;
2223
GLint dstRefLuminance = -1;
2324
GLint sdrSaturation = -1; // sdr -> hdr saturation
2425
GLint sdrBrightness = -1; // sdr -> hdr brightness multiplier
26+
GLint convertMatrix = -1;
2527
GLint tex = -1;
2628
GLint alpha = -1;
2729
GLint posAttrib = -1;

src/render/shaders/glsl/CM.frag

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ uniform int texType; // eTextureType: 0 - rgba, 1 - rgbx, 2 - ext
1111
// uniform int skipCM;
1212
uniform int sourceTF; // eTransferFunction
1313
uniform int targetTF; // eTransferFunction
14-
uniform mat4x2 sourcePrimaries;
1514
uniform mat4x2 targetPrimaries;
1615

1716
uniform float alpha;
@@ -43,7 +42,7 @@ void main() {
4342
discard;
4443

4544
// this shader shouldn't be used when skipCM == 1
46-
pixColor = doColorManagement(pixColor, sourceTF, sourcePrimaries, targetTF, targetPrimaries);
45+
pixColor = doColorManagement(pixColor, sourceTF, targetTF, targetPrimaries);
4746

4847
if (applyTint == 1)
4948
pixColor = vec4(pixColor.rgb * tint.rgb, pixColor[3]);

0 commit comments

Comments
 (0)