summaryrefslogtreecommitdiff
path: root/src/render/OpenGL.cpp
diff options
context:
space:
mode:
authorUjinT34 <41110182+UjinT34@users.noreply.github.com>2025-03-14 02:15:18 +0300
committerGitHub <noreply@github.com>2025-03-14 00:15:18 +0100
commit8c97cb7858e5d6c35d1a055930904346fb4248db (patch)
tree87d7e30393f9177d035183f273be54f03b9451d5 /src/render/OpenGL.cpp
parente86d3a14e46d19d8a47f8ceb6410546715d45f10 (diff)
renderer: add simple color management (#9506)
Adds proper color management and transformations for CM surfaces.
Diffstat (limited to 'src/render/OpenGL.cpp')
-rw-r--r--src/render/OpenGL.cpp98
1 files changed, 95 insertions, 3 deletions
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 17224523..a8a38bac 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -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);