mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-07 06:18:05 +02:00
renderer: Various CM fixes, part 8 of refactors (#13860)
Part 8 of Ujin's refactors.
This commit is contained in:
parent
4cce7f60a9
commit
66ea2e2c9e
27 changed files with 357 additions and 157 deletions
|
|
@ -3026,7 +3026,7 @@ void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> 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() ?
|
||||
|
|
|
|||
|
|
@ -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});
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ std::optional<dev_t> 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;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ using namespace NColorManagement;
|
|||
using namespace Render::GL;
|
||||
using namespace Monitor;
|
||||
|
||||
CMonitor::CMonitor(SP<Aquamarine::IOutput> output_) : m_state(this), m_output(output_), m_imageDescription(DEFAULT_IMAGE_DESCRIPTION) {
|
||||
CMonitor::CMonitor(SP<Aquamarine::IOutput> 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<Hyprlang::FLOAT>("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<Hyprlang::INT>("render:direct_scanout");
|
||||
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
||||
static auto PNONSHADER = CConfigValue<Hyprlang::INT>("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<NColorManagement::PImageDescription> 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<Hyprlang::INT>("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<Hyprlang::INT>("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<Hyprlang::INT>("render:use_fp16");
|
||||
return *PFP16 == 1 || (*PFP16 == 2 && m_imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ);
|
||||
static const auto PFP16 = CConfigValue<Hyprlang::INT>("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<CMonitorResources> 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<CMonitorResources>(m_self, DRM_FORMAT, m_pixelSize, useFP16() ? LINEAR_IMAGE_DESCRIPTION : m_imageDescription);
|
||||
m_resources = makeUnique<CMonitorResources>(m_self, DRM_FORMAT, m_pixelSize, DESC);
|
||||
|
||||
if (m_resources->m_imageDescription != DESC)
|
||||
m_resources->setImageDescription(DESC);
|
||||
|
||||
return m_resources;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ CMonitorResources::CMonitorResources(WP<CMonitor> 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<Render::IFramebuffer> fb) {
|
||||
|
|
@ -23,6 +24,19 @@ void CMonitorResources::initFB(SP<Render::IFramebuffer> 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<Render::IFramebuffer> CMonitorResources::getUnusedWorkBuffer() {
|
||||
std::erase_if(m_workBuffers, [](const auto& res) { return res.lastUsed.getSeconds() >= MAX_UNUSED_SECONDS; });
|
||||
|
||||
|
|
@ -65,7 +79,7 @@ SP<Render::IFramebuffer> 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<Render::ITexture> 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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ namespace Monitor {
|
|||
SP<Render::IFramebuffer> m_blurFB;
|
||||
|
||||
private:
|
||||
void initFB(SP<Render::IFramebuffer> fb);
|
||||
void initFB(SP<Render::IFramebuffer> fb);
|
||||
void setImageDescription(NColorManagement::PImageDescription imageDescription);
|
||||
NColorManagement::PImageDescription getMirrorTexImageDescription();
|
||||
|
||||
struct SResource {
|
||||
SP<Render::IFramebuffer> buffer;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
#include "ColorManagement.hpp"
|
||||
#include "../../macros.hpp"
|
||||
#include "helpers/TransferFunction.hpp"
|
||||
#include <hyprutils/memory/UniquePtr.hpp>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace NColorManagement;
|
||||
using namespace NTransferFunction;
|
||||
|
||||
namespace NColorManagement {
|
||||
// expected to be small
|
||||
|
|
@ -110,6 +112,20 @@ WP<const CPrimaries> CImageDescription::getPrimaries() const {
|
|||
return CPrimaries::from(m_primariesId);
|
||||
}
|
||||
|
||||
bool CImageDescription::needsCM(WP<const CImageDescription> 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<float, 3>& s) {
|
||||
return Mat3x3{std::array<float, 9>{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;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "color-management-v1.hpp"
|
||||
#include <format>
|
||||
#include <hyprgraphics/color/Color.hpp>
|
||||
#include "../../helpers/memory/Memory.hpp"
|
||||
#include "../../helpers/math/Math.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <expected>
|
||||
|
||||
|
|
@ -78,6 +80,24 @@ namespace NColorManagement {
|
|||
default: return sc<eTransferFunction>(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<const CPrimaries> getPrimaries() const;
|
||||
bool needsCM(WP<const CImageDescription> target) const;
|
||||
|
||||
private:
|
||||
CImageDescription(const SImageDescription& imageDescription, const uint64_t imageDescriptionId);
|
||||
|
|
@ -330,7 +351,9 @@ namespace NColorManagement {
|
|||
|
||||
using PImageDescription = WP<const CImageDescription>;
|
||||
|
||||
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 <typename CharT>
|
||||
struct std::formatter<Hyprgraphics::SPCPRimaries, CharT> : std::formatter<CharT> {
|
||||
template <typename FormatContext>
|
||||
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 <typename CharT>
|
||||
struct std::formatter<NColorManagement::SImageDescription::SPCLuminances, CharT> : std::formatter<CharT> {
|
||||
template <typename FormatContext>
|
||||
auto format(const NColorManagement::SImageDescription::SPCLuminances& luminances, FormatContext& ctx) const {
|
||||
return std::format_to(ctx.out(), "[{}-{}({})]", luminances.min, luminances.max, luminances.reference);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CharT>
|
||||
struct std::formatter<NColorManagement::SImageDescription, CharT> : std::formatter<CharT> {
|
||||
template <typename FormatContext>
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -419,8 +419,10 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
|
|||
|
||||
const bool shouldUseCpuBuffer = *PCPUBUFFER == 1 || (*PCPUBUFFER != 0 && g_pHyprRenderer->isNvidia());
|
||||
|
||||
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<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
|
|||
|
||||
if (SURFACE->m_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;
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ CColorManagementSurface::CColorManagementSurface(SP<CWpColorManagementSurfaceV1>
|
|||
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<CWpColorManagementSurfaceV1>
|
|||
});
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ SP<ITexture> CHyprGLRenderer::createTexture(const int width, const int height, u
|
|||
g_pHyprOpenGL->makeEGLCurrent();
|
||||
SP<ITexture> tex = makeShared<CGLTexture>();
|
||||
|
||||
tex->allocate({width, height});
|
||||
tex->allocate({width, height}, DRM_FORMAT_ARGB8888); // FIXME assume DRM_FORMAT_ARGB8888
|
||||
|
||||
tex->m_size = {width, height};
|
||||
// copy the data to an OpenGL texture we have
|
||||
|
|
@ -237,6 +237,7 @@ SP<ITexture> CHyprGLRenderer::createTexture(cairo_surface_t* cairo) {
|
|||
if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) {
|
||||
tex->setTexParameter(GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
||||
tex->setTexParameter(GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
tex->m_drmFormat = DRM_FORMAT_ARGB8888;
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_size.x, tex->m_size.y, 0, glFormat, glType, DATA);
|
||||
|
|
|
|||
|
|
@ -782,6 +782,7 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, SP<IFra
|
|||
|
||||
void CHyprOpenGLImpl::end() {
|
||||
static auto PZOOMDISABLEAA = CConfigValue<Hyprlang::INT>("cursor:zoom_disable_aa");
|
||||
static auto PFPINVALIDATE = CConfigValue<Hyprlang::INT>("debug:invalidate_fp16");
|
||||
auto& m_renderData = g_pHyprRenderer->m_renderData;
|
||||
const auto PMONITOR = m_renderData.pMonitor;
|
||||
TRACY_GPU_ZONE("RenderEnd");
|
||||
|
|
@ -839,7 +840,7 @@ void CHyprOpenGLImpl::end() {
|
|||
g_pHyprRenderer->popMonitorTransformEnabled();
|
||||
|
||||
// invalidate our render FBs to signal to the driver we don't need them anymore
|
||||
if (!g_pHyprRenderer->m_renderData.pMonitor->useFP16()) { // FIXME wtf?
|
||||
if (!g_pHyprRenderer->m_renderData.pMonitor->useFP16() || *PFPINVALIDATE == 1 || (*PFPINVALIDATE == 2 && !g_pHyprRenderer->isNvidia())) { // FIXME wtf?
|
||||
g_pHyprRenderer->m_renderData.pMonitor->resources()->forEachUnusedFB(
|
||||
[](const auto& fb) {
|
||||
fb->bind();
|
||||
|
|
@ -1194,6 +1195,11 @@ void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const PImageDescription
|
|||
g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const PImageDescription imageDescription, const SCMSettings& settings) {
|
||||
passCMUniforms(shader, imageDescription, g_pHyprRenderer->workBufferImageDescription(), true, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance,
|
||||
g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance, settings);
|
||||
}
|
||||
|
||||
WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
|
||||
static const auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
|
||||
static const auto PCURSORTIMEOUT = CConfigValue<Hyprlang::FLOAT>("cursor:inactive_timeout");
|
||||
|
|
@ -1268,7 +1274,6 @@ WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
|
|||
}
|
||||
|
||||
WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STextureRenderData& data, eTextureType texType, const CBox& newBox) {
|
||||
static const auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
||||
static const auto PENABLECM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
|
||||
static auto PBLEND = CConfigValue<Hyprlang::INT>("render:use_shader_blur_blend");
|
||||
|
||||
|
|
@ -1291,10 +1296,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
|
|||
if (data.finalMonitorCM || (g_pHyprRenderer->m_renderData.currentWindow && g_pHyprRenderer->m_renderData.currentWindow->m_ruleApplicator->RGBX().valueOrDefault()))
|
||||
shaderFeatures &= ~SH_FEAT_RGBA;
|
||||
|
||||
const auto surface = g_pHyprRenderer->m_renderData.surface;
|
||||
const bool isHDRSurface = surface.valid() && surface->m_colorManagement.valid() ? surface->m_colorManagement->isHDR() : false;
|
||||
const bool canPassHDRSurface = isHDRSurface && !surface->m_colorManagement->isWindowsScRGB(); // windows scRGB requires CM shader
|
||||
|
||||
const auto surface = g_pHyprRenderer->m_renderData.surface;
|
||||
const auto WORK_BUFFER_IMAGE_DESCRIPTION = g_pHyprRenderer->workBufferImageDescription();
|
||||
|
||||
// chosenSdrEotf contains the valid eotf for this display
|
||||
|
|
@ -1304,8 +1306,8 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
|
|||
return tex->m_imageDescription;
|
||||
|
||||
// if valid CM surface, use that as a source
|
||||
if (g_pHyprRenderer->m_renderData.surface.valid() && g_pHyprRenderer->m_renderData.surface->m_colorManagement.valid())
|
||||
return CImageDescription::from(g_pHyprRenderer->m_renderData.surface->m_colorManagement->imageDescription());
|
||||
if (surface.valid() && surface->m_colorManagement.valid())
|
||||
return CImageDescription::from(surface->m_colorManagement->imageDescription());
|
||||
|
||||
if (data.cmBackToSRGB)
|
||||
return g_pHyprRenderer->m_renderData.pMonitor->m_imageDescription;
|
||||
|
|
@ -1316,7 +1318,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
|
|||
return WORK_BUFFER_IMAGE_DESCRIPTION;
|
||||
|
||||
// otherwise, default
|
||||
return DEFAULT_IMAGE_DESCRIPTION;
|
||||
return getDefaultImageDescription();
|
||||
}();
|
||||
|
||||
const auto TARGET_IMAGE_DESCRIPTION = [&] {
|
||||
|
|
@ -1325,7 +1327,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
|
|||
|
||||
// if we are CM'ing back, use default sRGB
|
||||
if (data.cmBackToSRGB)
|
||||
return DEFAULT_IMAGE_DESCRIPTION;
|
||||
return getDefaultImageDescription();
|
||||
|
||||
// for final CM, use the target description
|
||||
if (data.finalMonitorCM)
|
||||
|
|
@ -1341,15 +1343,13 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
|
|||
if (data.discardActive)
|
||||
shaderFeatures |= SH_FEAT_DISCARD;
|
||||
|
||||
const bool CANT_CHECK_CM_EQUALITY =
|
||||
data.cmBackToSRGB || data.finalMonitorCM || (!g_pHyprRenderer->m_renderData.surface || !g_pHyprRenderer->m_renderData.surface->m_colorManagement);
|
||||
const bool skipCM = !*PENABLECM || !m_cmSupported /* CM unsupported or disabled */
|
||||
|| g_pHyprRenderer->m_renderData.pMonitor->doesNoShaderCM() /* no shader needed */
|
||||
|| !SOURCE_IMAGE_DESCRIPTION->needsCM(TARGET_IMAGE_DESCRIPTION) /* Source and target have matching image descriptions */
|
||||
;
|
||||
|
||||
const bool skipCM = !*PENABLECM || !m_cmSupported /* CM unsupported or disabled */
|
||||
|| g_pHyprRenderer->m_renderData.pMonitor->doesNoShaderCM() /* no shader needed */
|
||||
|| (SOURCE_IMAGE_DESCRIPTION->id() == TARGET_IMAGE_DESCRIPTION->id() && !CANT_CHECK_CM_EQUALITY) /* Source and target have the same image description */
|
||||
|| (((*PPASS && canPassHDRSurface) ||
|
||||
(*PPASS == 1 && !isHDRSurface && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR_EDID)) &&
|
||||
m_renderData.pMonitor->inFullscreenMode()) /* Fullscreen window with pass cm enabled */;
|
||||
if (g_pHyprRenderer->m_renderData.pMonitor->needsACopyFB())
|
||||
Log::logger->log(Log::TRACE, "CM: render to FB skip={} {} -> {}", skipCM, SOURCE_IMAGE_DESCRIPTION->value(), TARGET_IMAGE_DESCRIPTION->value());
|
||||
|
||||
if (data.allowDim && g_pHyprRenderer->m_renderData.currentWindow &&
|
||||
(g_pHyprRenderer->m_renderData.currentWindow->m_notRespondingTint->value() > 0 || g_pHyprRenderer->m_renderData.currentWindow->m_dimPercent->value() > 0))
|
||||
|
|
@ -1359,9 +1359,9 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
|
|||
shaderFeatures |= SH_FEAT_ROUNDING;
|
||||
|
||||
if (!skipCM) {
|
||||
const auto settings = g_pHyprRenderer->getCMSettings(SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION,
|
||||
g_pHyprRenderer->m_renderData.surface.valid() ? g_pHyprRenderer->m_renderData.surface.lock() : nullptr, true,
|
||||
g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance);
|
||||
const auto settings =
|
||||
g_pHyprRenderer->getCMSettings(SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION, surface.valid() ? surface.lock() : nullptr, true,
|
||||
g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance, true);
|
||||
|
||||
shaderFeatures |= SH_FEAT_CM;
|
||||
|
||||
|
|
@ -1670,10 +1670,10 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
|
|||
WP<CShader> shader;
|
||||
|
||||
// From FB to sRGB
|
||||
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||
const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
|
||||
if (!skipCM) {
|
||||
shader = useShader(getShaderVariant(SH_FRAG_BLURPREPARE, SH_FEAT_CM));
|
||||
passCMUniforms(shader, g_pHyprRenderer->workBufferImageDescription(), DEFAULT_IMAGE_DESCRIPTION);
|
||||
passCMUniforms(shader, g_pHyprRenderer->workBufferImageDescription(), getDefaultImageDescription());
|
||||
shader->setUniformFloat(SHADER_SDR_SATURATION,
|
||||
m_renderData.pMonitor->m_sdrSaturation > 0 &&
|
||||
g_pHyprRenderer->workBufferImageDescription()->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
|
||||
|
|
@ -1790,10 +1790,10 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
|
|||
currentTex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
// From FB to sRGB
|
||||
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||
const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
|
||||
if (!skipCM) {
|
||||
shader = useShader(getShaderVariant(SH_FRAG_BLURFINISH, SH_FEAT_CM));
|
||||
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION, g_pHyprRenderer->workBufferImageDescription());
|
||||
passCMUniforms(shader, getDefaultImageDescription(), g_pHyprRenderer->workBufferImageDescription());
|
||||
shader->setUniformFloat(SHADER_SDR_SATURATION,
|
||||
m_renderData.pMonitor->m_sdrSaturation > 0 &&
|
||||
g_pHyprRenderer->workBufferImageDescription()->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
|
||||
|
|
@ -2074,10 +2074,10 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const Config::CGradientValue
|
|||
WP<CShader> shader;
|
||||
|
||||
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
|
||||
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||
const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
|
||||
if (!skipCM) {
|
||||
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD) | globalFeatures()));
|
||||
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
|
||||
passCMUniforms(shader, getDefaultImageDescription());
|
||||
} else
|
||||
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | globalFeatures()));
|
||||
|
||||
|
|
@ -2159,10 +2159,10 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const Config::CGradientValue
|
|||
|
||||
WP<CShader> shader;
|
||||
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
|
||||
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||
const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
|
||||
if (!skipCM) {
|
||||
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD) | globalFeatures()));
|
||||
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
|
||||
passCMUniforms(shader, getDefaultImageDescription());
|
||||
} else
|
||||
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | globalFeatures()));
|
||||
|
||||
|
|
@ -2237,10 +2237,10 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
|
|||
blend(true);
|
||||
|
||||
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
|
||||
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||
const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
|
||||
auto shader = useShader(getShaderVariant(SH_FRAG_SHADOW, skipCM ? 0 : SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD) | globalFeatures()));
|
||||
if (!skipCM)
|
||||
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
|
||||
passCMUniforms(shader, getDefaultImageDescription());
|
||||
|
||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||
shader->setUniformFloat4(SHADER_COLOR, col.r, col.g, col.b, col.a * a);
|
||||
|
|
@ -2301,10 +2301,10 @@ void CHyprOpenGLImpl::renderInnerGlow(const CBox& box, int round, float rounding
|
|||
blend(true);
|
||||
|
||||
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
|
||||
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||
const bool skipCM = !m_cmSupported || !g_pHyprRenderer->workBufferImageDescription()->needsCM(getDefaultImageDescription());
|
||||
auto shader = useShader(getShaderVariant(SH_FRAG_INNER_GLOW, skipCM ? 0 : SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD)));
|
||||
if (!skipCM)
|
||||
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
|
||||
passCMUniforms(shader, getDefaultImageDescription());
|
||||
|
||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||
shader->setUniformFloat4(SHADER_COLOR, col.r, col.g, col.b, col.a * a);
|
||||
|
|
@ -2353,6 +2353,8 @@ void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
|
|||
}
|
||||
auto guard = g_pHyprRenderer->bindTempFB(g_pHyprRenderer->m_renderData.pMonitor->resources()->mirrorFB());
|
||||
|
||||
Log::logger->log(Log::TRACE, "CM: saveBufferForMirror {} -> {}", TEX->m_imageDescription->value(), g_pHyprRenderer->m_renderData.currentFB->imageDescription()->value());
|
||||
|
||||
blend(false);
|
||||
|
||||
renderTexture(TEX, box,
|
||||
|
|
|
|||
|
|
@ -339,6 +339,7 @@ namespace Render::GL {
|
|||
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
|
||||
bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
|
||||
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
|
||||
void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const SCMSettings& settings);
|
||||
void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
||||
void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
||||
void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
#include "Texture.hpp"
|
||||
#include "./pass/PreBlurElement.hpp"
|
||||
#include "types.hpp"
|
||||
#include <hyprgraphics/color/Color.hpp>
|
||||
#include <hyprutils/math/Mat3x3.hpp>
|
||||
#include <hyprutils/math/Region.hpp>
|
||||
#include <hyprutils/math/Vector2D.hpp>
|
||||
|
|
@ -1514,7 +1515,7 @@ SP<ITexture> IHyprRenderer::renderText(const std::string& text, CHyprColor col,
|
|||
|
||||
cairo_surface_flush(CAIROSURFACE);
|
||||
|
||||
auto tex = createTexture(cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE), cairo_image_surface_get_data(CAIROSURFACE));
|
||||
auto tex = createTexture(CAIROSURFACE);
|
||||
|
||||
cairo_destroy(CAIRO);
|
||||
cairo_surface_destroy(CAIROSURFACE);
|
||||
|
|
@ -1779,10 +1780,10 @@ void IHyprRenderer::clearCMSettingsCache() {
|
|||
}
|
||||
|
||||
SCMSettings IHyprRenderer::getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
|
||||
SP<CWLSurfaceResource> surface, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) {
|
||||
SP<CWLSurfaceResource> surface, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance, bool shouldUseSurface) {
|
||||
const auto srcId = imageDescription->id();
|
||||
const auto dstId = targetImageDescription->id();
|
||||
void* sPtr = m_renderData.surface.get();
|
||||
void* sPtr = shouldUseSurface ? m_renderData.surface.get() : nullptr;
|
||||
|
||||
for (auto const& entry : m_cmSettingsCache) {
|
||||
if (entry.srcDescId == srcId && entry.dstDescId == dstId && entry.surfacePtr == sPtr && entry.modifySDR == modifySDR && entry.sdrMinLuminance == sdrMinLuminance &&
|
||||
|
|
@ -1793,7 +1794,8 @@ SCMSettings IHyprRenderer::getCMSettings(const NColorManagement::PImageDescripti
|
|||
const auto sdrEOTF = NTransferFunction::fromConfig();
|
||||
NColorManagement::eTransferFunction srcTF;
|
||||
|
||||
if (m_renderData.surface.valid()) {
|
||||
if (shouldUseSurface && m_renderData.surface.valid() &&
|
||||
(imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_GAMMA22 || imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_SRGB)) {
|
||||
if (m_renderData.surface->m_colorManagement.valid()) {
|
||||
if (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && imageDescription->value().transferFunction == NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB)
|
||||
srcTF = NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22;
|
||||
|
|
@ -1842,7 +1844,15 @@ SCMSettings IHyprRenderer::getCMSettings(const NColorManagement::PImageDescripti
|
|||
.sdrBrightnessMultiplier = needsSDRmod && m_renderData.pMonitor->m_sdrBrightness > 0 ? m_renderData.pMonitor->m_sdrBrightness : 1.0f,
|
||||
};
|
||||
|
||||
m_cmSettingsCache.push_back({srcId, dstId, sPtr, modifySDR, sdrMinLuminance, sdrMaxLuminance, result});
|
||||
m_cmSettingsCache.push_back({
|
||||
.srcDescId = srcId,
|
||||
.dstDescId = dstId,
|
||||
.surfacePtr = sPtr,
|
||||
.modifySDR = modifySDR,
|
||||
.sdrMinLuminance = sdrMinLuminance,
|
||||
.sdrMaxLuminance = sdrMaxLuminance,
|
||||
.settings = result,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1937,11 +1947,16 @@ void IHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
|
|||
|
||||
if (canAttemptDirectScanout) {
|
||||
if (pMonitor->attemptDirectScanout()) {
|
||||
pMonitor->m_directScanoutIsActive = true;
|
||||
if (!pMonitor->m_directScanoutIsActive) {
|
||||
pMonitor->m_previousFSWindow.reset(); // recalc fs settings
|
||||
pMonitor->m_directScanoutIsActive = true;
|
||||
}
|
||||
handleFullscreenSettings(pMonitor);
|
||||
return;
|
||||
} else if (!pMonitor->m_lastScanout.expired() || pMonitor->m_directScanoutIsActive) {
|
||||
Log::logger->log(Log::DEBUG, "Left a direct scanout.");
|
||||
pMonitor->m_lastScanout.reset();
|
||||
pMonitor->m_previousFSWindow.reset(); // recalc fs settings
|
||||
pMonitor->m_directScanoutIsActive = false;
|
||||
|
||||
// reset DRM format, but only if needed since it might modeset
|
||||
|
|
@ -2183,11 +2198,11 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, S
|
|||
};
|
||||
}
|
||||
|
||||
bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
||||
void IHyprRenderer::handleFullscreenSettings(PHLMONITOR pMonitor) {
|
||||
static auto PCT = CConfigValue<Hyprlang::INT>("render:send_content_type");
|
||||
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
||||
static auto PAUTOHDR = CConfigValue<Hyprlang::INT>("render:cm_auto_hdr");
|
||||
static auto PNONSHADER = CConfigValue<Hyprlang::INT>("render:non_shader_cm");
|
||||
static auto PNSINTEROP = CConfigValue<Hyprlang::INT>("render:non_shader_cm_interop");
|
||||
|
||||
const bool configuredHDR = (pMonitor->m_cmType == NCMType::CM_HDR_EDID || pMonitor->m_cmType == NCMType::CM_HDR);
|
||||
bool wantHDR = configuredHDR;
|
||||
|
|
@ -2198,14 +2213,6 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
|||
// HDR metadata determined by
|
||||
// HDR scRGB - monitor settings
|
||||
// HDR PQ surface & DS is active - surface settings
|
||||
// PPASS = 0 monitor settings
|
||||
// PPASS = 1
|
||||
// windowed: monitor settings
|
||||
// fullscreen surface: surface settings FIXME: fullscreen SDR surface passthrough - pass degamma, gamma if needed
|
||||
// PPASS = 2
|
||||
// windowed: monitor settings
|
||||
// fullscreen SDR surface: monitor settings
|
||||
// fullscreen HDR surface: surface settings
|
||||
|
||||
bool hdrIsHandled = false;
|
||||
if (FS_WINDOW) {
|
||||
|
|
@ -2215,8 +2222,9 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
|||
// we have a surface with image description
|
||||
if (SURF && SURF->m_colorManagement.valid() && SURF->m_colorManagement->hasImageDescription()) {
|
||||
const bool surfaceIsHDR = SURF->m_colorManagement->isHDR();
|
||||
if (!SURF->m_colorManagement->isWindowsScRGB() && (*PPASS == 1 || ((*PPASS == 2 || !pMonitor->m_lastScanout.expired()) && surfaceIsHDR))) {
|
||||
// passthrough
|
||||
wantHDR = *PAUTOHDR && surfaceIsHDR;
|
||||
if (surfaceIsHDR && !SURF->m_colorManagement->isWindowsScRGB() && !pMonitor->m_lastScanout.expired()) {
|
||||
// DS HDR
|
||||
bool needsHdrMetadataUpdate = SURF->m_colorManagement->needsHdrMetadataUpdate() || pMonitor->m_previousFSWindow != FS_WINDOW || pMonitor->m_needsHDRupdate;
|
||||
if (SURF->m_colorManagement->needsHdrMetadataUpdate()) {
|
||||
Log::logger->log(Log::INFO, "[CM] Recreating HDR metadata for surface");
|
||||
|
|
@ -2228,8 +2236,7 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
|||
}
|
||||
hdrIsHandled = true;
|
||||
pMonitor->m_needsHDRupdate = false;
|
||||
} else if (*PAUTOHDR && surfaceIsHDR)
|
||||
wantHDR = true; // auto-hdr: hdr on
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2271,28 +2278,50 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
|||
if (*PCT)
|
||||
pMonitor->m_output->state->setContentType(NContentType::toDRM(FS_WINDOW ? FS_WINDOW->getContentType() : CONTENT_TYPE_NONE));
|
||||
|
||||
if (FS_WINDOW != pMonitor->m_previousFSWindow || (!FS_WINDOW && pMonitor->m_noShaderCTM)) {
|
||||
if (*PNONSHADER == CM_NS_IGNORE || !FS_WINDOW || !pMonitor->needsCM() || !pMonitor->canNoShaderCM() ||
|
||||
(*PNONSHADER == CM_NS_ONDEMAND && pMonitor->m_lastScanout.expired() && *PPASS != 1)) {
|
||||
if (pMonitor->m_noShaderCTM) {
|
||||
Log::logger->log(Log::INFO, "[CM] No fullscreen CTM, restoring previous one");
|
||||
pMonitor->m_noShaderCTM = false;
|
||||
pMonitor->m_ctmUpdated = true;
|
||||
}
|
||||
} else {
|
||||
const auto FS_DESC = pMonitor->getFSImageDescription();
|
||||
if (FS_DESC.has_value()) {
|
||||
if (FS_WINDOW != pMonitor->m_previousFSWindow || (!FS_WINDOW && pMonitor->m_noShaderCTM) || pMonitor->m_ctmUpdated) {
|
||||
const bool INTEROP = (*PNSINTEROP == 1 || (*PNSINTEROP == 2 && FS_WINDOW && FS_WINDOW->getContentType() == CONTENT_TYPE_NONE));
|
||||
bool resetCTM = !FS_WINDOW;
|
||||
if (FS_WINDOW) {
|
||||
if (*PNONSHADER == CM_NS_IGNORE)
|
||||
resetCTM = true;
|
||||
else if (const auto FS_DESC = pMonitor->getFSImageDescription(); pMonitor->needsCM() && pMonitor->canNoShaderCM(!pMonitor->m_lastScanout.expired()) &&
|
||||
FS_DESC.has_value() && (*PNONSHADER != CM_NS_ONDEMAND || !pMonitor->m_lastScanout.expired())) {
|
||||
Log::logger->log(Log::INFO, "[CM] Updating fullscreen CTM");
|
||||
pMonitor->m_noShaderCTM = true;
|
||||
auto conversion = FS_DESC.value()->getPrimaries()->convertMatrix(pMonitor->m_imageDescription->getPrimaries());
|
||||
const auto mat = conversion.mat();
|
||||
const std::array<float, 9> CTM = {
|
||||
pMonitor->m_noShaderCTM = true;
|
||||
pMonitor->m_ctmUpdated = false;
|
||||
auto conversion = FS_DESC.value()->getPrimaries()->convertMatrix(pMonitor->m_imageDescription->getPrimaries());
|
||||
if (pMonitor->m_ctm != Mat3x3::identity() && INTEROP) {
|
||||
const auto& ctm = pMonitor->m_ctm.getMatrix();
|
||||
std::array<std::array<double, 3>, 3> values = {
|
||||
{
|
||||
{ctm[0], ctm[1], ctm[2]},
|
||||
{ctm[3], ctm[4], ctm[5]},
|
||||
{ctm[6], ctm[7], ctm[8]},
|
||||
},
|
||||
};
|
||||
conversion = conversion * Hyprgraphics::CMatrix3(values);
|
||||
}
|
||||
const auto mat = conversion.mat();
|
||||
const std::array<float, 9> CTM = {
|
||||
mat[0][0], mat[0][1], mat[0][2], //
|
||||
mat[1][0], mat[1][1], mat[1][2], //
|
||||
mat[2][0], mat[2][1], mat[2][2], //
|
||||
};
|
||||
pMonitor->m_output->state->setCTM(CTM);
|
||||
}
|
||||
} else if (!INTEROP && pMonitor->m_ctm != Mat3x3::identity()) {
|
||||
Log::logger->log(Log::INFO, "[CM] Setting identity CTM");
|
||||
pMonitor->m_noShaderCTM = true;
|
||||
pMonitor->m_ctmUpdated = false;
|
||||
|
||||
pMonitor->m_output->state->setCTM(Mat3x3::identity());
|
||||
} else
|
||||
resetCTM = true;
|
||||
}
|
||||
|
||||
if (resetCTM && pMonitor->m_noShaderCTM) {
|
||||
Log::logger->log(Log::INFO, "[CM] No fullscreen CTM, restoring previous one");
|
||||
pMonitor->m_noShaderCTM = false;
|
||||
pMonitor->m_ctmUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2302,6 +2331,10 @@ bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
|||
}
|
||||
|
||||
pMonitor->m_previousFSWindow = FS_WINDOW;
|
||||
}
|
||||
|
||||
bool IHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
||||
handleFullscreenSettings(pMonitor);
|
||||
|
||||
bool ok = pMonitor->m_state.commit();
|
||||
if (!ok) {
|
||||
|
|
|
|||
|
|
@ -190,7 +190,8 @@ namespace Render {
|
|||
void preBlurForCurrentMonitor(CRegion* fakeDamage);
|
||||
|
||||
SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
|
||||
SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
|
||||
SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1,
|
||||
bool shouldUseSurface = false);
|
||||
void clearCMSettingsCache();
|
||||
virtual bool reloadShaders(const std::string& path = "") = 0;
|
||||
|
||||
|
|
@ -234,6 +235,8 @@ namespace Render {
|
|||
bool m_monitorTransformEnabled = false; // do not modify directly
|
||||
std::stack<bool> m_monitorTransformStack;
|
||||
|
||||
void handleFullscreenSettings(PHLMONITOR pMonitor);
|
||||
|
||||
// old private:
|
||||
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
|
||||
void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue