diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 87748109f..a5826d195 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -3026,7 +3026,7 @@ void CCompositor::onNewMonitor(SP output) { PImageDescription CCompositor::getPreferredImageDescription() { if (!PROTO::colorManagement) { Log::logger->log(Log::ERR, "FIXME: color management protocol is not enabled, returning empty image description"); - return DEFAULT_IMAGE_DESCRIPTION; + return getDefaultImageDescription(); } Log::logger->log(Log::WARN, "FIXME: color management protocol is enabled, determine correct preferred image description"); // should determine some common settings to avoid unnecessary transformations while keeping maximum displayable precision @@ -3036,7 +3036,7 @@ PImageDescription CCompositor::getPreferredImageDescription() { PImageDescription CCompositor::getHDRImageDescription() { if (!PROTO::colorManagement) { Log::logger->log(Log::ERR, "FIXME: color management protocol is not enabled, returning empty image description"); - return DEFAULT_IMAGE_DESCRIPTION; + return getDefaultImageDescription(); } return m_monitors.size() == 1 && m_monitors[0]->m_output && m_monitors[0]->m_output->parsedEDID.hdrMetadata.has_value() ? diff --git a/src/config/legacy/ConfigManager.cpp b/src/config/legacy/ConfigManager.cpp index c2bdeeae5..33667e35f 100644 --- a/src/config/legacy/ConfigManager.cpp +++ b/src/config/legacy/ConfigManager.cpp @@ -596,6 +596,7 @@ CConfigManager::CConfigManager() { registerConfigVar("debug:ds_handle_same_buffer_fifo", Hyprlang::INT{1}); registerConfigVar("debug:fifo_pending_workaround", Hyprlang::INT{0}); registerConfigVar("debug:render_solitary_wo_damage", Hyprlang::INT{0}); + registerConfigVar("debug:invalidate_fp16", Hyprlang::INT{2}); registerConfigVar("decoration:rounding", Hyprlang::INT{0}); registerConfigVar("decoration:rounding_power", {2.F}); @@ -813,12 +814,12 @@ CConfigManager::CConfigManager() { registerConfigVar("render:expand_undersized_textures", Hyprlang::INT{1}); registerConfigVar("render:xp_mode", Hyprlang::INT{0}); registerConfigVar("render:ctm_animation", Hyprlang::INT{2}); - registerConfigVar("render:cm_fs_passthrough", Hyprlang::INT{2}); registerConfigVar("render:cm_enabled", Hyprlang::INT{1}); registerConfigVar("render:send_content_type", Hyprlang::INT{1}); registerConfigVar("render:cm_auto_hdr", Hyprlang::INT{1}); registerConfigVar("render:new_render_scheduling", Hyprlang::INT{0}); - registerConfigVar("render:non_shader_cm", Hyprlang::INT{3}); + registerConfigVar("render:non_shader_cm", Hyprlang::INT{2}); + registerConfigVar("render:non_shader_cm_interop", Hyprlang::INT{2}); registerConfigVar("render:cm_sdr_eotf", {"default"}); registerConfigVar("render:commit_timing_enabled", Hyprlang::INT{1}); registerConfigVar("render:icc_vcgt_enabled", Hyprlang::INT{1}); diff --git a/src/config/supplementary/ConfigDescriptions.hpp b/src/config/supplementary/ConfigDescriptions.hpp index f02dac0af..c217c044a 100644 --- a/src/config/supplementary/ConfigDescriptions.hpp +++ b/src/config/supplementary/ConfigDescriptions.hpp @@ -1638,12 +1638,6 @@ namespace Config::Supplementary { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{2, 0, 2}, }, - SConfigOptionDescription{ - .value = "render:cm_fs_passthrough", - .description = "Passthrough color settings for fullscreen apps when possible", - .type = CONFIG_OPTION_INT, - .data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2}, - }, SConfigOptionDescription{ .value = "render:cm_enabled", .description = "Enable Color Management pipelines (requires restart to fully take effect)", @@ -1657,11 +1651,10 @@ namespace Config::Supplementary { .data = SConfigOptionDescription::SBoolData{true}, }, SConfigOptionDescription{ - .value = "render:cm_auto_hdr", - .description = - "Auto-switch to hdr mode when fullscreen app is in hdr, 0 - off, 1 - hdr, 2 - hdredid (cm_fs_passthrough can switch to hdr even when this setting is off)", - .type = CONFIG_OPTION_INT, - .data = SConfigOptionDescription::SRangeData{.value = 1, .min = 0, .max = 2}, + .value = "render:cm_auto_hdr", + .description = "Auto-switch to hdr mode when fullscreen app is in hdr, 0 - off, 1 - hdr, 2 - hdredid", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{.value = 1, .min = 0, .max = 2}, }, SConfigOptionDescription{ .value = "render:new_render_scheduling", @@ -1675,6 +1668,12 @@ namespace Config::Supplementary { .type = CONFIG_OPTION_CHOICE, .data = SConfigOptionDescription::SChoiceData{0, "disable,always,ondemand,ignore"}, }, + SConfigOptionDescription{ + .value = "render:non_shader_cm_interop", + .description = "non_shader_cm interaction with ctm proto (hyprsunset and similar). 0 - disable, 1 - enable, 2 - auto (enabled for unknown content type)", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2}, + }, SConfigOptionDescription{ .value = "render:cm_sdr_eotf", .description = @@ -2009,6 +2008,12 @@ namespace Config::Supplementary { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, + SConfigOptionDescription{ + .value = "debug:invalidate_fp16", + .description = "Allow fp16 buffer invalidation. 0 - disable, 1 - enabled, 2 - disable on nvidia", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2}, + }, /* * layout: diff --git a/src/helpers/Drm.cpp b/src/helpers/Drm.cpp index f91c5692a..4f3119f83 100644 --- a/src/helpers/Drm.cpp +++ b/src/helpers/Drm.cpp @@ -32,7 +32,7 @@ std::optional DRM::devIDFromFD(int fd) { } bool DRM::sameGpu(int fd1, int fd2) { - if (fd1 >= 0 && fd1 == fd2) + if (fd1 < 0 || fd2 < 0 || fd1 == fd2) return true; static std::mutex cacheMutex; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index eef68c2ff..5fb6cf31b 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -62,7 +62,7 @@ using namespace NColorManagement; using namespace Render::GL; using namespace Monitor; -CMonitor::CMonitor(SP output_) : m_state(this), m_output(output_), m_imageDescription(DEFAULT_IMAGE_DESCRIPTION) { +CMonitor::CMonitor(SP output_) : m_state(this), m_output(output_), m_imageDescription(getDefaultImageDescription()) { g_pAnimationManager->createAnimation(0.f, m_specialFade, Config::animationTree()->getAnimationPropertyConfig("specialWorkspaceIn"), AVARDAMAGE_NONE); m_specialFade->setUpdateCallback([this](auto) { g_pHyprRenderer->damageMonitor(m_self.lock()); }); static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); @@ -511,9 +511,9 @@ static NColorManagement::eTransferFunction chooseTF(NTransferFunction::eTF tf) { const auto sdrEOTF = NTransferFunction::fromConfig(); switch (tf) { - case NTransferFunction::TF_DEFAULT: case NTransferFunction::TF_GAMMA22: case NTransferFunction::TF_FORCED_GAMMA22: return NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22; + case NTransferFunction::TF_DEFAULT: case NTransferFunction::TF_SRGB: return NColorManagement::CM_TRANSFER_FUNCTION_SRGB; case NTransferFunction::TF_AUTO: // use global setting @@ -949,7 +949,7 @@ bool CMonitor::applyMonitorRule(Config::CMonitorRule&& pMonitorRule, bool force) m_enabled10bit = set10bit; - m_supportsWideColor = RULE->m_supportsHDR; + m_supportsWideColor = RULE->m_supportsWideColor; m_supportsHDR = RULE->m_supportsHDR; if (RULE->m_iccFile.empty()) { @@ -1853,7 +1853,6 @@ bool CMonitor::updateTearing() { uint16_t CMonitor::isDSBlocked(bool full) { uint16_t reasons = 0; static auto PDIRECTSCANOUT = CConfigValue("render:direct_scanout"); - static auto PPASS = CConfigValue("render:cm_fs_passthrough"); static auto PNONSHADER = CConfigValue("render:non_shader_cm"); const auto PWORKSPACE = m_activeWorkspace; @@ -1930,9 +1929,14 @@ uint16_t CMonitor::isDSBlocked(bool full) { const bool surfaceIsHDR = PSURFACE->m_colorManagement.valid() && PSURFACE->m_colorManagement->isHDR(); const bool surfaceIsScRGB = surfaceIsHDR && PSURFACE->m_colorManagement->isWindowsScRGB(); - if (needsCM() && (*PNONSHADER != CM_NS_IGNORE || surfaceIsScRGB) && !canNoShaderCM() && - ((inHDR() && (*PPASS == 0 || !surfaceIsHDR || surfaceIsScRGB)) || (!inHDR() && (*PPASS != 1 || surfaceIsHDR)))) - reasons |= DS_BLOCK_CM; + if (surfaceIsScRGB) + reasons |= DS_BLOCK_CM; // block scRGB + else if (*PNONSHADER != CM_NS_IGNORE) { + if (!surfaceIsHDR && needsCM() && !canNoShaderCM(true)) + reasons |= DS_BLOCK_CM; // block SDR that needs CM while non-shader CM isn't available + else if (surfaceIsHDR && !inHDR()) + reasons |= DS_BLOCK_CM; // block HDR while monitor isn't in HDR mode + } return reasons; } @@ -1987,6 +1991,7 @@ bool CMonitor::attemptDirectScanout() { if (m_lastScanout.expired()) m_prevDrmFormat = m_drmFormat; + const bool NEEDS_TEST = !m_lastScanout || m_drmFormat != params.format; // do not retest while it's active if (m_drmFormat != params.format) { m_output->state->setFormat(params.format); m_drmFormat = params.format; @@ -1997,7 +2002,7 @@ bool CMonitor::attemptDirectScanout() { m_output->state->setPresentationMode(m_tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); - if (!m_state.test()) { + if (NEEDS_TEST && !m_state.test()) { Log::logger->log(Log::TRACE, "attemptDirectScanout: failed basic test"); return false; } @@ -2278,7 +2283,7 @@ std::optional CMonitor::getFSImageDescripti const auto ROOT_SURF = FS_WINDOW->wlSurface()->resource(); const auto SURF = ROOT_SURF->findWithCM(); - return SURF ? NColorManagement::CImageDescription::from(SURF->m_colorManagement->imageDescription()) : DEFAULT_IMAGE_DESCRIPTION; + return SURF ? NColorManagement::CImageDescription::from(SURF->m_colorManagement->imageDescription()) : getDefaultImageDescription(); } NColorManagement::SPCPRimaries CMonitor::getMasteringPrimaries() { @@ -2317,8 +2322,20 @@ bool CMonitor::needsCM() { return SRC_DESC.has_value() && SRC_DESC.value() != m_imageDescription; } +static bool isCompatibleTF(eTransferFunction sourceTF, eTransferFunction targetTF) { + static auto PNONSHADER = CConfigValue("render:non_shader_cm"); + const auto sdrEOTF = NTransferFunction::fromConfig(); + return sourceTF == targetTF // same + || (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && sourceTF == NColorManagement::CM_TRANSFER_FUNCTION_SRGB // forced source gamma22 to output gamma22 + && targetTF == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22) // + || (*PNONSHADER == CM_NS_ONDEMAND // FIXME incorrect but good enough for DS + && (sourceTF == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 || sourceTF == NColorManagement::CM_TRANSFER_FUNCTION_SRGB) // + && (targetTF == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 || targetTF == NColorManagement::CM_TRANSFER_FUNCTION_SRGB)) // + ; +} + // TODO support more drm properties -bool CMonitor::canNoShaderCM() { +bool CMonitor::canNoShaderCM(bool forDSmode) { static auto PNONSHADER = CConfigValue("render:non_shader_cm"); if (*PNONSHADER == CM_NS_DISABLE) return false; @@ -2327,22 +2344,22 @@ bool CMonitor::canNoShaderCM() { if (!SRC_DESC.has_value()) return false; - if (SRC_DESC.value() == m_imageDescription) + const auto& DST_DESC = forDSmode ? m_imageDescription : resources()->m_imageDescription; + if (SRC_DESC.value() == DST_DESC) return true; // no CM needed - const auto SRC_DESC_VALUE = SRC_DESC.value()->value(); + const auto& SRC_DESC_VALUE = SRC_DESC.value()->value(); if (m_imageDescription->value().icc.present) return false; - const auto sdrEOTF = NTransferFunction::fromConfig(); + Log::logger->log(Log::TRACE, "CM: can no shder compares src={} to output={}", SRC_DESC_VALUE, m_imageDescription->value()); + // only primaries differ return ( - (SRC_DESC_VALUE.transferFunction == m_imageDescription->value().transferFunction || - (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && SRC_DESC_VALUE.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB && - m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22)) && - SRC_DESC_VALUE.transferFunctionPower == m_imageDescription->value().transferFunctionPower && - (!inHDR() || SRC_DESC_VALUE.luminances == m_imageDescription->value().luminances) + isCompatibleTF(SRC_DESC_VALUE.transferFunction, DST_DESC->value().transferFunction) // + && SRC_DESC_VALUE.transferFunctionPower == DST_DESC->value().transferFunctionPower // + && (!inHDR() || SRC_DESC_VALUE.luminances == DST_DESC->value().luminances) // not used by shaders atm // && SRC_DESC_VALUE.masteringLuminances == m_imageDescription->value().masteringLuminances && SRC_DESC_VALUE.maxCLL == m_imageDescription->value().maxCLL && SRC_DESC_VALUE.maxFALL == m_imageDescription->value().maxFALL ); @@ -2505,6 +2522,7 @@ bool CMonitor::needsUnmodifiedCopy() { if (!HAS_MODS) return false; + // TODO handle some FP16 cases if (m_imageDescription->value().transferFunction != CM_TRANSFER_FUNCTION_ST2084_PQ && m_imageDescription->value().transferFunction != CM_TRANSFER_FUNCTION_HLG) return false; @@ -2512,15 +2530,25 @@ bool CMonitor::needsUnmodifiedCopy() { } bool CMonitor::useFP16() { - static const auto PFP16 = CConfigValue("render:use_fp16"); - return *PFP16 == 1 || (*PFP16 == 2 && m_imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ); + static const auto PFP16 = CConfigValue("render:use_fp16"); + bool shouldUse = *PFP16 == 1 || (*PFP16 == 2 && m_imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ); + static bool usedBefore = shouldUse; + if (usedBefore != shouldUse) { + usedBefore = shouldUse; + m_blurFBDirty = true; + } + return shouldUse; } WP CMonitor::resources() { const auto DRM_FORMAT = useFP16() ? DRM_FORMAT_ABGR16161616F : m_output->state->state().drmFormat; + const auto DESC = useFP16() ? LINEAR_IMAGE_DESCRIPTION : m_imageDescription; if (!m_resources || m_resources->m_drmFormat != DRM_FORMAT || m_resources->m_size != m_pixelSize) - m_resources = makeUnique(m_self, DRM_FORMAT, m_pixelSize, useFP16() ? LINEAR_IMAGE_DESCRIPTION : m_imageDescription); + m_resources = makeUnique(m_self, DRM_FORMAT, m_pixelSize, DESC); + + if (m_resources->m_imageDescription != DESC) + m_resources->setImageDescription(DESC); return m_resources; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 74fe676b5..59a64237e 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -365,8 +365,8 @@ class CMonitor { uint32_t getPreferredReadFormat(); bool needsCM(); - /// Can do CM without shader - bool canNoShaderCM(); + /// Can do CM without shader (forDSmode ? check output image description : check workbuffer image description) + bool canNoShaderCM(bool forDSmode = false); bool doesNoShaderCM(); bool m_enabled = false; diff --git a/src/helpers/MonitorResources.cpp b/src/helpers/MonitorResources.cpp index 6f5c4d339..8e7723c23 100644 --- a/src/helpers/MonitorResources.cpp +++ b/src/helpers/MonitorResources.cpp @@ -15,6 +15,7 @@ CMonitorResources::CMonitorResources(WP monitor, DRMFormat format, Vec m_blurFB(g_pHyprRenderer->createFB(std::format("Monitor {} blur FB", monitor->m_name))), m_monitor(monitor), m_drmFormat(format), m_size(size), m_imageDescription(imageDescription) { initFB(m_blurFB); + monitor->m_blurFBDirty = true; } void CMonitorResources::initFB(SP fb) { @@ -23,6 +24,19 @@ void CMonitorResources::initFB(SP fb) { fb->setImageDescription(m_imageDescription); } +void CMonitorResources::setImageDescription(NColorManagement::PImageDescription imageDescription) { + if (m_imageDescription == imageDescription) + return; + m_imageDescription = imageDescription; + m_blurFB->setImageDescription(imageDescription); + for (const auto& res : m_workBuffers) + res.buffer->setImageDescription(imageDescription); + if (m_monitorMirrorFB) + m_monitorMirrorFB->setImageDescription(NColorManagement::getDefaultImageDescription()); + if (m_mirrorTex) + m_mirrorTex->m_imageDescription = getMirrorTexImageDescription(); +} + SP CMonitorResources::getUnusedWorkBuffer() { std::erase_if(m_workBuffers, [](const auto& res) { return res.lastUsed.getSeconds() >= MAX_UNUSED_SECONDS; }); @@ -65,7 +79,7 @@ SP CMonitorResources::mirrorFB() { if (!m_monitorMirrorFB->isAllocated()) { m_monitorMirrorFB->alloc(m_size.x, m_size.y, DRM_FORMAT_XRGB8888); - m_monitorMirrorFB->setImageDescription(NColorManagement::DEFAULT_IMAGE_DESCRIPTION); + m_monitorMirrorFB->setImageDescription(NColorManagement::getDefaultImageDescription()); } return m_monitorMirrorFB; @@ -75,13 +89,9 @@ SP CMonitorResources::getMirrorTexture() { return hasMirrorFB() ? mirrorFB()->getTexture() : nullptr; } -void CMonitorResources::enableMirror() { - if (m_mirrorTex) - return; - m_mirrorTex = g_pHyprRenderer->createTexture(); - m_mirrorTex->allocate({m_size.x, m_size.y}, DRM_FORMAT_XRGB8888); - m_mirrorTex->m_imageDescription = CImageDescription::from(SImageDescription{ - .transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22, +NColorManagement::PImageDescription CMonitorResources::getMirrorTexImageDescription() { + return CImageDescription::from(SImageDescription{ + .transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_SRGB, .primariesNameSet = m_imageDescription->value().primariesNameSet, .primariesNamed = m_imageDescription->value().primariesNamed, .primaries = m_imageDescription->value().primaries, @@ -89,6 +99,17 @@ void CMonitorResources::enableMirror() { }); } +void CMonitorResources::enableMirror() { + if (m_mirrorTex) + return; + m_mirrorTex = g_pHyprRenderer->createTexture(); + m_mirrorTex->allocate({m_size.x, m_size.y}, DRM_FORMAT_XRGB8888); + m_mirrorTex->m_imageDescription = getMirrorTexImageDescription(); + m_monitor->m_blurFBDirty = true; +} + void CMonitorResources::disableMirror() { + if (m_mirrorTex) + m_monitor->m_blurFBDirty = true; m_mirrorTex.reset(); } diff --git a/src/helpers/MonitorResources.hpp b/src/helpers/MonitorResources.hpp index a5a60fa5b..6092b9c9f 100644 --- a/src/helpers/MonitorResources.hpp +++ b/src/helpers/MonitorResources.hpp @@ -25,7 +25,9 @@ namespace Monitor { SP m_blurFB; private: - void initFB(SP fb); + void initFB(SP fb); + void setImageDescription(NColorManagement::PImageDescription imageDescription); + NColorManagement::PImageDescription getMirrorTexImageDescription(); struct SResource { SP buffer; diff --git a/src/helpers/cm/ColorManagement.cpp b/src/helpers/cm/ColorManagement.cpp index 829adbe7b..5e4725d40 100644 --- a/src/helpers/cm/ColorManagement.cpp +++ b/src/helpers/cm/ColorManagement.cpp @@ -1,10 +1,12 @@ #include "ColorManagement.hpp" #include "../../macros.hpp" +#include "helpers/TransferFunction.hpp" #include #include #include using namespace NColorManagement; +using namespace NTransferFunction; namespace NColorManagement { // expected to be small @@ -110,6 +112,20 @@ WP CImageDescription::getPrimaries() const { return CPrimaries::from(m_primariesId); } +bool CImageDescription::needsCM(WP target) const { + if (m_id == target->m_id) + return false; + + return m_imageDescription.icc.present || target->m_imageDescription.icc.present // TODO compare ICC + || m_imageDescription.transferFunction != target->m_imageDescription.transferFunction // + //|| m_imageDescription.transferFunctionPower != target->m_imageDescription.transferFunctionPower // TODO unsupported + || m_imageDescription.getPrimaries() != target->m_imageDescription.getPrimaries() // + // || m_imageDescription.masteringPrimaries != target->m_imageDescription.masteringPrimaries // TODO unused + || m_imageDescription.luminances != target->m_imageDescription.luminances // + // || m_imageDescription.masteringLuminances != target->m_imageDescription.masteringLuminances // TODO unused + ; +} + static Mat3x3 diag3(const std::array& s) { return Mat3x3{std::array{s[0], 0, 0, 0, s[1], 0, 0, 0, s[2]}}; } @@ -190,4 +206,16 @@ Mat3x3 NColorManagement::adaptBradford(Hyprgraphics::CColor::xy srcW, Hyprgraphi result.multiply(diag3(scale)).multiply(Bradford); return result; -} \ No newline at end of file +} + +PImageDescription NColorManagement::getDefaultImageDescription() { + const auto TF = fromConfig(); + switch (TF) { + case TF_AUTO: + case TF_GAMMA22: + case TF_FORCED_GAMMA22: return DEFAULT_GAMMA22_IMAGE_DESCRIPTION; + case TF_DEFAULT: + case TF_SRGB: return DEFAULT_SRGB_IMAGE_DESCRIPTION; + default: UNREACHABLE(); + } +} diff --git a/src/helpers/cm/ColorManagement.hpp b/src/helpers/cm/ColorManagement.hpp index dccbb9722..183a8544d 100644 --- a/src/helpers/cm/ColorManagement.hpp +++ b/src/helpers/cm/ColorManagement.hpp @@ -1,11 +1,13 @@ #pragma once #include "color-management-v1.hpp" +#include #include #include "../../helpers/memory/Memory.hpp" #include "../../helpers/math/Math.hpp" #include +#include #include #include @@ -78,6 +80,24 @@ namespace NColorManagement { default: return sc(tf); } } + inline std::string tfToString(eTransferFunction tf) { + switch (tf) { + case CM_TRANSFER_FUNCTION_BT1886: return "TF:BT1886"; + case CM_TRANSFER_FUNCTION_GAMMA22: return "TF:GAMMA22"; + case CM_TRANSFER_FUNCTION_GAMMA28: return "TF:GAMMA28"; + case CM_TRANSFER_FUNCTION_ST240: return "TF:ST240"; + case CM_TRANSFER_FUNCTION_EXT_LINEAR: return "TF:EXT_LINEAR"; + case CM_TRANSFER_FUNCTION_LOG_100: return "TF:LOG_100"; + case CM_TRANSFER_FUNCTION_LOG_316: return "TF:LOG_316"; + case CM_TRANSFER_FUNCTION_XVYCC: return "TF:XVYCC"; + case CM_TRANSFER_FUNCTION_SRGB: return "TF:SRGB"; + case CM_TRANSFER_FUNCTION_EXT_SRGB: return "TF:EXT_SRGB"; + case CM_TRANSFER_FUNCTION_ST2084_PQ: return "TF:ST2084_PQ"; + case CM_TRANSFER_FUNCTION_ST428: return "TF:ST428"; + case CM_TRANSFER_FUNCTION_HLG: return "TF:HLG"; + default: return "TF:ERROR"; + } + } using SPCPRimaries = Hyprgraphics::SPCPRimaries; @@ -320,6 +340,7 @@ namespace NColorManagement { uint64_t id() const; WP getPrimaries() const; + bool needsCM(WP target) const; private: CImageDescription(const SImageDescription& imageDescription, const uint64_t imageDescriptionId); @@ -330,7 +351,9 @@ namespace NColorManagement { using PImageDescription = WP; - static const auto DEFAULT_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{ + PImageDescription getDefaultImageDescription(); + + static const auto DEFAULT_GAMMA22_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{ .transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22, .primariesNameSet = true, .primariesNamed = NColorManagement::CM_PRIMARIES_SRGB, @@ -338,6 +361,14 @@ namespace NColorManagement { .luminances = {.min = SDR_MIN_LUMINANCE, .max = 80, .reference = 80}, }); + static const auto DEFAULT_SRGB_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{ + .transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_SRGB, + .primariesNameSet = true, + .primariesNamed = NColorManagement::CM_PRIMARIES_SRGB, + .primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_SRGB), + .luminances = {.min = SDR_MIN_LUMINANCE, .max = 80, .reference = 80}, + }); + static const auto DEFAULT_HDR_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{ .transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ, .primariesNameSet = true, @@ -363,3 +394,30 @@ namespace NColorManagement { .luminances = {.min = 0, .max = 10000, .reference = 80}, }); } + +template +struct std::formatter : std::formatter { + template + auto format(const Hyprgraphics::SPCPRimaries& primaries, FormatContext& ctx) const { + return std::format_to(ctx.out(), "[r={},{} g={},{} b={},{} w={},{}]", primaries.red.x, primaries.red.y, primaries.green.x, primaries.green.y, primaries.blue.x, + primaries.blue.y, primaries.white.x, primaries.white.y); + } +}; + +template +struct std::formatter : std::formatter { + template + auto format(const NColorManagement::SImageDescription::SPCLuminances& luminances, FormatContext& ctx) const { + return std::format_to(ctx.out(), "[{}-{}({})]", luminances.min, luminances.max, luminances.reference); + } +}; + +template +struct std::formatter : std::formatter { + template + auto format(const NColorManagement::SImageDescription& imageDescription, FormatContext& ctx) const { + return std::format_to(ctx.out(), "[{}{}, primaries={}, luminances={}]", NColorManagement::tfToString(imageDescription.transferFunction), + imageDescription.transferFunctionPower != 1.0f ? std::format("^{}", imageDescription.transferFunctionPower) : "", imageDescription.getPrimaries(), + imageDescription.luminances); + } +}; diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 32332895a..634a13519 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -146,16 +146,7 @@ void CHyprError::createQueued() { cairo_surface_flush(CAIROSURFACE); // copy the data to an OpenGL texture we have - const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - auto tex = texture(); - tex->allocate(PMONITOR->m_pixelSize); - tex->bind(); - tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST); - tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST); - tex->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE); - tex->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); + m_texture = g_pHyprRenderer->createTexture(CAIROSURFACE); // delete cairo cairo_destroy(CAIRO); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 8d3c83f03..04deca9a7 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -419,8 +419,10 @@ SP CPointerManager::renderHWCursorBuffer(SPisNvidia()); - if (maxSize == Vector2D{}) + if (maxSize == Vector2D{}) { + Log::logger->log(Log::TRACE, "hardware cursor has zero max size {}, current {}", maxSize, m_currentCursorImage.size); return nullptr; + } if (maxSize != Vector2D{-1, -1}) { if (cursorSize.x > maxSize.x || cursorSize.y > maxSize.y) { @@ -493,6 +495,8 @@ SP CPointerManager::renderHWCursorBuffer(SPm_current.texture) { Log::logger->log(Log::TRACE, "Cursor CPU surface: format {}, expecting AR24", NFormatUtils::drmFormatName(SURFACE->m_current.texture->m_drmFormat)); + if (!SURFACE->m_current.texture->m_drmFormat) + SURFACE->m_current.texture->m_drmFormat = DRM_FORMAT_ARGB8888; // FIXME assumes DRM_FORMAT_ARGB8888 if (SURFACE->m_current.texture->m_drmFormat == DRM_FORMAT_ABGR8888) { Log::logger->log(Log::TRACE, "Cursor CPU surface format AB24, will flip. WARNING: this will break on big endian!"); flipRB = true; diff --git a/src/managers/screenshare/ScreenshareFrame.cpp b/src/managers/screenshare/ScreenshareFrame.cpp index 47c61fe6e..de71fcaac 100644 --- a/src/managers/screenshare/ScreenshareFrame.cpp +++ b/src/managers/screenshare/ScreenshareFrame.cpp @@ -171,6 +171,16 @@ void CScreenshareFrame::renderMonitor() { return; } + if (!TEXTURE->m_imageDescription) + Log::logger->log(Log::ERR, "CM: FIXME no source image description for screenshare"); + + if (!g_pHyprRenderer->m_renderData.currentFB->imageDescription()) + Log::logger->log(Log::ERR, "CM: FIXME no target image description for screenshare"); + + if (TEXTURE->m_imageDescription && g_pHyprRenderer->m_renderData.currentFB->imageDescription()) + Log::logger->log(Log::TRACE, "CM: screenshot renderMonitor {} -> {}", TEXTURE->m_imageDescription->value(), + g_pHyprRenderer->m_renderData.currentFB->imageDescription()->value()); + const bool IS_CM_AWARE = PROTO::colorManagement && PROTO::colorManagement->isClientCMAware(m_session->m_client); g_pHyprRenderer->m_renderData.transformDamage = false; g_pHyprRenderer->m_renderData.noSimplify = true; @@ -373,7 +383,7 @@ bool CScreenshareFrame::copyDmabuf() { LOGM(Log::ERR, "Can't copy: failed to begin rendering to dma frame"); return false; } - g_pHyprRenderer->m_renderData.currentFB->setImageDescription(NColorManagement::DEFAULT_IMAGE_DESCRIPTION); + g_pHyprRenderer->m_renderData.currentFB->setImageDescription(NColorManagement::DEFAULT_SRGB_IMAGE_DESCRIPTION); render(); @@ -407,7 +417,7 @@ bool CScreenshareFrame::copyShm() { auto outFB = g_pHyprRenderer->createFB(); outFB->alloc(m_bufferSize.x, m_bufferSize.y, shm.format); - outFB->setImageDescription(NColorManagement::DEFAULT_IMAGE_DESCRIPTION); + outFB->setImageDescription(NColorManagement::DEFAULT_SRGB_IMAGE_DESCRIPTION); if (!g_pHyprRenderer->beginFullFakeRender(PMONITOR, m_damage, outFB)) { LOGM(Log::ERR, "Can't copy: failed to begin rendering"); @@ -440,7 +450,7 @@ void CScreenshareFrame::storeTempFB() { if (!m_session->m_tempFB) m_session->m_tempFB = g_pHyprRenderer->createFB(); m_session->m_tempFB->alloc(m_bufferSize.x, m_bufferSize.y); - m_session->m_tempFB->setImageDescription(NColorManagement::DEFAULT_IMAGE_DESCRIPTION); + m_session->m_tempFB->setImageDescription(NColorManagement::DEFAULT_SRGB_IMAGE_DESCRIPTION); CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index bfab02e49..fce91691b 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -266,7 +266,7 @@ CColorManagementSurface::CColorManagementSurface(SP return; m_client = m_resource->client(); - m_imageDescription = DEFAULT_IMAGE_DESCRIPTION; + m_imageDescription = getDefaultImageDescription(); m_resource->setDestroy([this](CWpColorManagementSurfaceV1* r) { LOGM(Log::TRACE, "Destroy wp cm surface {}", (uintptr_t)m_surface); @@ -302,7 +302,7 @@ CColorManagementSurface::CColorManagementSurface(SP }); m_resource->setUnsetImageDescription([this](CWpColorManagementSurfaceV1* r) { LOGM(Log::TRACE, "Unset image description for surface={}", (uintptr_t)r); - m_imageDescription = DEFAULT_IMAGE_DESCRIPTION; + m_imageDescription = getDefaultImageDescription(); setHasImageDescription(false); }); } @@ -316,8 +316,10 @@ wl_client* CColorManagementSurface::client() { } const SImageDescription& CColorManagementSurface::imageDescription() { - if (!hasImageDescription()) - LOGM(Log::WARN, "Reading imageDescription while none set. Returns default or empty values"); + if (!hasImageDescription()) { + LOGM(Log::TRACE, "Reading imageDescription while none set. Returns default or empty values"); + return getDefaultImageDescription()->value(); // JIC default settings change + } return m_imageDescription->value(); } diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 47a466c1a..4b8d392ee 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 77fffd250..aefdc67a4 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 8ae52c8ee..358e47028 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 78518ffe7..82b8f0548 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 ba82fa153..df1106b0f 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 d61333c78..42592f2ca 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 3881c6f6e..59c0c4e35 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 22bb8146f..3216290e6 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 36e7d660d..86a37d88a 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 472c6ea51..0d8c68e93 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 2bdc00023..f5326d9c8 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 076ca62c2..596cd8fba 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 a0ba24ef1..dcce45a67 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]); }