cm: Use precomputed primaries conversion (#9814)

This commit is contained in:
UjinT34 2025-04-29 22:29:40 +03:00 committed by GitHub
parent 94bc132084
commit 49974d5e34
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 164 additions and 136 deletions

View file

@ -8,8 +8,6 @@
using namespace NColorManagement; using namespace NColorManagement;
static uint64_t lastImageID = 0; // FIXME use for deduplication
CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resource) { CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resource) {
if UNLIKELY (!good()) if UNLIKELY (!good())
return; return;
@ -191,14 +189,13 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
} }
RESOURCE->self = RESOURCE; RESOURCE->self = RESOURCE;
RESOURCE->settings.id = ++lastImageID;
RESOURCE->settings.windowsScRGB = true; RESOURCE->settings.windowsScRGB = true;
RESOURCE->settings.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB; RESOURCE->settings.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB;
RESOURCE->settings.primariesNameSet = true; RESOURCE->settings.primariesNameSet = true;
RESOURCE->settings.primaries = NColorPrimaries::BT709; RESOURCE->settings.primaries = NColorPrimaries::BT709;
RESOURCE->settings.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_EXT_LINEAR; RESOURCE->settings.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_EXT_LINEAR;
RESOURCE->settings.luminances.reference = 203; RESOURCE->settings.luminances.reference = 203;
RESOURCE->resource()->sendReady(RESOURCE->settings.id); RESOURCE->resource()->sendReady(RESOURCE->settings.updateId());
}); });
m_resource->setOnDestroy([this](CWpColorManagerV1* r) { PROTO::colorManagement->destroyResource(this); }); m_resource->setOnDestroy([this](CWpColorManagerV1* r) { PROTO::colorManagement->destroyResource(this); });
@ -239,9 +236,7 @@ CColorManagementOutput::CColorManagementOutput(SP<CWpColorManagementOutputV1> re
RESOURCE->m_resource->sendFailed(WP_IMAGE_DESCRIPTION_V1_CAUSE_NO_OUTPUT, "No output"); RESOURCE->m_resource->sendFailed(WP_IMAGE_DESCRIPTION_V1_CAUSE_NO_OUTPUT, "No output");
else { else {
RESOURCE->settings = m_monitor->imageDescription; RESOURCE->settings = m_monitor->imageDescription;
if (RESOURCE->settings.id) RESOURCE->m_resource->sendReady(RESOURCE->settings.updateId());
RESOURCE->settings.id = ++lastImageID;
RESOURCE->m_resource->sendReady(RESOURCE->settings.id); // FIXME: create correct id
} }
}); });
} }
@ -383,10 +378,7 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP<CWpColorMana
m_currentPreferred = RESOURCE; m_currentPreferred = RESOURCE;
m_currentPreferred->settings = g_pCompositor->getPreferredImageDescription(); m_currentPreferred->settings = g_pCompositor->getPreferredImageDescription();
if (!m_currentPreferred->settings.id) RESOURCE->resource()->sendReady(m_currentPreferred->settings.updateId());
m_currentPreferred->settings.id = ++lastImageID;
RESOURCE->resource()->sendReady(++lastImageID); // FIXME: create correct id
}); });
m_resource->setGetPreferredParametric([this](CWpColorManagementSurfaceFeedbackV1* r, uint32_t id) { m_resource->setGetPreferredParametric([this](CWpColorManagementSurfaceFeedbackV1* r, uint32_t id) {
@ -419,7 +411,7 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP<CWpColorMana
return; return;
} }
RESOURCE->resource()->sendReady(++lastImageID); // FIXME: create correct id RESOURCE->resource()->sendReady(m_currentPreferred->settings.updateId());
}); });
} }
@ -467,8 +459,7 @@ CColorManagementIccCreator::CColorManagementIccCreator(SP<CWpImageDescriptionCre
RESOURCE->self = RESOURCE; RESOURCE->self = RESOURCE;
RESOURCE->settings = settings; RESOURCE->settings = settings;
settings.id = ++lastImageID; RESOURCE->resource()->sendReady(settings.updateId());
RESOURCE->resource()->sendReady(settings.id); // FIXME: create correct id
PROTO::colorManagement->destroyResource(this); PROTO::colorManagement->destroyResource(this);
}); });
@ -522,8 +513,7 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CWpImage
RESOURCE->self = RESOURCE; RESOURCE->self = RESOURCE;
RESOURCE->settings = settings; RESOURCE->settings = settings;
settings.id = ++lastImageID; RESOURCE->resource()->sendReady(settings.updateId());
RESOURCE->resource()->sendReady(settings.id); // FIXME: create correct id
PROTO::colorManagement->destroyResource(this); PROTO::colorManagement->destroyResource(this);
}); });

View file

@ -1,6 +1,10 @@
#include "ColorManagement.hpp" #include "ColorManagement.hpp"
#include <map>
namespace NColorManagement { namespace NColorManagement {
static uint32_t lastImageID = 0;
static std::map<uint32_t, SImageDescription> knownDescriptionIds; // expected to be small
const SPCPRimaries& getPrimaries(ePrimaries name) { const SPCPRimaries& getPrimaries(ePrimaries name) {
switch (name) { switch (name) {
case CM_PRIMARIES_SRGB: return NColorPrimaries::BT709; case CM_PRIMARIES_SRGB: return NColorPrimaries::BT709;
@ -17,4 +21,26 @@ namespace NColorManagement {
} }
} }
// TODO make image descriptions immutable and always set an id
uint32_t SImageDescription::findId() const {
for (auto it = knownDescriptionIds.begin(); it != knownDescriptionIds.end(); ++it) {
if (it->second == *this)
return it->first;
}
const auto newId = ++lastImageID;
knownDescriptionIds.insert(std::make_pair(newId, *this));
return newId;
}
uint32_t SImageDescription::getId() const {
return id > 0 ? id : findId();
}
uint32_t SImageDescription::updateId() {
id = 0;
id = findId();
return id;
}
} }

View file

@ -1,6 +1,13 @@
#pragma once #pragma once
#include "color-management-v1.hpp" #include "color-management-v1.hpp"
#include <hyprgraphics/color/Color.hpp>
#define SDR_MIN_LUMINANCE 0.2
#define SDR_MAX_LUMINANCE 80.0
#define HDR_MIN_LUMINANCE 0.005
#define HDR_MAX_LUMINANCE 10000.0
#define HLG_MAX_LUMINANCE 1000.0
namespace NColorManagement { namespace NColorManagement {
enum ePrimaries : uint8_t { enum ePrimaries : uint8_t {
@ -47,19 +54,7 @@ namespace NColorManagement {
return (eTransferFunction)tf; return (eTransferFunction)tf;
} }
struct SPCPRimaries { typedef Hyprgraphics::SPCPRimaries SPCPRimaries;
struct xy { //NOLINT(readability-identifier-naming)
float x = 0;
float y = 0;
bool operator==(const xy& p2) const {
return x == p2.x && y == p2.y;
}
} red, green, blue, white;
bool operator==(const SPCPRimaries& p2) const {
return red == p2.red && green == p2.green && blue == p2.blue && white == p2.white;
}
};
namespace NColorPrimaries { namespace NColorPrimaries {
static const auto DEFAULT_PRIMARIES = SPCPRimaries{}; static const auto DEFAULT_PRIMARIES = SPCPRimaries{};
@ -185,5 +180,46 @@ namespace NColorManagement {
return NColorManagement::getPrimaries(primariesNamed); return NColorManagement::getPrimaries(primariesNamed);
return primaries; return primaries;
} }
float getTFMinLuminance() const {
switch (transferFunction) {
case CM_TRANSFER_FUNCTION_EXT_LINEAR: return 0;
case CM_TRANSFER_FUNCTION_ST2084_PQ:
case CM_TRANSFER_FUNCTION_HLG: return HDR_MIN_LUMINANCE;
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: return SDR_MIN_LUMINANCE;
}
};
float getTFMaxLuminance() const {
switch (transferFunction) {
case CM_TRANSFER_FUNCTION_ST2084_PQ: return HDR_MAX_LUMINANCE;
case CM_TRANSFER_FUNCTION_HLG: return HLG_MAX_LUMINANCE;
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: return SDR_MAX_LUMINANCE;
}
};
uint32_t findId() const;
uint32_t getId() const;
uint32_t updateId();
}; };
} }

View file

@ -1,3 +1,5 @@
#include <GLES3/gl32.h>
#include <hyprgraphics/color/Color.hpp>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <hyprutils/path/Path.hpp> #include <hyprutils/path/Path.hpp>
#include <random> #include <random>
@ -908,13 +910,15 @@ static void getCMShaderUniforms(CShader& shader) {
shader.skipCM = glGetUniformLocation(shader.program, "skipCM"); shader.skipCM = glGetUniformLocation(shader.program, "skipCM");
shader.sourceTF = glGetUniformLocation(shader.program, "sourceTF"); shader.sourceTF = glGetUniformLocation(shader.program, "sourceTF");
shader.targetTF = glGetUniformLocation(shader.program, "targetTF"); 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.targetPrimaries = glGetUniformLocation(shader.program, "targetPrimaries");
shader.maxLuminance = glGetUniformLocation(shader.program, "maxLuminance"); shader.maxLuminance = glGetUniformLocation(shader.program, "maxLuminance");
shader.dstMaxLuminance = glGetUniformLocation(shader.program, "dstMaxLuminance"); shader.dstMaxLuminance = glGetUniformLocation(shader.program, "dstMaxLuminance");
shader.dstRefLuminance = glGetUniformLocation(shader.program, "dstRefLuminance"); shader.dstRefLuminance = glGetUniformLocation(shader.program, "dstRefLuminance");
shader.sdrSaturation = glGetUniformLocation(shader.program, "sdrSaturation"); shader.sdrSaturation = glGetUniformLocation(shader.program, "sdrSaturation");
shader.sdrBrightness = glGetUniformLocation(shader.program, "sdrBrightnessMultiplier"); shader.sdrBrightness = glGetUniformLocation(shader.program, "sdrBrightnessMultiplier");
shader.convertMatrix = glGetUniformLocation(shader.program, "convertMatrix");
} }
// shader has #include "rounding.glsl" // shader has #include "rounding.glsl"
@ -1437,27 +1441,26 @@ void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, const CBox& box,
scissor(nullptr); 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, void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const NColorManagement::SImageDescription& imageDescription,
const NColorManagement::SImageDescription& targetImageDescription, bool modifySDR) { const NColorManagement::SImageDescription& targetImageDescription, bool modifySDR) {
glUniform1i(shader.sourceTF, imageDescription.transferFunction); glUniform1i(shader.sourceTF, imageDescription.transferFunction);
glUniform1i(shader.targetTF, targetImageDescription.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{} ? const auto targetPrimaries = targetImageDescription.primariesNameSet || targetImageDescription.primaries == SPCPRimaries{} ?
getPrimaries(targetImageDescription.primariesNamed) : getPrimaries(targetImageDescription.primariesNamed) :
targetImageDescription.primaries; 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] = { const GLfloat glTargetPrimaries[8] = {
targetPrimaries.red.x, targetPrimaries.red.y, targetPrimaries.green.x, targetPrimaries.green.y, targetPrimaries.red.x, targetPrimaries.red.y, targetPrimaries.green.x, targetPrimaries.green.y,
targetPrimaries.blue.x, targetPrimaries.blue.y, targetPrimaries.white.x, targetPrimaries.white.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); 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; 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.maxLuminance, maxLuminance * targetImageDescription.luminances.reference / imageDescription.luminances.reference);
glUniform1f(shader.dstMaxLuminance, targetImageDescription.luminances.max > 0 ? targetImageDescription.luminances.max : 10000); 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, glUniform1f(shader.sdrBrightness,
modifySDR && m_RenderData.pMonitor->sdrBrightness > 0 && targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ? modifySDR && m_RenderData.pMonitor->sdrBrightness > 0 && targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
m_RenderData.pMonitor->sdrBrightness : m_RenderData.pMonitor->sdrBrightness :
1.0f); 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) { void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const SImageDescription& imageDescription) {

View file

@ -15,13 +15,15 @@ class CShader {
GLint skipCM = -1; GLint skipCM = -1;
GLint sourceTF = -1; GLint sourceTF = -1;
GLint targetTF = -1; GLint targetTF = -1;
GLint sourcePrimaries = -1; GLint srcTFRange = -1;
GLint dstTFRange = -1;
GLint targetPrimaries = -1; GLint targetPrimaries = -1;
GLint maxLuminance = -1; GLint maxLuminance = -1;
GLint dstMaxLuminance = -1; GLint dstMaxLuminance = -1;
GLint dstRefLuminance = -1; GLint dstRefLuminance = -1;
GLint sdrSaturation = -1; // sdr -> hdr saturation GLint sdrSaturation = -1; // sdr -> hdr saturation
GLint sdrBrightness = -1; // sdr -> hdr brightness multiplier GLint sdrBrightness = -1; // sdr -> hdr brightness multiplier
GLint convertMatrix = -1;
GLint tex = -1; GLint tex = -1;
GLint alpha = -1; GLint alpha = -1;
GLint posAttrib = -1; GLint posAttrib = -1;

View file

@ -11,7 +11,6 @@ uniform int texType; // eTextureType: 0 - rgba, 1 - rgbx, 2 - ext
// uniform int skipCM; // uniform int skipCM;
uniform int sourceTF; // eTransferFunction uniform int sourceTF; // eTransferFunction
uniform int targetTF; // eTransferFunction uniform int targetTF; // eTransferFunction
uniform mat4x2 sourcePrimaries;
uniform mat4x2 targetPrimaries; uniform mat4x2 targetPrimaries;
uniform float alpha; uniform float alpha;
@ -43,7 +42,7 @@ void main() {
discard; discard;
// this shader shouldn't be used when skipCM == 1 // 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) if (applyTint == 1)
pixColor = vec4(pixColor.rgb * tint.rgb, pixColor[3]); pixColor = vec4(pixColor.rgb * tint.rgb, pixColor[3]);

View file

@ -1,8 +1,12 @@
uniform vec2 srcTFRange;
uniform vec2 dstTFRange;
uniform float maxLuminance; uniform float maxLuminance;
uniform float dstMaxLuminance; uniform float dstMaxLuminance;
uniform float dstRefLuminance; uniform float dstRefLuminance;
uniform float sdrSaturation; uniform float sdrSaturation;
uniform float sdrBrightnessMultiplier; uniform float sdrBrightnessMultiplier;
uniform mat3 convertMatrix;
//enum eTransferFunction //enum eTransferFunction
#define CM_TRANSFER_FUNCTION_BT1886 1 #define CM_TRANSFER_FUNCTION_BT1886 1
@ -117,30 +121,8 @@ vec4 toLinear(vec4 color, int tf) {
return color; return color;
} }
vec4 toNit(vec4 color, int tf) { vec4 toNit(vec4 color, vec2 range) {
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR) color.rgb = color.rgb * (range[1] - range[0]) + range[0];
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;
}
}
return color; return color;
} }
@ -195,33 +177,13 @@ vec4 fromLinear(vec4 color, int tf) {
return color; return color;
} }
vec4 fromLinearNit(vec4 color, int tf) { vec4 fromLinearNit(vec4 color, int tf, vec2 range) {
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR) if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
color.rgb = color.rgb / SDR_MAX_LUMINANCE; color.rgb = color.rgb / SDR_MAX_LUMINANCE;
else { else {
color.rgb /= max(color.a, 0.001); color.rgb /= max(color.a, 0.001);
color.rgb = (color.rgb - range[0]) / (range[1] - range[0]);
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 = fromLinearRGB(color.rgb, tf); color.rgb = fromLinearRGB(color.rgb, tf);
color.rgb *= color.a; color.rgb *= color.a;
} }
return color; 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) { mat3 adaptWhite(vec2 src, vec2 dst) {
if (src == dst) if (src == dst)
@ -266,6 +221,13 @@ mat3 adaptWhite(vec2 src, vec2 dst) {
0.0, 0.0, 1.0 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 srcXYZ = xy2xyz(src);
vec3 dstXYZ = xy2xyz(dst); vec3 dstXYZ = xy2xyz(dst);
vec3 factors = (Bradford * dstXYZ) / (Bradford * srcXYZ); vec3 factors = (Bradford * dstXYZ) / (Bradford * srcXYZ);
@ -287,21 +249,37 @@ const mat3 BT2020toLMS = mat3(
-0.1922, 1.1004, 0.0755, -0.1922, 1.1004, 0.0755,
0.0070, 0.0749, 0.8434 0.0070, 0.0749, 0.8434
); );
const mat3 LMStoBT2020 = inverse(BT2020toLMS); //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( // const mat3 ICtCpPQ = transpose(mat3(
2048.0, 2048.0, 0.0, // 2048.0, 2048.0, 0.0,
6610.0, -13613.0, 7003.0, // 6610.0, -13613.0, 7003.0,
17933.0, -17390.0, -543.0 // 17933.0, -17390.0, -543.0
) / 4096.0); // ) / 4096.0);
const mat3 ICtCpPQInv = inverse(ICtCpPQ); 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
);
const mat3 ICtCpHLG = transpose(mat3( // unused for now
2048.0, 2048.0, 0.0, // const mat3 ICtCpHLG = transpose(mat3(
3625.0, -7465.0, 3840.0, // 2048.0, 2048.0, 0.0,
9500.0, -9212.0, -288.0 // 3625.0, -7465.0, 3840.0,
) / 4096.0); // 9500.0, -9212.0, -288.0
const mat3 ICtCpHLGInv = inverse(ICtCpHLG); // ) / 4096.0);
// const mat3 ICtCpHLGInv = inverse(ICtCpHLG);
vec4 tonemap(vec4 color, mat3 dstXYZ) { vec4 tonemap(vec4 color, mat3 dstXYZ) {
if (maxLuminance < dstMaxLuminance * 1.01) 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]); 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 /= max(pixColor.a, 0.001);
pixColor.rgb = toLinearRGB(pixColor.rgb, srcTF); pixColor.rgb = toLinearRGB(pixColor.rgb, srcTF);
mat3 srcxyz = primaries2xyz(srcPrimaries); pixColor.rgb = convertMatrix * pixColor.rgb;
mat3 dstxyz; pixColor = toNit(pixColor, srcTFRange);
if (srcPrimaries == dstPrimaries)
dstxyz = srcxyz;
else {
dstxyz = primaries2xyz(dstPrimaries);
pixColor = convertPrimaries(pixColor, srcxyz, srcPrimaries[3], dstxyz, dstPrimaries[3]);
}
pixColor = toNit(pixColor, srcTF);
pixColor.rgb *= pixColor.a; pixColor.rgb *= pixColor.a;
mat3 dstxyz = primaries2xyz(dstPrimaries);
pixColor = tonemap(pixColor, dstxyz); 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) { 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 /= pixColor.a;
pixColor.rgb *= sdrBrightnessMultiplier; pixColor.rgb *= sdrBrightnessMultiplier;
pixColor.rgb *= pixColor.a; pixColor.rgb *= pixColor.a;

View file

@ -11,8 +11,6 @@ uniform float brightness;
uniform int skipCM; uniform int skipCM;
uniform int sourceTF; // eTransferFunction uniform int sourceTF; // eTransferFunction
uniform int targetTF; // eTransferFunction uniform int targetTF; // eTransferFunction
uniform mat4x2 sourcePrimaries;
uniform mat4x2 targetPrimaries;
#include "CM.glsl" #include "CM.glsl"
@ -29,17 +27,9 @@ void main() {
if (sourceTF == CM_TRANSFER_FUNCTION_ST2084_PQ) { if (sourceTF == CM_TRANSFER_FUNCTION_ST2084_PQ) {
pixColor.rgb /= sdrBrightnessMultiplier; pixColor.rgb /= sdrBrightnessMultiplier;
} }
pixColor.rgb = toLinearRGB(pixColor.rgb, sourceTF); pixColor.rgb = convertMatrix * toLinearRGB(pixColor.rgb, sourceTF);
mat3 srcxyz = primaries2xyz(sourcePrimaries); pixColor = toNit(pixColor, srcTFRange);
mat3 dstxyz; pixColor = fromLinearNit(pixColor, targetTF, dstTFRange);
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);
} }
// contrast // contrast

View file

@ -7,7 +7,6 @@ in vec2 v_texcoord;
uniform int skipCM; uniform int skipCM;
uniform int sourceTF; // eTransferFunction uniform int sourceTF; // eTransferFunction
uniform int targetTF; // eTransferFunction uniform int targetTF; // eTransferFunction
uniform mat4x2 sourcePrimaries;
uniform mat4x2 targetPrimaries; uniform mat4x2 targetPrimaries;
uniform vec2 fullSizeUntransformed; uniform vec2 fullSizeUntransformed;
@ -175,7 +174,7 @@ void main() {
pixColor.rgb *= pixColor[3]; pixColor.rgb *= pixColor[3];
if (skipCM == 0) if (skipCM == 0)
pixColor = doColorManagement(pixColor, sourceTF, sourcePrimaries, targetTF, targetPrimaries); pixColor = doColorManagement(pixColor, sourceTF, targetTF, targetPrimaries);
pixColor *= alpha * additionalAlpha; pixColor *= alpha * additionalAlpha;

View file

@ -8,7 +8,6 @@ in vec2 v_texcoord;
uniform int skipCM; uniform int skipCM;
uniform int sourceTF; // eTransferFunction uniform int sourceTF; // eTransferFunction
uniform int targetTF; // eTransferFunction uniform int targetTF; // eTransferFunction
uniform mat4x2 sourcePrimaries;
uniform mat4x2 targetPrimaries; uniform mat4x2 targetPrimaries;
uniform vec2 topLeft; uniform vec2 topLeft;
@ -94,7 +93,7 @@ void main() {
pixColor.rgb *= pixColor[3]; pixColor.rgb *= pixColor[3];
if (skipCM == 0) if (skipCM == 0)
pixColor = doColorManagement(pixColor, sourceTF, sourcePrimaries, targetTF, targetPrimaries); pixColor = doColorManagement(pixColor, sourceTF, targetTF, targetPrimaries);
fragColor = pixColor; fragColor = pixColor;
} }