summaryrefslogtreecommitdiff
path: root/src/render
diff options
context:
space:
mode:
authorUjinT34 <41110182+UjinT34@users.noreply.github.com>2025-04-29 22:29:40 +0300
committerGitHub <noreply@github.com>2025-04-29 21:29:40 +0200
commit49974d5e34292ede24351c8638fe060b382bbda0 (patch)
tree162b1dab426dd3d152cc76fb5f42f6d10cf09968 /src/render
parent94bc1320843e4f45c4b8d3fd3cd08f8914b5fa13 (diff)
cm: Use precomputed primaries conversion (#9814)
Diffstat (limited to 'src/render')
-rw-r--r--src/render/OpenGL.cpp31
-rw-r--r--src/render/Shader.hpp4
-rw-r--r--src/render/shaders/glsl/CM.frag3
-rw-r--r--src/render/shaders/glsl/CM.glsl132
-rw-r--r--src/render/shaders/glsl/blurprepare.frag16
-rw-r--r--src/render/shaders/glsl/border.frag3
-rw-r--r--src/render/shaders/glsl/shadow.frag3
7 files changed, 84 insertions, 108 deletions
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index a6ddb519..a6cc176a 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -1,3 +1,5 @@
+#include <GLES3/gl32.h>
+#include <hyprgraphics/color/Color.hpp>
#include <hyprutils/string/String.hpp>
#include <hyprutils/path/Path.hpp>
#include <random>
@@ -908,13 +910,15 @@ static void getCMShaderUniforms(CShader& shader) {
shader.skipCM = glGetUniformLocation(shader.program, "skipCM");
shader.sourceTF = glGetUniformLocation(shader.program, "sourceTF");
shader.targetTF = glGetUniformLocation(shader.program, "targetTF");
- shader.sourcePrimaries = glGetUniformLocation(shader.program, "sourcePrimaries");
+ shader.srcTFRange = glGetUniformLocation(shader.program, "srcTFRange");
+ shader.dstTFRange = glGetUniformLocation(shader.program, "dstTFRange");
shader.targetPrimaries = glGetUniformLocation(shader.program, "targetPrimaries");
shader.maxLuminance = glGetUniformLocation(shader.program, "maxLuminance");
shader.dstMaxLuminance = glGetUniformLocation(shader.program, "dstMaxLuminance");
shader.dstRefLuminance = glGetUniformLocation(shader.program, "dstRefLuminance");
shader.sdrSaturation = glGetUniformLocation(shader.program, "sdrSaturation");
shader.sdrBrightness = glGetUniformLocation(shader.program, "sdrBrightnessMultiplier");
+ shader.convertMatrix = glGetUniformLocation(shader.program, "convertMatrix");
}
// shader has #include "rounding.glsl"
@@ -1437,27 +1441,26 @@ void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, const CBox& box,
scissor(nullptr);
}
+static std::map<std::pair<uint32_t, uint32_t>, std::array<GLfloat, 9>> primariesConversionCache;
+
void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const NColorManagement::SImageDescription& imageDescription,
const NColorManagement::SImageDescription& targetImageDescription, bool modifySDR) {
glUniform1i(shader.sourceTF, imageDescription.transferFunction);
glUniform1i(shader.targetTF, targetImageDescription.transferFunction);
- const auto sourcePrimaries =
- imageDescription.primariesNameSet || imageDescription.primaries == SPCPRimaries{} ? getPrimaries(imageDescription.primariesNamed) : imageDescription.primaries;
+
const auto targetPrimaries = targetImageDescription.primariesNameSet || targetImageDescription.primaries == SPCPRimaries{} ?
getPrimaries(targetImageDescription.primariesNamed) :
targetImageDescription.primaries;
- const GLfloat glSourcePrimaries[8] = {
- sourcePrimaries.red.x, sourcePrimaries.red.y, sourcePrimaries.green.x, sourcePrimaries.green.y,
- sourcePrimaries.blue.x, sourcePrimaries.blue.y, sourcePrimaries.white.x, sourcePrimaries.white.y,
- };
const GLfloat glTargetPrimaries[8] = {
targetPrimaries.red.x, targetPrimaries.red.y, targetPrimaries.green.x, targetPrimaries.green.y,
targetPrimaries.blue.x, targetPrimaries.blue.y, targetPrimaries.white.x, targetPrimaries.white.y,
};
- glUniformMatrix4x2fv(shader.sourcePrimaries, 1, false, glSourcePrimaries);
glUniformMatrix4x2fv(shader.targetPrimaries, 1, false, glTargetPrimaries);
+ glUniform2f(shader.srcTFRange, imageDescription.getTFMinLuminance(), imageDescription.getTFMaxLuminance());
+ glUniform2f(shader.dstTFRange, targetImageDescription.getTFMinLuminance(), targetImageDescription.getTFMaxLuminance());
+
const float maxLuminance = imageDescription.luminances.max > 0 ? imageDescription.luminances.max : imageDescription.luminances.reference;
glUniform1f(shader.maxLuminance, maxLuminance * targetImageDescription.luminances.reference / imageDescription.luminances.reference);
glUniform1f(shader.dstMaxLuminance, targetImageDescription.luminances.max > 0 ? targetImageDescription.luminances.max : 10000);
@@ -1469,7 +1472,19 @@ void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const NColorManageme
glUniform1f(shader.sdrBrightness,
modifySDR && m_RenderData.pMonitor->sdrBrightness > 0 && targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
m_RenderData.pMonitor->sdrBrightness :
+
1.0f);
+ const auto cacheKey = std::make_pair(imageDescription.getId(), targetImageDescription.getId());
+ if (!primariesConversionCache.contains(cacheKey)) {
+ const auto mat = imageDescription.getPrimaries().convertMatrix(targetImageDescription.getPrimaries()).mat();
+ const std::array<GLfloat, 9> glConvertMatrix = {
+ mat[0][0], mat[1][0], mat[2][0], //
+ mat[0][1], mat[1][1], mat[2][1], //
+ mat[0][2], mat[1][2], mat[2][2], //
+ };
+ primariesConversionCache.insert(std::make_pair(cacheKey, glConvertMatrix));
+ }
+ glUniformMatrix3fv(shader.convertMatrix, 1, false, &primariesConversionCache[cacheKey][0]);
}
void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const SImageDescription& imageDescription) {
diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp
index 1d21894c..cd9b6f22 100644
--- a/src/render/Shader.hpp
+++ b/src/render/Shader.hpp
@@ -15,13 +15,15 @@ class CShader {
GLint skipCM = -1;
GLint sourceTF = -1;
GLint targetTF = -1;
- GLint sourcePrimaries = -1;
+ GLint srcTFRange = -1;
+ GLint dstTFRange = -1;
GLint targetPrimaries = -1;
GLint maxLuminance = -1;
GLint dstMaxLuminance = -1;
GLint dstRefLuminance = -1;
GLint sdrSaturation = -1; // sdr -> hdr saturation
GLint sdrBrightness = -1; // sdr -> hdr brightness multiplier
+ GLint convertMatrix = -1;
GLint tex = -1;
GLint alpha = -1;
GLint posAttrib = -1;
diff --git a/src/render/shaders/glsl/CM.frag b/src/render/shaders/glsl/CM.frag
index 369e9cf0..031fe7f3 100644
--- a/src/render/shaders/glsl/CM.frag
+++ b/src/render/shaders/glsl/CM.frag
@@ -11,7 +11,6 @@ uniform int texType; // eTextureType: 0 - rgba, 1 - rgbx, 2 - ext
// uniform int skipCM;
uniform int sourceTF; // eTransferFunction
uniform int targetTF; // eTransferFunction
-uniform mat4x2 sourcePrimaries;
uniform mat4x2 targetPrimaries;
uniform float alpha;
@@ -43,7 +42,7 @@ void main() {
discard;
// this shader shouldn't be used when skipCM == 1
- pixColor = doColorManagement(pixColor, sourceTF, sourcePrimaries, targetTF, targetPrimaries);
+ pixColor = doColorManagement(pixColor, sourceTF, targetTF, targetPrimaries);
if (applyTint == 1)
pixColor = vec4(pixColor.rgb * tint.rgb, pixColor[3]);
diff --git a/src/render/shaders/glsl/CM.glsl b/src/render/shaders/glsl/CM.glsl
index 4cf2745c..8c505ee5 100644
--- a/src/render/shaders/glsl/CM.glsl
+++ b/src/render/shaders/glsl/CM.glsl
@@ -1,8 +1,12 @@
+uniform vec2 srcTFRange;
+uniform vec2 dstTFRange;
+
uniform float maxLuminance;
uniform float dstMaxLuminance;
uniform float dstRefLuminance;
uniform float sdrSaturation;
uniform float sdrBrightnessMultiplier;
+uniform mat3 convertMatrix;
//enum eTransferFunction
#define CM_TRANSFER_FUNCTION_BT1886 1
@@ -117,30 +121,8 @@ vec4 toLinear(vec4 color, int tf) {
return color;
}
-vec4 toNit(vec4 color, int tf) {
- if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
- color.rgb = color.rgb * SDR_MAX_LUMINANCE;
- else {
-
- switch (tf) {
- case CM_TRANSFER_FUNCTION_ST2084_PQ:
- color.rgb = color.rgb * (HDR_MAX_LUMINANCE - HDR_MIN_LUMINANCE) + HDR_MIN_LUMINANCE; break;
- case CM_TRANSFER_FUNCTION_HLG:
- color.rgb = color.rgb * (HLG_MAX_LUMINANCE - HDR_MIN_LUMINANCE) + HDR_MIN_LUMINANCE; break;
- case CM_TRANSFER_FUNCTION_GAMMA22:
- case CM_TRANSFER_FUNCTION_GAMMA28:
- case CM_TRANSFER_FUNCTION_BT1886:
- case CM_TRANSFER_FUNCTION_ST240:
- case CM_TRANSFER_FUNCTION_LOG_100:
- case CM_TRANSFER_FUNCTION_LOG_316:
- case CM_TRANSFER_FUNCTION_XVYCC:
- case CM_TRANSFER_FUNCTION_EXT_SRGB:
- case CM_TRANSFER_FUNCTION_ST428:
- case CM_TRANSFER_FUNCTION_SRGB:
- default:
- color.rgb = color.rgb * (SDR_MAX_LUMINANCE - SDR_MIN_LUMINANCE) + SDR_MIN_LUMINANCE; break;
- }
- }
+vec4 toNit(vec4 color, vec2 range) {
+ color.rgb = color.rgb * (range[1] - range[0]) + range[0];
return color;
}
@@ -195,33 +177,13 @@ vec4 fromLinear(vec4 color, int tf) {
return color;
}
-vec4 fromLinearNit(vec4 color, int tf) {
+vec4 fromLinearNit(vec4 color, int tf, vec2 range) {
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
color.rgb = color.rgb / SDR_MAX_LUMINANCE;
else {
color.rgb /= max(color.a, 0.001);
-
- switch (tf) {
- case CM_TRANSFER_FUNCTION_ST2084_PQ:
- color.rgb = (color.rgb - HDR_MIN_LUMINANCE) / (HDR_MAX_LUMINANCE - HDR_MIN_LUMINANCE); break;
- case CM_TRANSFER_FUNCTION_HLG:
- color.rgb = (color.rgb - HDR_MIN_LUMINANCE) / (HLG_MAX_LUMINANCE - HDR_MIN_LUMINANCE); break;
- case CM_TRANSFER_FUNCTION_GAMMA22:
- case CM_TRANSFER_FUNCTION_GAMMA28:
- case CM_TRANSFER_FUNCTION_BT1886:
- case CM_TRANSFER_FUNCTION_ST240:
- case CM_TRANSFER_FUNCTION_LOG_100:
- case CM_TRANSFER_FUNCTION_LOG_316:
- case CM_TRANSFER_FUNCTION_XVYCC:
- case CM_TRANSFER_FUNCTION_EXT_SRGB:
- case CM_TRANSFER_FUNCTION_ST428:
- case CM_TRANSFER_FUNCTION_SRGB:
- default:
- color.rgb = (color.rgb - SDR_MIN_LUMINANCE) / (SDR_MAX_LUMINANCE - SDR_MIN_LUMINANCE); break;
- }
-
+ color.rgb = (color.rgb - range[0]) / (range[1] - range[0]);
color.rgb = fromLinearRGB(color.rgb, tf);
-
color.rgb *= color.a;
}
return color;
@@ -250,13 +212,6 @@ mat3 primaries2xyz(mat4x2 primaries) {
);
}
-// const vec2 D65 = vec2(0.3127, 0.3290);
-const mat3 Bradford = mat3(
- 0.8951, 0.2664, -0.1614,
- -0.7502, 1.7135, 0.0367,
- 0.0389, -0.0685, 1.0296
-);
-const mat3 BradfordInv = inverse(Bradford);
mat3 adaptWhite(vec2 src, vec2 dst) {
if (src == dst)
@@ -266,6 +221,13 @@ mat3 adaptWhite(vec2 src, vec2 dst) {
0.0, 0.0, 1.0
);
+ // const vec2 D65 = vec2(0.3127, 0.3290);
+ const mat3 Bradford = mat3(
+ 0.8951, 0.2664, -0.1614,
+ -0.7502, 1.7135, 0.0367,
+ 0.0389, -0.0685, 1.0296
+ );
+ mat3 BradfordInv = inverse(Bradford);
vec3 srcXYZ = xy2xyz(src);
vec3 dstXYZ = xy2xyz(dst);
vec3 factors = (Bradford * dstXYZ) / (Bradford * srcXYZ);
@@ -287,21 +249,37 @@ const mat3 BT2020toLMS = mat3(
-0.1922, 1.1004, 0.0755,
0.0070, 0.0749, 0.8434
);
-const mat3 LMStoBT2020 = inverse(BT2020toLMS);
-
-const mat3 ICtCpPQ = transpose(mat3(
- 2048.0, 2048.0, 0.0,
- 6610.0, -13613.0, 7003.0,
- 17933.0, -17390.0, -543.0
-) / 4096.0);
-const mat3 ICtCpPQInv = inverse(ICtCpPQ);
-
-const mat3 ICtCpHLG = transpose(mat3(
- 2048.0, 2048.0, 0.0,
- 3625.0, -7465.0, 3840.0,
- 9500.0, -9212.0, -288.0
-) / 4096.0);
-const mat3 ICtCpHLGInv = inverse(ICtCpHLG);
+//const mat3 LMStoBT2020 = inverse(BT2020toLMS);
+const mat3 LMStoBT2020 = mat3(
+ 2.0701800566956135096, -1.3264568761030210255, 0.20661600684785517081,
+ 0.36498825003265747974, 0.68046736285223514102, -0.045421753075853231409,
+ -0.049595542238932107896, -0.049421161186757487412, 1.1879959417328034394
+);
+
+// const mat3 ICtCpPQ = transpose(mat3(
+// 2048.0, 2048.0, 0.0,
+// 6610.0, -13613.0, 7003.0,
+// 17933.0, -17390.0, -543.0
+// ) / 4096.0);
+const mat3 ICtCpPQ = mat3(
+ 0.5, 1.61376953125, 4.378173828125,
+ 0.5, -3.323486328125, -4.24560546875,
+ 0.0, 1.709716796875, -0.132568359375
+);
+//const mat3 ICtCpPQInv = inverse(ICtCpPQ);
+const mat3 ICtCpPQInv = mat3(
+ 1.0, 1.0, 1.0,
+ 0.0086090370379327566, -0.0086090370379327566, 0.560031335710679118,
+ 0.11102962500302595656, -0.11102962500302595656, -0.32062717498731885185
+);
+
+// unused for now
+// const mat3 ICtCpHLG = transpose(mat3(
+// 2048.0, 2048.0, 0.0,
+// 3625.0, -7465.0, 3840.0,
+// 9500.0, -9212.0, -288.0
+// ) / 4096.0);
+// const mat3 ICtCpHLGInv = inverse(ICtCpHLG);
vec4 tonemap(vec4 color, mat3 dstXYZ) {
if (maxLuminance < dstMaxLuminance * 1.01)
@@ -339,23 +317,17 @@ vec4 tonemap(vec4 color, mat3 dstXYZ) {
return vec4(fromLMS * toLinear(vec4(ICtCpPQInv * ICtCp, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb * HDR_MAX_LUMINANCE, color[3]);
}
-vec4 doColorManagement(vec4 pixColor, int srcTF, mat4x2 srcPrimaries, int dstTF, mat4x2 dstPrimaries) {
+vec4 doColorManagement(vec4 pixColor, int srcTF, int dstTF, mat4x2 dstPrimaries) {
pixColor.rgb /= max(pixColor.a, 0.001);
pixColor.rgb = toLinearRGB(pixColor.rgb, srcTF);
- mat3 srcxyz = primaries2xyz(srcPrimaries);
- mat3 dstxyz;
- if (srcPrimaries == dstPrimaries)
- dstxyz = srcxyz;
- else {
- dstxyz = primaries2xyz(dstPrimaries);
- pixColor = convertPrimaries(pixColor, srcxyz, srcPrimaries[3], dstxyz, dstPrimaries[3]);
- }
- pixColor = toNit(pixColor, srcTF);
+ pixColor.rgb = convertMatrix * pixColor.rgb;
+ pixColor = toNit(pixColor, srcTFRange);
pixColor.rgb *= pixColor.a;
+ mat3 dstxyz = primaries2xyz(dstPrimaries);
pixColor = tonemap(pixColor, dstxyz);
- pixColor = fromLinearNit(pixColor, dstTF);
+ pixColor = fromLinearNit(pixColor, dstTF, dstTFRange);
if (srcTF == CM_TRANSFER_FUNCTION_SRGB && dstTF == CM_TRANSFER_FUNCTION_ST2084_PQ) {
- pixColor = saturate(pixColor, srcxyz, sdrSaturation);
+ pixColor = saturate(pixColor, dstxyz, sdrSaturation);
pixColor.rgb /= pixColor.a;
pixColor.rgb *= sdrBrightnessMultiplier;
pixColor.rgb *= pixColor.a;
diff --git a/src/render/shaders/glsl/blurprepare.frag b/src/render/shaders/glsl/blurprepare.frag
index 0be2d53a..548289c3 100644
--- a/src/render/shaders/glsl/blurprepare.frag
+++ b/src/render/shaders/glsl/blurprepare.frag
@@ -11,8 +11,6 @@ uniform float brightness;
uniform int skipCM;
uniform int sourceTF; // eTransferFunction
uniform int targetTF; // eTransferFunction
-uniform mat4x2 sourcePrimaries;
-uniform mat4x2 targetPrimaries;
#include "CM.glsl"
@@ -29,17 +27,9 @@ void main() {
if (sourceTF == CM_TRANSFER_FUNCTION_ST2084_PQ) {
pixColor.rgb /= sdrBrightnessMultiplier;
}
- pixColor.rgb = toLinearRGB(pixColor.rgb, sourceTF);
- mat3 srcxyz = primaries2xyz(sourcePrimaries);
- mat3 dstxyz;
- if (sourcePrimaries == targetPrimaries)
- dstxyz = srcxyz;
- else {
- dstxyz = primaries2xyz(targetPrimaries);
- pixColor = convertPrimaries(pixColor, srcxyz, sourcePrimaries[3], dstxyz, targetPrimaries[3]);
- }
- pixColor = toNit(pixColor, sourceTF);
- pixColor = fromLinearNit(pixColor, targetTF);
+ pixColor.rgb = convertMatrix * toLinearRGB(pixColor.rgb, sourceTF);
+ pixColor = toNit(pixColor, srcTFRange);
+ pixColor = fromLinearNit(pixColor, targetTF, dstTFRange);
}
// contrast
diff --git a/src/render/shaders/glsl/border.frag b/src/render/shaders/glsl/border.frag
index 68541e14..38ae24c0 100644
--- a/src/render/shaders/glsl/border.frag
+++ b/src/render/shaders/glsl/border.frag
@@ -7,7 +7,6 @@ in vec2 v_texcoord;
uniform int skipCM;
uniform int sourceTF; // eTransferFunction
uniform int targetTF; // eTransferFunction
-uniform mat4x2 sourcePrimaries;
uniform mat4x2 targetPrimaries;
uniform vec2 fullSizeUntransformed;
@@ -175,7 +174,7 @@ void main() {
pixColor.rgb *= pixColor[3];
if (skipCM == 0)
- pixColor = doColorManagement(pixColor, sourceTF, sourcePrimaries, targetTF, targetPrimaries);
+ pixColor = doColorManagement(pixColor, sourceTF, targetTF, targetPrimaries);
pixColor *= alpha * additionalAlpha;
diff --git a/src/render/shaders/glsl/shadow.frag b/src/render/shaders/glsl/shadow.frag
index 7a930f96..b6fdf6ee 100644
--- a/src/render/shaders/glsl/shadow.frag
+++ b/src/render/shaders/glsl/shadow.frag
@@ -8,7 +8,6 @@ in vec2 v_texcoord;
uniform int skipCM;
uniform int sourceTF; // eTransferFunction
uniform int targetTF; // eTransferFunction
-uniform mat4x2 sourcePrimaries;
uniform mat4x2 targetPrimaries;
uniform vec2 topLeft;
@@ -94,7 +93,7 @@ void main() {
pixColor.rgb *= pixColor[3];
if (skipCM == 0)
- pixColor = doColorManagement(pixColor, sourceTF, sourcePrimaries, targetTF, targetPrimaries);
+ pixColor = doColorManagement(pixColor, sourceTF, targetTF, targetPrimaries);
fragColor = pixColor;
} \ No newline at end of file