mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-05 22:51:58 -07:00
renderer: add simple color management (#9506)
Adds proper color management and transformations for CM surfaces.
This commit is contained in:
@@ -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);
|
||||
|
Reference in New Issue
Block a user