renderer: add simple color management (#9506)

Adds proper color management and transformations for CM surfaces.
This commit is contained in:
UjinT34
2025-03-14 02:15:18 +03:00
committed by GitHub
parent e86d3a14e4
commit 8c97cb7858
14 changed files with 823 additions and 179 deletions

View File

@@ -9,6 +9,7 @@
#include "../desktop/LayerSurface.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../protocols/ColorManagement.hpp"
#include "../managers/HookSystemManager.hpp"
#include "../managers/input/InputManager.hpp"
#include "pass/TexPassElement.hpp"
@@ -20,6 +21,7 @@
#include <gbm.h>
#include <filesystem>
using namespace Hyprutils::OS;
using namespace NColorManagement;
const std::vector<const char*> ASSET_PATHS = {
#ifdef DATAROOTDIR
@@ -866,6 +868,39 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shQUAD.roundingPower = glGetUniformLocation(prog, "roundingPower");
#ifndef GLES2
prog = createProgram(TEXVERTSRC320, TEXFRAGSRCCM);
m_RenderData.pCurrentMonData->m_shCM.program = prog;
m_RenderData.pCurrentMonData->m_shCM.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shCM.tex = glGetUniformLocation(prog, "tex");
m_RenderData.pCurrentMonData->m_shCM.texType = glGetUniformLocation(prog, "texType");
m_RenderData.pCurrentMonData->m_shCM.skipCM = glGetUniformLocation(prog, "skipCM");
m_RenderData.pCurrentMonData->m_shCM.sourceTF = glGetUniformLocation(prog, "sourceTF");
m_RenderData.pCurrentMonData->m_shCM.targetTF = glGetUniformLocation(prog, "targetTF");
m_RenderData.pCurrentMonData->m_shCM.sourcePrimaries = glGetUniformLocation(prog, "sourcePrimaries");
m_RenderData.pCurrentMonData->m_shCM.targetPrimaries = glGetUniformLocation(prog, "targetPrimaries");
m_RenderData.pCurrentMonData->m_shCM.maxLuminance = glGetUniformLocation(prog, "maxLuminance");
m_RenderData.pCurrentMonData->m_shCM.dstMaxLuminance = glGetUniformLocation(prog, "dstMaxLuminance");
m_RenderData.pCurrentMonData->m_shCM.dstRefLuminance = glGetUniformLocation(prog, "dstRefLuminance");
m_RenderData.pCurrentMonData->m_shCM.sdrSaturation = glGetUniformLocation(prog, "sdrSaturation");
m_RenderData.pCurrentMonData->m_shCM.sdrBrightness = glGetUniformLocation(prog, "sdrBrightnessMultiplier");
m_RenderData.pCurrentMonData->m_shCM.alphaMatte = glGetUniformLocation(prog, "texMatte");
m_RenderData.pCurrentMonData->m_shCM.alpha = glGetUniformLocation(prog, "alpha");
m_RenderData.pCurrentMonData->m_shCM.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shCM.matteTexAttrib = glGetAttribLocation(prog, "texcoordMatte");
m_RenderData.pCurrentMonData->m_shCM.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shCM.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_RenderData.pCurrentMonData->m_shCM.discardAlpha = glGetUniformLocation(prog, "discardAlpha");
m_RenderData.pCurrentMonData->m_shCM.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue");
m_RenderData.pCurrentMonData->m_shCM.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shCM.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shCM.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shCM.roundingPower = glGetUniformLocation(prog, "roundingPower");
m_RenderData.pCurrentMonData->m_shCM.applyTint = glGetUniformLocation(prog, "applyTint");
m_RenderData.pCurrentMonData->m_shCM.tint = glGetUniformLocation(prog, "tint");
m_RenderData.pCurrentMonData->m_shCM.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte");
#endif
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA);
m_RenderData.pCurrentMonData->m_shRGBA.program = prog;
m_RenderData.pCurrentMonData->m_shRGBA.proj = glGetUniformLocation(prog, "proj");
@@ -1280,7 +1315,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
CBox newBox = box;
m_RenderData.renderModif.applyToBox(newBox);
static auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
static auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
// get the needed transform for this texture
const bool TRANSFORMS_MATCH = wlTransformToHyprutils(m_RenderData.pMonitor->transform) == tex->m_eTransform; // FIXME: combine them properly!!!
@@ -1304,6 +1340,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
const bool CRASHING = m_bApplyFinalShader && g_pHyprRenderer->m_bCrashingInProgress;
auto texType = tex->m_iType;
if (CRASHING) {
shader = &m_RenderData.pCurrentMonData->m_shGLITCH;
usingFinalShader = true;
@@ -1316,16 +1354,27 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
usingFinalShader = true;
} else {
switch (tex->m_iType) {
#ifdef GLES2
case TEXTURE_RGBA: shader = &m_RenderData.pCurrentMonData->m_shRGBA; break;
case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shRGBX; break;
case TEXTURE_EXTERNAL: shader = &m_RenderData.pCurrentMonData->m_shEXT; break;
#else
case TEXTURE_RGBA:
case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shCM; break;
#endif
case TEXTURE_EXTERNAL: shader = &m_RenderData.pCurrentMonData->m_shEXT; break; // might be unused
default: RASSERT(false, "tex->m_iTarget unsupported!");
}
}
}
if (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.RGBX.valueOrDefault())
if (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.RGBX.valueOrDefault()) {
#ifdef GLES2
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
#else
shader = &m_RenderData.pCurrentMonData->m_shCM;
#endif
texType = TEXTURE_RGBX;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex->m_iTarget, tex->m_iTexID);
@@ -1350,6 +1399,49 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif
glUniform1i(shader->tex, 0);
#ifndef GLES2
if (!usingFinalShader && (texType == TEXTURE_RGBA || texType == TEXTURE_RGBX)) {
const bool skipCM = *PPASS && m_RenderData.pMonitor->activeWorkspace && m_RenderData.pMonitor->activeWorkspace->m_bHasFullscreenWindow &&
m_RenderData.pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
glUniform1i(shader->texType, texType);
glUniform1i(shader->skipCM, skipCM);
if (!skipCM) {
const auto imageDescription =
m_RenderData.surface.valid() && m_RenderData.surface->colorManagement.valid() ? m_RenderData.surface->colorManagement->imageDescription() : SImageDescription{};
glUniform1i(shader->sourceTF, imageDescription.transferFunction);
glUniform1i(shader->targetTF, m_RenderData.pMonitor->imageDescription.transferFunction);
const auto sourcePrimaries =
imageDescription.primariesNameSet || imageDescription.primaries == SPCPRimaries{} ? getPrimaries(imageDescription.primariesNamed) : imageDescription.primaries;
const auto targetPrimaries = m_RenderData.pMonitor->imageDescription.primariesNameSet || m_RenderData.pMonitor->imageDescription.primaries == SPCPRimaries{} ?
getPrimaries(m_RenderData.pMonitor->imageDescription.primariesNamed) :
m_RenderData.pMonitor->imageDescription.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);
const float maxLuminance = imageDescription.luminances.max > 0 ? imageDescription.luminances.max : imageDescription.luminances.reference;
glUniform1f(shader->maxLuminance, maxLuminance * m_RenderData.pMonitor->imageDescription.luminances.reference / imageDescription.luminances.reference);
glUniform1f(shader->dstMaxLuminance, m_RenderData.pMonitor->imageDescription.luminances.max > 0 ? m_RenderData.pMonitor->imageDescription.luminances.max : 10000);
glUniform1f(shader->dstRefLuminance, m_RenderData.pMonitor->imageDescription.luminances.reference);
glUniform1f(shader->sdrSaturation,
m_RenderData.pMonitor->sdrSaturation > 0 && m_RenderData.pMonitor->imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
m_RenderData.pMonitor->sdrSaturation :
1.0f);
glUniform1f(shader->sdrBrightness,
m_RenderData.pMonitor->sdrBrightness > 0 && m_RenderData.pMonitor->imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
m_RenderData.pMonitor->sdrBrightness :
1.0f);
}
}
#endif
if ((usingFinalShader && *PDT == 0) || CRASHING) {
glUniform1f(shader->time, m_tGlobalTimer.getSeconds() - shader->initialTime);