mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-05-15 08:10:36 +01:00
cm: Use precomputed primaries conversion (#9814)
This commit is contained in:
parent
94bc132084
commit
49974d5e34
10 changed files with 164 additions and 136 deletions
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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();
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
Loading…
Reference in a new issue