Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/protocols/types/ColorManagement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

#define SDR_MIN_LUMINANCE 0.2
#define SDR_MAX_LUMINANCE 80.0
#define SDR_REF_LUMINANCE 80.0
#define HDR_MIN_LUMINANCE 0.005
#define HDR_MAX_LUMINANCE 10000.0
#define HDR_REF_LUMINANCE 203.0
#define HLG_MAX_LUMINANCE 1000.0

namespace NColorManagement {
Expand Down Expand Up @@ -228,6 +230,25 @@ namespace NColorManagement {
}
};

float getTFRefLuminance(int sdrRefLuminance = -1) const {
switch (transferFunction) {
case CM_TRANSFER_FUNCTION_EXT_LINEAR:
case CM_TRANSFER_FUNCTION_ST2084_PQ:
case CM_TRANSFER_FUNCTION_HLG: return HDR_REF_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 sdrRefLuminance >= 0 ? sdrRefLuminance : SDR_REF_LUMINANCE;
}
};

uint32_t findId() const;
uint32_t getId() const;
uint32_t updateId();
Expand Down
13 changes: 8 additions & 5 deletions src/render/OpenGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,7 @@ static void getCMShaderUniforms(SShader& shader) {
shader.uniformLocations[SHADER_DST_TF_RANGE] = glGetUniformLocation(shader.program, "dstTFRange");
shader.uniformLocations[SHADER_TARGET_PRIMARIES] = glGetUniformLocation(shader.program, "targetPrimaries");
shader.uniformLocations[SHADER_MAX_LUMINANCE] = glGetUniformLocation(shader.program, "maxLuminance");
shader.uniformLocations[SHADER_SRC_REF_LUMINANCE] = glGetUniformLocation(shader.program, "srcRefLuminance");
shader.uniformLocations[SHADER_DST_MAX_LUMINANCE] = glGetUniformLocation(shader.program, "dstMaxLuminance");
shader.uniformLocations[SHADER_DST_REF_LUMINANCE] = glGetUniformLocation(shader.program, "dstRefLuminance");
shader.uniformLocations[SHADER_SDR_SATURATION] = glGetUniformLocation(shader.program, "sdrSaturation");
Expand Down Expand Up @@ -1589,10 +1590,12 @@ void CHyprOpenGLImpl::passCMUniforms(SShader& shader, const NColorManagement::SI
shader.setUniformFloat2(SHADER_DST_TF_RANGE, targetImageDescription.getTFMinLuminance(needsSDRmod ? sdrMinLuminance : -1),
targetImageDescription.getTFMaxLuminance(needsSDRmod ? sdrMaxLuminance : -1));

shader.setUniformFloat(SHADER_SRC_REF_LUMINANCE, imageDescription.getTFRefLuminance(-1));
shader.setUniformFloat(SHADER_DST_REF_LUMINANCE, targetImageDescription.getTFRefLuminance(-1));

const float maxLuminance = imageDescription.luminances.max > 0 ? imageDescription.luminances.max : imageDescription.luminances.reference;
shader.setUniformFloat(SHADER_MAX_LUMINANCE, maxLuminance * targetImageDescription.luminances.reference / imageDescription.luminances.reference);
shader.setUniformFloat(SHADER_DST_MAX_LUMINANCE, targetImageDescription.luminances.max > 0 ? targetImageDescription.luminances.max : 10000);
shader.setUniformFloat(SHADER_DST_REF_LUMINANCE, targetImageDescription.luminances.reference);
shader.setUniformFloat(SHADER_SDR_SATURATION, needsSDRmod && m_renderData.pMonitor->m_sdrSaturation > 0 ? m_renderData.pMonitor->m_sdrSaturation : 1.0f);
shader.setUniformFloat(SHADER_SDR_BRIGHTNESS, needsSDRmod && m_renderData.pMonitor->m_sdrBrightness > 0 ? m_renderData.pMonitor->m_sdrBrightness : 1.0f);
const auto cacheKey = std::make_pair(imageDescription.getId(), targetImageDescription.getId());
Expand Down Expand Up @@ -1709,10 +1712,10 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, c
shader->setUniformInt(SHADER_TEX_TYPE, texType);
if (data.cmBackToSRGB) {
// revert luma changes to avoid black screenshots.
// this will likely not be 1:1, and might cause screenshots to be too bright, but it's better than pitch black.
imageDescription.luminances = {};
static auto PSDREOTF = CConfigValue<Hyprlang::INT>("render:cm_sdr_eotf");
auto chosenSdrEotf = *PSDREOTF > 0 ? NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 : NColorManagement::CM_TRANSFER_FUNCTION_SRGB;
imageDescription.luminances = {
.min = imageDescription.getTFMinLuminance(-1), .max = imageDescription.getTFMaxLuminance(-1), .reference = imageDescription.getTFRefLuminance(-1)};
static auto PSDREOTF = CConfigValue<Hyprlang::INT>("render:cm_sdr_eotf");
auto chosenSdrEotf = *PSDREOTF > 0 ? NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 : NColorManagement::CM_TRANSFER_FUNCTION_SRGB;
passCMUniforms(*shader, imageDescription, NColorManagement::SImageDescription{.transferFunction = chosenSdrEotf}, true, -1, -1);
} else
passCMUniforms(*shader, imageDescription);
Expand Down
1 change: 1 addition & 0 deletions src/render/Shader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum eShaderUniform : uint8_t {
SHADER_DST_TF_RANGE,
SHADER_TARGET_PRIMARIES,
SHADER_MAX_LUMINANCE,
SHADER_SRC_REF_LUMINANCE,
SHADER_DST_MAX_LUMINANCE,
SHADER_DST_REF_LUMINANCE,
SHADER_SDR_SATURATION,
Expand Down
27 changes: 12 additions & 15 deletions src/render/shaders/glsl/CM.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ uniform vec2 srcTFRange;
uniform vec2 dstTFRange;

uniform float maxLuminance;
uniform float srcRefLuminance;
uniform float dstMaxLuminance;
uniform float dstRefLuminance;
uniform float sdrSaturation;
Expand Down Expand Up @@ -387,24 +388,20 @@ vec4 tonemap(vec4 color, mat3 dstXYZ) {
PQ_INV_M1
) * HDR_MAX_LUMINANCE;

float srcScale = maxLuminance / dstRefLuminance;
float dstScale = dstMaxLuminance / dstRefLuminance;
float linearPart = min(luminance, dstRefLuminance);
float luminanceAboveRef = max(luminance - dstRefLuminance, 0.0);
float maxExcessLuminance = max(maxLuminance - dstRefLuminance, 1.0);
float shoulder = log((luminanceAboveRef / maxExcessLuminance + 1.0) * (M_E - 1.0));
float mappedHigh = shoulder * (dstMaxLuminance - dstRefLuminance);
float newLum = clamp(linearPart + mappedHigh, 0.0, dstMaxLuminance);

float minScale = min(srcScale, 1.5);
float dimming = 1.0 / clamp(minScale / dstScale, 1.0, minScale);
float refLuminance = dstRefLuminance * dimming;
float newIpq = tfPQ(vec3(newLum / HDR_MAX_LUMINANCE)).r;
ICtCp[0] = clamp(newIpq, 0.0, 1.0);

float low = min(luminance * dimming, refLuminance);
float highlight = clamp((luminance / dstRefLuminance - 1.0) / (srcScale - 1.0), 0.0, 1.0);
float high = log(highlight * (M_E - 1.0) + 1.0) * (dstMaxLuminance - refLuminance);
luminance = low + high;
// scale src to dst reference
float refScale = dstRefLuminance / srcRefLuminance;

E = pow(clamp(ICtCp[0], 0.0, 1.0), PQ_M1);
ICtCp[0] = pow(
(PQ_C1 + PQ_C2 * E) / (1.0 + PQ_C3 * E),
PQ_M2
) / HDR_MAX_LUMINANCE;
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 * refScale, color[3]);
}

vec4 doColorManagement(vec4 pixColor, int srcTF, int dstTF, mat4x2 dstPrimaries) {
Expand Down
2 changes: 1 addition & 1 deletion src/render/shaders/glsl/blurprepare.frag
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void main() {
pixColor.rgb /= sdrBrightnessMultiplier;
}
pixColor.rgb = convertMatrix * toLinearRGB(pixColor.rgb, sourceTF);
pixColor = toNit(pixColor, srcTFRange);
pixColor = toNit(pixColor, vec2(srcTFRange[0], srcRefLuminance));
pixColor = fromLinearNit(pixColor, targetTF, dstTFRange);
}

Expand Down
Loading