From 66ea2e2c9ed4e9257521e6706fbd21feb7e3cc5b Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Thu, 16 Apr 2026 21:19:25 +0300 Subject: renderer: Various CM fixes, part 8 of refactors (#13860) Part 8 of Ujin's refactors. --- src/render/Framebuffer.cpp | 2 + src/render/GLRenderer.cpp | 3 +- src/render/OpenGL.cpp | 68 +++++++++++---------- src/render/OpenGL.hpp | 1 + src/render/Renderer.cpp | 105 +++++++++++++++++++++----------- src/render/Renderer.hpp | 5 +- src/render/gl/GLFramebuffer.cpp | 2 +- src/render/gl/GLTexture.cpp | 2 +- src/render/shaders/glsl/blur1.glsl | 12 ++-- src/render/shaders/glsl/cm_helpers.glsl | 14 ++--- src/render/shaders/glsl/gain.glsl | 3 +- src/render/shaders/glsl/surface.frag | 5 +- src/render/shaders/glsl/tonemap.glsl | 6 ++ 13 files changed, 139 insertions(+), 89 deletions(-) (limited to 'src/render') 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 CHyprGLRenderer::createTexture(const int width, const int height, u g_pHyprOpenGL->makeEGLCurrent(); SP tex = makeShared(); - 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 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("cursor:zoom_disable_aa"); + static auto PFPINVALIDATE = CConfigValue("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 shader, const PImageDescription g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance); } +void CHyprOpenGLImpl::passCMUniforms(WP 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 CHyprOpenGLImpl::renderToOutputInternal() { static const auto PDT = CConfigValue("debug:damage_tracking"); static const auto PCURSORTIMEOUT = CConfigValue("cursor:inactive_timeout"); @@ -1268,7 +1274,6 @@ WP CHyprOpenGLImpl::renderToOutputInternal() { } WP CHyprOpenGLImpl::renderToFBInternal(SP tex, const STextureRenderData& data, eTextureType texType, const CBox& newBox) { - static const auto PPASS = CConfigValue("render:cm_fs_passthrough"); static const auto PENABLECM = CConfigValue("render:cm_enabled"); static auto PBLEND = CConfigValue("render:use_shader_blur_blend"); @@ -1291,10 +1296,7 @@ WP CHyprOpenGLImpl::renderToFBInternal(SP 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 CHyprOpenGLImpl::renderToFBInternal(SP 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 CHyprOpenGLImpl::renderToFBInternal(SP 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 CHyprOpenGLImpl::renderToFBInternal(SP 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 CHyprOpenGLImpl::renderToFBInternal(SP 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 CHyprOpenGLImpl::renderToFBInternal(SP 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 CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or WP 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 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 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 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, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1); void passCMUniforms(WP, const NColorManagement::PImageDescription imageDescription); + void passCMUniforms(WP, 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 #include #include #include @@ -1514,7 +1515,7 @@ SP 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 surface, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) { + SP 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("render:send_content_type"); - static auto PPASS = CConfigValue("render:cm_fs_passthrough"); static auto PAUTOHDR = CConfigValue("render:cm_auto_hdr"); static auto PNONSHADER = CConfigValue("render:non_shader_cm"); + static auto PNSINTEROP = CConfigValue("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 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, 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 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 surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1); + SP 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 m_monitorTransformStack; + void handleFullscreenSettings(PHLMONITOR pMonitor); + // old private: void arrangeLayerArray(PHLMONITOR, const std::vector&, 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]); } -- cgit v1.2.3