summaryrefslogtreecommitdiff
path: root/src/render
diff options
context:
space:
mode:
authorUjinT34 <41110182+UjinT34@users.noreply.github.com>2026-04-16 21:19:25 +0300
committerGitHub <noreply@github.com>2026-04-16 19:19:25 +0100
commit66ea2e2c9ed4e9257521e6706fbd21feb7e3cc5b (patch)
tree6c0c9842245917e9828874263cd11d6f556a0a48 /src/render
parent4cce7f60a9c8772d18ffb43cb74aa227ab4b3bc4 (diff)
renderer: Various CM fixes, part 8 of refactors (#13860)
Part 8 of Ujin's refactors.
Diffstat (limited to 'src/render')
-rw-r--r--src/render/Framebuffer.cpp2
-rw-r--r--src/render/GLRenderer.cpp3
-rw-r--r--src/render/OpenGL.cpp68
-rw-r--r--src/render/OpenGL.hpp1
-rw-r--r--src/render/Renderer.cpp105
-rw-r--r--src/render/Renderer.hpp5
-rw-r--r--src/render/gl/GLFramebuffer.cpp2
-rw-r--r--src/render/gl/GLTexture.cpp2
-rw-r--r--src/render/shaders/glsl/blur1.glsl12
-rw-r--r--src/render/shaders/glsl/cm_helpers.glsl14
-rw-r--r--src/render/shaders/glsl/gain.glsl3
-rw-r--r--src/render/shaders/glsl/surface.frag5
-rw-r--r--src/render/shaders/glsl/tonemap.glsl6
13 files changed, 139 insertions, 89 deletions
diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp
index 47a466c1..4b8d392e 100644
--- a/src/render/Framebuffer.cpp
+++ b/src/render/Framebuffer.cpp
@@ -62,4 +62,6 @@ void IFramebuffer::setImageDescription(NColorManagement::PImageDescription desc)
m_imageDescription = desc;
if (m_tex)
m_tex->m_imageDescription = desc;
+ else
+ Log::logger->log(Log::TRACE, "CM: FIXME no framebuffer texture");
}
diff --git a/src/render/GLRenderer.cpp b/src/render/GLRenderer.cpp
index 77fffd25..aefdc67a 100644
--- a/src/render/GLRenderer.cpp
+++ b/src/render/GLRenderer.cpp
@@ -199,7 +199,7 @@ SP<ITexture> CHyprGLRenderer::createTexture(const int width, const int height, u
g_pHyprOpenGL->makeEGLCurrent();
SP<ITexture> tex = makeShared<CGLTexture>();
- tex->allocate({width, height});
+ tex->allocate({width, height}, DRM_FORMAT_ARGB8888); // FIXME assume DRM_FORMAT_ARGB8888
tex->m_size = {width, height};
// copy the data to an OpenGL texture we have
@@ -237,6 +237,7 @@ SP<ITexture> CHyprGLRenderer::createTexture(cairo_surface_t* cairo) {
if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) {
tex->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE);
tex->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED);
+ tex->m_drmFormat = DRM_FORMAT_ARGB8888;
}
glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_size.x, tex->m_size.y, 0, glFormat, glType, DATA);
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 8ae52c8e..358e4702 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -782,6 +782,7 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, SP<IFra
void CHyprOpenGLImpl::end() {
static auto PZOOMDISABLEAA = CConfigValue<Hyprlang::INT>("cursor:zoom_disable_aa");
+ static auto PFPINVALIDATE = CConfigValue<Hyprlang::INT>("debug:invalidate_fp16");
auto& m_renderData = g_pHyprRenderer->m_renderData;
const auto PMONITOR = m_renderData.pMonitor;
TRACY_GPU_ZONE("RenderEnd");
@@ -839,7 +840,7 @@ void CHyprOpenGLImpl::end() {
g_pHyprRenderer->popMonitorTransformEnabled();
// invalidate our render FBs to signal to the driver we don't need them anymore
- if (!g_pHyprRenderer->m_renderData.pMonitor->useFP16()) { // FIXME wtf?
+ if (!g_pHyprRenderer->m_renderData.pMonitor->useFP16() || *PFPINVALIDATE == 1 || (*PFPINVALIDATE == 2 && !g_pHyprRenderer->isNvidia())) { // FIXME wtf?
g_pHyprRenderer->m_renderData.pMonitor->resources()->forEachUnusedFB(
[](const auto& fb) {
fb->bind();
@@ -1194,6 +1195,11 @@ void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const PImageDescription
g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance);
}
+void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const PImageDescription imageDescription, const SCMSettings& settings) {
+ passCMUniforms(shader, imageDescription, g_pHyprRenderer->workBufferImageDescription(), true, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance,
+ g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance, settings);
+}
+
WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
static const auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
static const auto PCURSORTIMEOUT = CConfigValue<Hyprlang::FLOAT>("cursor:inactive_timeout");
@@ -1268,7 +1274,6 @@ WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
}
WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STextureRenderData& data, eTextureType texType, const CBox& newBox) {
- static const auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
static const auto PENABLECM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
static auto PBLEND = CConfigValue<Hyprlang::INT>("render:use_shader_blur_blend");
@@ -1291,10 +1296,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
if (data.finalMonitorCM || (g_pHyprRenderer->m_renderData.currentWindow && g_pHyprRenderer->m_renderData.currentWindow->m_ruleApplicator->RGBX().valueOrDefault()))
shaderFeatures &= ~SH_FEAT_RGBA;
- const auto surface = g_pHyprRenderer->m_renderData.surface;
- const bool isHDRSurface = surface.valid() && surface->m_colorManagement.valid() ? surface->m_colorManagement->isHDR() : false;
- const bool canPassHDRSurface = isHDRSurface && !surface->m_colorManagement->isWindowsScRGB(); // windows scRGB requires CM shader
-
+ const auto surface = g_pHyprRenderer->m_renderData.surface;
const auto WORK_BUFFER_IMAGE_DESCRIPTION = g_pHyprRenderer->workBufferImageDescription();
// chosenSdrEotf contains the valid eotf for this display
@@ -1304,8 +1306,8 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
return tex->m_imageDescription;
// if valid CM surface, use that as a source
- if (g_pHyprRenderer->m_renderData.surface.valid() && g_pHyprRenderer->m_renderData.surface->m_colorManagement.valid())
- return CImageDescription::from(g_pHyprRenderer->m_renderData.surface->m_colorManagement->imageDescription());
+ if (surface.valid() && surface->m_colorManagement.valid())
+ return CImageDescription::from(surface->m_colorManagement->imageDescription());
if (data.cmBackToSRGB)
return g_pHyprRenderer->m_renderData.pMonitor->m_imageDescription;
@@ -1316,7 +1318,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
return WORK_BUFFER_IMAGE_DESCRIPTION;
// otherwise, default
- return DEFAULT_IMAGE_DESCRIPTION;
+ return getDefaultImageDescription();
}();
const auto TARGET_IMAGE_DESCRIPTION = [&] {
@@ -1325,7 +1327,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
// if we are CM'ing back, use default sRGB
if (data.cmBackToSRGB)
- return DEFAULT_IMAGE_DESCRIPTION;
+ return getDefaultImageDescription();
// for final CM, use the target description
if (data.finalMonitorCM)
@@ -1341,15 +1343,13 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
if (data.discardActive)
shaderFeatures |= SH_FEAT_DISCARD;
- const bool CANT_CHECK_CM_EQUALITY =
- data.cmBackToSRGB || data.finalMonitorCM || (!g_pHyprRenderer->m_renderData.surface || !g_pHyprRenderer->m_renderData.surface->m_colorManagement);
+ const bool skipCM = !*PENABLECM || !m_cmSupported /* CM unsupported or disabled */
+ || g_pHyprRenderer->m_renderData.pMonitor->doesNoShaderCM() /* no shader needed */
+ || !SOURCE_IMAGE_DESCRIPTION->needsCM(TARGET_IMAGE_DESCRIPTION) /* Source and target have matching image descriptions */
+ ;
- const bool skipCM = !*PENABLECM || !m_cmSupported /* CM unsupported or disabled */
- || g_pHyprRenderer->m_renderData.pMonitor->doesNoShaderCM() /* no shader needed */
- || (SOURCE_IMAGE_DESCRIPTION->id() == TARGET_IMAGE_DESCRIPTION->id() && !CANT_CHECK_CM_EQUALITY) /* Source and target have the same image description */
- || (((*PPASS && canPassHDRSurface) ||
- (*PPASS == 1 && !isHDRSurface && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR_EDID)) &&
- m_renderData.pMonitor->inFullscreenMode()) /* Fullscreen window with pass cm enabled */;
+ if (g_pHyprRenderer->m_renderData.pMonitor->needsACopyFB())
+ Log::logger->log(Log::TRACE, "CM: render to FB skip={} {} -> {}", skipCM, SOURCE_IMAGE_DESCRIPTION->value(), TARGET_IMAGE_DESCRIPTION->value());
if (data.allowDim && g_pHyprRenderer->m_renderData.currentWindow &&
(g_pHyprRenderer->m_renderData.currentWindow->m_notRespondingTint->value() > 0 || g_pHyprRenderer->m_renderData.currentWindow->m_dimPercent->value() > 0))
@@ -1359,9 +1359,9 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
shaderFeatures |= SH_FEAT_ROUNDING;
if (!skipCM) {
- const auto settings = g_pHyprRenderer->getCMSettings(SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION,
- g_pHyprRenderer->m_renderData.surface.valid() ? g_pHyprRenderer->m_renderData.surface.lock() : nullptr, true,
- g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance);
+ const auto settings =
+ g_pHyprRenderer->getCMSettings(SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION, surface.valid() ? surface.lock() : nullptr, true,
+ g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance, true);
shaderFeatures |= SH_FEAT_CM;
@@ -1670,10 +1670,10 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
WP<CShader> shader;
// From FB to sRGB
- const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
+ const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
if (!skipCM) {
shader = useShader(getShaderVariant(SH_FRAG_BLURPREPARE, SH_FEAT_CM));
- passCMUniforms(shader, g_pHyprRenderer->workBufferImageDescription(), DEFAULT_IMAGE_DESCRIPTION);
+ passCMUniforms(shader, g_pHyprRenderer->workBufferImageDescription(), getDefaultImageDescription());
shader->setUniformFloat(SHADER_SDR_SATURATION,
m_renderData.pMonitor->m_sdrSaturation > 0 &&
g_pHyprRenderer->workBufferImageDescription()->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
@@ -1790,10 +1790,10 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
currentTex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// From FB to sRGB
- const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
+ const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
if (!skipCM) {
shader = useShader(getShaderVariant(SH_FRAG_BLURFINISH, SH_FEAT_CM));
- passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION, g_pHyprRenderer->workBufferImageDescription());
+ passCMUniforms(shader, getDefaultImageDescription(), g_pHyprRenderer->workBufferImageDescription());
shader->setUniformFloat(SHADER_SDR_SATURATION,
m_renderData.pMonitor->m_sdrSaturation > 0 &&
g_pHyprRenderer->workBufferImageDescription()->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
@@ -2074,10 +2074,10 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const Config::CGradientValue
WP<CShader> shader;
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
- const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
+ const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
if (!skipCM) {
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD) | globalFeatures()));
- passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
+ passCMUniforms(shader, getDefaultImageDescription());
} else
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | globalFeatures()));
@@ -2159,10 +2159,10 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const Config::CGradientValue
WP<CShader> shader;
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
- const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
+ const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
if (!skipCM) {
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD) | globalFeatures()));
- passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
+ passCMUniforms(shader, getDefaultImageDescription());
} else
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | globalFeatures()));
@@ -2237,10 +2237,10 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
blend(true);
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
- const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
+ const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
auto shader = useShader(getShaderVariant(SH_FRAG_SHADOW, skipCM ? 0 : SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD) | globalFeatures()));
if (!skipCM)
- passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
+ passCMUniforms(shader, getDefaultImageDescription());
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
shader->setUniformFloat4(SHADER_COLOR, col.r, col.g, col.b, col.a * a);
@@ -2301,10 +2301,10 @@ void CHyprOpenGLImpl::renderInnerGlow(const CBox& box, int round, float rounding
blend(true);
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
- const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
+ const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
auto shader = useShader(getShaderVariant(SH_FRAG_INNER_GLOW, skipCM ? 0 : SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD)));
if (!skipCM)
- passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
+ passCMUniforms(shader, getDefaultImageDescription());
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
shader->setUniformFloat4(SHADER_COLOR, col.r, col.g, col.b, col.a * a);
@@ -2353,6 +2353,8 @@ void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
}
auto guard = g_pHyprRenderer->bindTempFB(g_pHyprRenderer->m_renderData.pMonitor->resources()->mirrorFB());
+ Log::logger->log(Log::TRACE, "CM: saveBufferForMirror {} -> {}", TEX->m_imageDescription->value(), g_pHyprRenderer->m_renderData.currentFB->imageDescription()->value());
+
blend(false);
renderTexture(TEX, box,
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 78518ffe..82b8f054 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -339,6 +339,7 @@ namespace Render::GL {
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
+ void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const SCMSettings& settings);
void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index ba82fa15..df1106b0 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -53,6 +53,7 @@
#include "Texture.hpp"
#include "./pass/PreBlurElement.hpp"
#include "types.hpp"
+#include <hyprgraphics/color/Color.hpp>
#include <hyprutils/math/Mat3x3.hpp>
#include <hyprutils/math/Region.hpp>
#include <hyprutils/math/Vector2D.hpp>
@@ -1514,7 +1515,7 @@ SP<ITexture> IHyprRenderer::renderText(const std::string& text, CHyprColor col,
cairo_surface_flush(CAIROSURFACE);
- auto tex = createTexture(cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE), cairo_image_surface_get_data(CAIROSURFACE));
+ auto tex = createTexture(CAIROSURFACE);
cairo_destroy(CAIRO);
cairo_surface_destroy(CAIROSURFACE);
@@ -1779,10 +1780,10 @@ void IHyprRenderer::clearCMSettingsCache() {
}
SCMSettings IHyprRenderer::getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
- SP<CWLSurfaceResource> surface, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) {
+ SP<CWLSurfaceResource> surface, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance, bool shouldUseSurface) {
const auto srcId = imageDescription->id();
const auto dstId = targetImageDescription->id();
- void* sPtr = m_renderData.surface.get();
+ void* sPtr = shouldUseSurface ? m_renderData.surface.get() : nullptr;
for (auto const& entry : m_cmSettingsCache) {
if (entry.srcDescId == srcId && entry.dstDescId == dstId && entry.surfacePtr == sPtr && entry.modifySDR == modifySDR && entry.sdrMinLuminance == sdrMinLuminance &&
@@ -1793,7 +1794,8 @@ SCMSettings IHyprRenderer::getCMSettings(const NColorManagement::PImageDescripti
const auto sdrEOTF = NTransferFunction::fromConfig();
NColorManagement::eTransferFunction srcTF;
- if (m_renderData.surface.valid()) {
+ if (shouldUseSurface && m_renderData.surface.valid() &&
+ (imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_GAMMA22 || imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_SRGB)) {
if (m_renderData.surface->m_colorManagement.valid()) {
if (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && imageDescription->value().transferFunction == NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB)
srcTF = NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22;
@@ -1842,7 +1844,15 @@ SCMSettings IHyprRenderer::getCMSettings(const NColorManagement::PImageDescripti
.sdrBrightnessMultiplier = needsSDRmod && m_renderData.pMonitor->m_sdrBrightness > 0 ? m_renderData.pMonitor->m_sdrBrightness : 1.0f,
};
- m_cmSettingsCache.push_back({srcId, dstId, sPtr, modifySDR, sdrMinLuminance, sdrMaxLuminance, result});
+ m_cmSettingsCache.push_back({
+ .srcDescId = srcId,
+ .dstDescId = dstId,
+ .surfacePtr = sPtr,
+ .modifySDR = modifySDR,
+ .sdrMinLuminance = sdrMinLuminance,
+ .sdrMaxLuminance = sdrMaxLuminance,
+ .settings = result,
+ });
return result;
}
@@ -1937,11 +1947,16 @@ void IHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
if (canAttemptDirectScanout) {
if (pMonitor->attemptDirectScanout()) {
- pMonitor->m_directScanoutIsActive = true;
+ if (!pMonitor->m_directScanoutIsActive) {
+ pMonitor->m_previousFSWindow.reset(); // recalc fs settings
+ pMonitor->m_directScanoutIsActive = true;
+ }
+ handleFullscreenSettings(pMonitor);
return;
} else if (!pMonitor->m_lastScanout.expired() || pMonitor->m_directScanoutIsActive) {
Log::logger->log(Log::DEBUG, "Left a direct scanout.");
pMonitor->m_lastScanout.reset();
+ pMonitor->m_previousFSWindow.reset(); // recalc fs settings
pMonitor->m_directScanoutIsActive = false;
// reset DRM format, but only if needed since it might modeset
@@ -2183,11 +2198,11 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, S
};
}
-bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
+void IHyprRenderer::handleFullscreenSettings(PHLMONITOR pMonitor) {
static auto PCT = CConfigValue<Hyprlang::INT>("render:send_content_type");
- static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
static auto PAUTOHDR = CConfigValue<Hyprlang::INT>("render:cm_auto_hdr");
static auto PNONSHADER = CConfigValue<Hyprlang::INT>("render:non_shader_cm");
+ static auto PNSINTEROP = CConfigValue<Hyprlang::INT>("render:non_shader_cm_interop");
const bool configuredHDR = (pMonitor->m_cmType == NCMType::CM_HDR_EDID || pMonitor->m_cmType == NCMType::CM_HDR);
bool wantHDR = configuredHDR;
@@ -2198,14 +2213,6 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
// HDR metadata determined by
// HDR scRGB - monitor settings
// HDR PQ surface & DS is active - surface settings
- // PPASS = 0 monitor settings
- // PPASS = 1
- // windowed: monitor settings
- // fullscreen surface: surface settings FIXME: fullscreen SDR surface passthrough - pass degamma, gamma if needed
- // PPASS = 2
- // windowed: monitor settings
- // fullscreen SDR surface: monitor settings
- // fullscreen HDR surface: surface settings
bool hdrIsHandled = false;
if (FS_WINDOW) {
@@ -2215,8 +2222,9 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
// we have a surface with image description
if (SURF && SURF->m_colorManagement.valid() && SURF->m_colorManagement->hasImageDescription()) {
const bool surfaceIsHDR = SURF->m_colorManagement->isHDR();
- if (!SURF->m_colorManagement->isWindowsScRGB() && (*PPASS == 1 || ((*PPASS == 2 || !pMonitor->m_lastScanout.expired()) && surfaceIsHDR))) {
- // passthrough
+ wantHDR = *PAUTOHDR && surfaceIsHDR;
+ if (surfaceIsHDR && !SURF->m_colorManagement->isWindowsScRGB() && !pMonitor->m_lastScanout.expired()) {
+ // DS HDR
bool needsHdrMetadataUpdate = SURF->m_colorManagement->needsHdrMetadataUpdate() || pMonitor->m_previousFSWindow != FS_WINDOW || pMonitor->m_needsHDRupdate;
if (SURF->m_colorManagement->needsHdrMetadataUpdate()) {
Log::logger->log(Log::INFO, "[CM] Recreating HDR metadata for surface");
@@ -2228,8 +2236,7 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
}
hdrIsHandled = true;
pMonitor->m_needsHDRupdate = false;
- } else if (*PAUTOHDR && surfaceIsHDR)
- wantHDR = true; // auto-hdr: hdr on
+ }
}
}
@@ -2271,28 +2278,50 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
if (*PCT)
pMonitor->m_output->state->setContentType(NContentType::toDRM(FS_WINDOW ? FS_WINDOW->getContentType() : CONTENT_TYPE_NONE));
- if (FS_WINDOW != pMonitor->m_previousFSWindow || (!FS_WINDOW && pMonitor->m_noShaderCTM)) {
- if (*PNONSHADER == CM_NS_IGNORE || !FS_WINDOW || !pMonitor->needsCM() || !pMonitor->canNoShaderCM() ||
- (*PNONSHADER == CM_NS_ONDEMAND && pMonitor->m_lastScanout.expired() && *PPASS != 1)) {
- if (pMonitor->m_noShaderCTM) {
- Log::logger->log(Log::INFO, "[CM] No fullscreen CTM, restoring previous one");
- pMonitor->m_noShaderCTM = false;
- pMonitor->m_ctmUpdated = true;
- }
- } else {
- const auto FS_DESC = pMonitor->getFSImageDescription();
- if (FS_DESC.has_value()) {
+ if (FS_WINDOW != pMonitor->m_previousFSWindow || (!FS_WINDOW && pMonitor->m_noShaderCTM) || pMonitor->m_ctmUpdated) {
+ const bool INTEROP = (*PNSINTEROP == 1 || (*PNSINTEROP == 2 && FS_WINDOW && FS_WINDOW->getContentType() == CONTENT_TYPE_NONE));
+ bool resetCTM = !FS_WINDOW;
+ if (FS_WINDOW) {
+ if (*PNONSHADER == CM_NS_IGNORE)
+ resetCTM = true;
+ else if (const auto FS_DESC = pMonitor->getFSImageDescription(); pMonitor->needsCM() && pMonitor->canNoShaderCM(!pMonitor->m_lastScanout.expired()) &&
+ FS_DESC.has_value() && (*PNONSHADER != CM_NS_ONDEMAND || !pMonitor->m_lastScanout.expired())) {
Log::logger->log(Log::INFO, "[CM] Updating fullscreen CTM");
- pMonitor->m_noShaderCTM = true;
- auto conversion = FS_DESC.value()->getPrimaries()->convertMatrix(pMonitor->m_imageDescription->getPrimaries());
- const auto mat = conversion.mat();
- const std::array<float, 9> CTM = {
+ pMonitor->m_noShaderCTM = true;
+ pMonitor->m_ctmUpdated = false;
+ auto conversion = FS_DESC.value()->getPrimaries()->convertMatrix(pMonitor->m_imageDescription->getPrimaries());
+ if (pMonitor->m_ctm != Mat3x3::identity() && INTEROP) {
+ const auto& ctm = pMonitor->m_ctm.getMatrix();
+ std::array<std::array<double, 3>, 3> values = {
+ {
+ {ctm[0], ctm[1], ctm[2]},
+ {ctm[3], ctm[4], ctm[5]},
+ {ctm[6], ctm[7], ctm[8]},
+ },
+ };
+ conversion = conversion * Hyprgraphics::CMatrix3(values);
+ }
+ const auto mat = conversion.mat();
+ const std::array<float, 9> CTM = {
mat[0][0], mat[0][1], mat[0][2], //
mat[1][0], mat[1][1], mat[1][2], //
mat[2][0], mat[2][1], mat[2][2], //
};
pMonitor->m_output->state->setCTM(CTM);
- }
+ } else if (!INTEROP && pMonitor->m_ctm != Mat3x3::identity()) {
+ Log::logger->log(Log::INFO, "[CM] Setting identity CTM");
+ pMonitor->m_noShaderCTM = true;
+ pMonitor->m_ctmUpdated = false;
+
+ pMonitor->m_output->state->setCTM(Mat3x3::identity());
+ } else
+ resetCTM = true;
+ }
+
+ if (resetCTM && pMonitor->m_noShaderCTM) {
+ Log::logger->log(Log::INFO, "[CM] No fullscreen CTM, restoring previous one");
+ pMonitor->m_noShaderCTM = false;
+ pMonitor->m_ctmUpdated = true;
}
}
@@ -2302,6 +2331,10 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
}
pMonitor->m_previousFSWindow = FS_WINDOW;
+}
+
+bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
+ handleFullscreenSettings(pMonitor);
bool ok = pMonitor->m_state.commit();
if (!ok) {
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index d61333c7..42592f2c 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -190,7 +190,8 @@ namespace Render {
void preBlurForCurrentMonitor(CRegion* fakeDamage);
SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
- SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
+ SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1,
+ bool shouldUseSurface = false);
void clearCMSettingsCache();
virtual bool reloadShaders(const std::string& path = "") = 0;
@@ -234,6 +235,8 @@ namespace Render {
bool m_monitorTransformEnabled = false; // do not modify directly
std::stack<bool> m_monitorTransformStack;
+ void handleFullscreenSettings(PHLMONITOR pMonitor);
+
// old private:
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry);
diff --git a/src/render/gl/GLFramebuffer.cpp b/src/render/gl/GLFramebuffer.cpp
index 3881c6f6..59c0c4e3 100644
--- a/src/render/gl/GLFramebuffer.cpp
+++ b/src/render/gl/GLFramebuffer.cpp
@@ -16,7 +16,7 @@ bool CGLFramebuffer::internalAlloc(int w, int h, uint32_t drmFormat) {
if (!m_tex) {
m_tex = g_pHyprRenderer->createTexture();
- m_tex->allocate({w, h});
+ m_tex->allocate({w, h}, drmFormat);
m_tex->bind();
m_tex->setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
m_tex->setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
diff --git a/src/render/gl/GLTexture.cpp b/src/render/gl/GLTexture.cpp
index 22bb8146..3216290e 100644
--- a/src/render/gl/GLTexture.cpp
+++ b/src/render/gl/GLTexture.cpp
@@ -84,7 +84,7 @@ CGLTexture::CGLTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image, bool
m_type = isDrmFormatOpaque(attrs.format) ? TEXTURE_RGBX : TEXTURE_RGBA;
//}
- allocate(attrs.size);
+ allocate(attrs.size, attrs.format);
m_eglImage = image;
bind();
diff --git a/src/render/shaders/glsl/blur1.glsl b/src/render/shaders/glsl/blur1.glsl
index 36e7d660..86a37d88 100644
--- a/src/render/shaders/glsl/blur1.glsl
+++ b/src/render/shaders/glsl/blur1.glsl
@@ -100,10 +100,14 @@ vec4 blur1(vec2 v_texcoord, sampler2D tex, float radius, vec2 halfpixel, int pas
vec2 uv = v_texcoord * 2.0;
vec4 sum = texture(tex, uv) * 4.0;
- sum += texture(tex, uv - halfpixel.xy * radius);
- sum += texture(tex, uv + halfpixel.xy * radius);
- sum += texture(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
- sum += texture(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
+ // Those pixels might go outside the rendered area and grab some gabage.
+ // That garbage maps to 0.0-1.0 range with UINT8 buffer and doesn't have any significant impact on the end result.
+ // FP16 garbage maps to -65,504 - 65,504 and defines the end result. Clamp it here to 0.0 - 1.0 to get the same quality outcome as with UINT8.
+ // Rerendering an undamaged area to get some insignificant color accuracy increase on blur edges isn't worth it.
+ sum += clamp(texture(tex, uv - halfpixel.xy * radius), 0.0, 1.0);
+ sum += clamp(texture(tex, uv + halfpixel.xy * radius), 0.0, 1.0);
+ sum += clamp(texture(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius), 0.0, 1.0);
+ sum += clamp(texture(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius), 0.0, 1.0);
vec4 color = sum / 8.0;
diff --git a/src/render/shaders/glsl/cm_helpers.glsl b/src/render/shaders/glsl/cm_helpers.glsl
index 472c6ea5..0d8c68e9 100644
--- a/src/render/shaders/glsl/cm_helpers.glsl
+++ b/src/render/shaders/glsl/cm_helpers.glsl
@@ -189,14 +189,10 @@ vec4 fromLinear(vec4 color, int tf) {
}
vec4 fromLinearNit(vec4 color, int tf, vec2 range) {
- if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
- color.rgb = color.rgb / SDR_MAX_LUMINANCE;
- else {
- color.rgb /= max(color.a, 0.001);
- color.rgb = (color.rgb - range[0]) / (range[1] - range[0]);
- color.rgb = fromLinearRGB(color.rgb, tf);
- color.rgb *= color.a;
- }
+ color.rgb = (color.rgb - range[0] * color.a) / (range[1] - range[0]); // @gulafaran
+ color.rgb /= max(color.a, 0.001);
+ color.rgb = fromLinearRGB(color.rgb, tf);
+ color.rgb *= color.a;
return color;
}
@@ -242,7 +238,7 @@ vec4
#endif
#if USE_MIRROR
// TODO HDR -> SDR tonemap
- vec4 mirrorColor = fromLinearNit(pixColor, CM_TRANSFER_FUNCTION_GAMMA22,
+ vec4 mirrorColor = fromLinearNit(pixColor, CM_TRANSFER_FUNCTION_SRGB,
srcTF == CM_TRANSFER_FUNCTION_GAMMA22 || srcTF == CM_TRANSFER_FUNCTION_SRGB ? srcTFRange : vec2(SDR_MIN_LUMINANCE, SDR_MAX_LUMINANCE));
#endif
pixColor = fromLinearNit(pixColor, dstTF, dstTFRange);
diff --git a/src/render/shaders/glsl/gain.glsl b/src/render/shaders/glsl/gain.glsl
index 2bdc0002..f5326d9c 100644
--- a/src/render/shaders/glsl/gain.glsl
+++ b/src/render/shaders/glsl/gain.glsl
@@ -1,4 +1,5 @@
-vec3 gain(vec3 x, float k) {
+vec3 gain(vec3 src, float k) {
+ vec3 x = clamp(src, 0.0, 1.0);
vec3 t = step(0.5, x);
vec3 y = mix(x, 1.0 - x, t);
vec3 a = 0.5 * pow(2.0 * y, vec3(k));
diff --git a/src/render/shaders/glsl/surface.frag b/src/render/shaders/glsl/surface.frag
index 076ca62c..596cd8fb 100644
--- a/src/render/shaders/glsl/surface.frag
+++ b/src/render/shaders/glsl/surface.frag
@@ -103,6 +103,7 @@ void main() {
#if USE_ROUNDING
pixColor = rounding(pixColor, radius, roundingPower, topLeft, fullSize);
#endif
+ pixColor *= alpha;
#if USE_BLUR
#if USE_DISCARD
pixColor = mix(pixColor, vec4(mix(texture(blurredBG, v_texcoord * uvSize + uvOffset).rgb, pixColor.rgb, pixColor.a), 1.0),
@@ -112,7 +113,7 @@ void main() {
#endif
#endif
- fragColor = pixColor * alpha;
+ fragColor = pixColor;
#if USE_MIRROR
#if USE_TINT
mirrorColor.rgb = mirrorColor.rgb * tint;
@@ -121,6 +122,7 @@ void main() {
#if USE_ROUNDING
mirrorColor = rounding(mirrorColor, radius, roundingPower, topLeft, fullSize);
#endif
+ mirrorColor = mirrorColor * alpha;
#if USE_BLUR
#if USE_DISCARD
mirrorColor = mix(mirrorColor, vec4(mix(texture(blurredBG, v_texcoord * uvSize + uvOffset).rgb, mirrorColor.rgb, mirrorColor.a), 1.0),
@@ -130,6 +132,5 @@ void main() {
#endif
#endif
- mirrorColor = mirrorColor * alpha;
#endif
}
diff --git a/src/render/shaders/glsl/tonemap.glsl b/src/render/shaders/glsl/tonemap.glsl
index a0ba24ef..dcce45a6 100644
--- a/src/render/shaders/glsl/tonemap.glsl
+++ b/src/render/shaders/glsl/tonemap.glsl
@@ -60,5 +60,11 @@ vec4 tonemap(vec4 color, mat3 dstXYZ, float maxLuminance, float dstMaxLuminance,
// scale src to dst reference
float refScale = dstRefLuminance / srcRefLuminance;
+ // kind of works but doesn't use newLum at all
return vec4(fromLMS * toLinear(vec4(ICtCpPQInv * ICtCp, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb * HDR_MAX_LUMINANCE * refScale, color[3]);
+ // breaks with overriden monitor luminances. might be caused by incorrect imput values
+ // @gulafaran
+ // vec3 outRGB = fromLMS * toLinear(vec4(ICtCpPQInv * ICtCp, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb;
+ // outRGB *= (newLum / max(luminance, 0.0001)); // actually apply the tone mapping
+ // return vec4(clamp(outRGB * HDR_MAX_LUMINANCE * refScale, 0.0, dstMaxLuminance), color[3]);
}