use a better work space, not linear, only for sdr

This commit is contained in:
Vaxry 2026-04-24 19:48:46 +01:00 committed by UjinT34
parent 158f580983
commit 19175706eb
13 changed files with 77 additions and 98 deletions

View file

@ -2549,9 +2549,29 @@ bool CMonitor::useFP16() {
return shouldUse;
}
PImageDescription CMonitor::workBufferImageDescription() {
if (!useFP16())
return m_imageDescription;
const auto& value = m_imageDescription->value();
const bool isHDRLikeTF =
value.transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ || value.transferFunction == CM_TRANSFER_FUNCTION_HLG || value.transferFunction == CM_TRANSFER_FUNCTION_EXT_LINEAR;
if (isHDRLikeTF || value.windowsScRGB)
return LINEAR_IMAGE_DESCRIPTION;
return CImageDescription::from(SImageDescription{
.transferFunction = chooseTF(m_sdrEotf),
.primariesNameSet = true,
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
.primaries = NColorPrimaries::BT2020,
});
}
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;
const auto DESC = workBufferImageDescription();
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, DESC);

View file

@ -393,10 +393,11 @@ class CMonitor {
return m_position == rhs.m_position && m_size == rhs.m_size && m_name == rhs.m_name;
}
bool needsACopyFB();
bool needsUnmodifiedCopy();
bool useFP16();
WP<Monitor::CMonitorResources> resources();
bool needsACopyFB();
bool needsUnmodifiedCopy();
bool useFP16();
NColorManagement::PImageDescription workBufferImageDescription();
WP<Monitor::CMonitorResources> resources();
private:
void updateMatrix();

View file

@ -32,7 +32,7 @@ void CMonitorResources::setImageDescription(NColorManagement::PImageDescription
for (const auto& res : m_workBuffers)
res.buffer->setImageDescription(imageDescription);
if (m_monitorMirrorFB)
m_monitorMirrorFB->setImageDescription(NColorManagement::getDefaultImageDescription());
m_monitorMirrorFB->setImageDescription(getMirrorTexImageDescription());
if (m_mirrorTex)
m_mirrorTex->m_imageDescription = getMirrorTexImageDescription();
}
@ -78,8 +78,8 @@ SP<Render::IFramebuffer> CMonitorResources::mirrorFB() {
m_monitorMirrorFB = g_pHyprRenderer->createFB(std::format("Monitor {} mirror FB", m_monitor->m_name));
if (!m_monitorMirrorFB->isAllocated()) {
m_monitorMirrorFB->alloc(m_size.x, m_size.y, DRM_FORMAT_XRGB8888);
m_monitorMirrorFB->setImageDescription(NColorManagement::getDefaultImageDescription());
m_monitorMirrorFB->alloc(m_size.x, m_size.y, m_monitor->m_activeMonitorRule.m_enable10bit ? DRM_FORMAT_XRGB2101010 : DRM_FORMAT_XRGB8888);
m_monitorMirrorFB->setImageDescription(getMirrorTexImageDescription());
}
return m_monitorMirrorFB;
@ -90,20 +90,16 @@ SP<Render::ITexture> CMonitorResources::getMirrorTexture() {
}
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,
.luminances = {.min = SDR_MIN_LUMINANCE, .max = 80, .reference = 80},
});
if (!m_monitor)
return DEFAULT_SRGB_IMAGE_DESCRIPTION;
return m_monitor->workBufferImageDescription();
}
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->allocate({m_size.x, m_size.y}, m_monitor->m_activeMonitorRule.m_enable10bit ? DRM_FORMAT_XRGB2101010 : DRM_FORMAT_XRGB8888);
m_mirrorTex->m_imageDescription = getMirrorTexImageDescription();
m_monitor->m_blurFBDirty = true;
}

View file

@ -196,11 +196,10 @@ void CScreenshareFrame::renderMonitor() {
g_pHyprRenderer->startRenderPass();
g_pHyprRenderer->draw(
CTexPassElement::SRenderData{
.tex = TEXTURE,
.box = monbox,
.flipEndFrame = true,
.cmBackToSRGB = !IS_CM_AWARE,
.cmBackToSRGBSource = !IS_CM_AWARE ? PMONITOR : nullptr,
.tex = TEXTURE,
.box = monbox,
.flipEndFrame = true,
.cmBackToSRGB = !IS_CM_AWARE,
},
{0, 0, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y});
g_pHyprRenderer->m_renderData.renderModif.enabled = OLD;

View file

@ -1298,7 +1298,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
shaderFeatures &= ~SH_FEAT_RGBA;
const auto surface = g_pHyprRenderer->m_renderData.surface;
const auto WORK_BUFFER_IMAGE_DESCRIPTION = g_pHyprRenderer->workBufferImageDescription();
const auto WORK_BUFFER_IMAGE_DESCRIPTION = g_pHyprRenderer->m_renderData.pMonitor->workBufferImageDescription();
// chosenSdrEotf contains the valid eotf for this display
@ -1311,7 +1311,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
return CImageDescription::from(surface->m_colorManagement->imageDescription());
if (data.cmBackToSRGB)
return g_pHyprRenderer->m_renderData.pMonitor->m_imageDescription;
return tex->m_imageDescription ? tex->m_imageDescription : WORK_BUFFER_IMAGE_DESCRIPTION;
// otherwise, if we are CM'ing back into source, use chosen, because that's what our work buffer is in
// the same applies to the final monitor CM
@ -1349,14 +1349,6 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STexture
|| !SOURCE_IMAGE_DESCRIPTION->needsCM(TARGET_IMAGE_DESCRIPTION) /* Source and target have matching image descriptions */
;
const auto sourceTF = SOURCE_IMAGE_DESCRIPTION->value().transferFunction;
const bool sourceIsUnmanagedSDRSurface = surface.valid() && !surface->m_colorManagement.valid() &&
(sourceTF == CM_TRANSFER_FUNCTION_SRGB || sourceTF == CM_TRANSFER_FUNCTION_GAMMA22 || sourceTF == CM_TRANSFER_FUNCTION_EXT_SRGB || sourceTF == CM_TRANSFER_FUNCTION_BT1886);
const bool targetIsLinearWorkBuffer = TARGET_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_EXT_LINEAR;
if (!skipCM && !data.finalMonitorCM && !data.cmBackToSRGB && sourceIsUnmanagedSDRSurface && targetIsLinearWorkBuffer)
shaderFeatures |= SH_FEAT_SDR_PREMUL_COMPAT;
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());
@ -2395,7 +2387,8 @@ void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
Log::logger->log(Log::ERR, "Invalid source texture for mirror");
return;
}
auto guard = g_pHyprRenderer->bindTempFB(g_pHyprRenderer->m_renderData.pMonitor->resources()->mirrorFB());
auto fb = g_pHyprRenderer->m_renderData.pMonitor->resources()->mirrorFB();
auto guard = g_pHyprRenderer->bindTempFB(fb);
Log::logger->log(Log::TRACE, "CM: saveBufferForMirror {} -> {}", TEX->m_imageDescription->value(), g_pHyprRenderer->m_renderData.currentFB->imageDescription()->value());
@ -2408,7 +2401,6 @@ void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
.round = 0,
.discardActive = false,
.allowCustomUV = false,
.cmBackToSRGB = true,
});
blend(true);

View file

@ -174,7 +174,6 @@ namespace Render::GL {
GLenum wrapX = GL_CLAMP_TO_EDGE, wrapY = GL_CLAMP_TO_EDGE;
bool cmBackToSRGB = false;
bool finalMonitorCM = false;
SP<CMonitor> cmBackToSRGBSource;
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;

View file

@ -3270,17 +3270,10 @@ void IHyprRenderer::renderSnapshot(WP<Desktop::View::CPopup> popup) {
}
NColorManagement::PImageDescription IHyprRenderer::workBufferImageDescription() {
// TODO
// const bool IS_MONITOR_ICC = m_renderData.pMonitor->m_imageDescription.valid() && m_renderData.pMonitor->m_imageDescription->value().icc.present;
// const auto sdrEOTF = NTransferFunction::fromConfig(IS_MONITOR_ICC);
// const auto CHOSEN_SDR_EOTF = sdrEOTF != NTransferFunction::TF_SRGB ? NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 : NColorManagement::CM_TRANSFER_FUNCTION_SRGB;
if (!m_renderData.pMonitor)
return LINEAR_IMAGE_DESCRIPTION;
return m_renderData.pMonitor->useFP16() ?
LINEAR_IMAGE_DESCRIPTION :
m_renderData.pMonitor->m_imageDescription; //CImageDescription::from(NColorManagement::SImageDescription{.transferFunction = CHOSEN_SDR_EOTF});
return m_renderData.pMonitor->workBufferImageDescription();
}
bool IHyprRenderer::shouldBlur(PHLLS ls) {

View file

@ -67,17 +67,10 @@ void CShaderLoader::include(const std::string& filename) {
std::string CShaderLoader::getDefines(ShaderFeatureFlags features) {
std::string res = "";
std::map<std::string, std::string> defines = {
{"USE_RGBA", features & SH_FEAT_RGBA ? "1" : "0"},
{"USE_DISCARD", features & SH_FEAT_DISCARD ? "1" : "0"},
{"USE_TINT", features & SH_FEAT_TINT ? "1" : "0"},
{"USE_ROUNDING", features & SH_FEAT_ROUNDING ? "1" : "0"},
{"USE_CM", features & SH_FEAT_CM ? "1" : "0"},
{"USE_TONEMAP", features & SH_FEAT_TONEMAP ? "1" : "0"},
{"USE_SDR_MOD", features & SH_FEAT_SDR_MOD ? "1" : "0"},
{"USE_BLUR", features & SH_FEAT_BLUR ? "1" : "0"},
{"USE_ICC", features & SH_FEAT_ICC ? "1" : "0"},
{"USE_RGBA", features & SH_FEAT_RGBA ? "1" : "0"}, {"USE_DISCARD", features & SH_FEAT_DISCARD ? "1" : "0"}, {"USE_TINT", features & SH_FEAT_TINT ? "1" : "0"},
{"USE_ROUNDING", features & SH_FEAT_ROUNDING ? "1" : "0"}, {"USE_CM", features & SH_FEAT_CM ? "1" : "0"}, {"USE_TONEMAP", features & SH_FEAT_TONEMAP ? "1" : "0"},
{"USE_SDR_MOD", features & SH_FEAT_SDR_MOD ? "1" : "0"}, {"USE_BLUR", features & SH_FEAT_BLUR ? "1" : "0"}, {"USE_ICC", features & SH_FEAT_ICC ? "1" : "0"},
{"USE_MIRROR", features & SH_FEAT_MIRROR ? "1" : "0"},
{"USE_SDR_PREMUL_COMPAT", features & SH_FEAT_SDR_PREMUL_COMPAT ? "1" : "0"},
};
for (const auto& [name, value] : defines) {
res += std::format("#define {} {}\n", name, value);

View file

@ -11,17 +11,16 @@ namespace Render {
enum ePreparedFragmentShaderFeature : uint16_t {
SH_FEAT_UNKNOWN = 0, // all features just in case
SH_FEAT_RGBA = (1 << 0), // RGBA/RGBX texture sampling
SH_FEAT_DISCARD = (1 << 1), // RGBA/RGBX texture sampling
SH_FEAT_TINT = (1 << 2), // uniforms: tint; condition: applyTint
SH_FEAT_ROUNDING = (1 << 3), // uniforms: radius, roundingPower, topLeft, fullSize; condition: radius > 0
SH_FEAT_CM = (1 << 4), // uniforms: srcTFRange, dstTFRange, srcRefLuminance, convertMatrix; condition: !skipCM
SH_FEAT_TONEMAP = (1 << 5), // uniforms: maxLuminance, dstMaxLuminance, dstRefLuminance; condition: maxLuminance < dstMaxLuminance * 1.01
SH_FEAT_SDR_MOD = (1 << 6), // uniforms: sdrSaturation, sdrBrightnessMultiplier; condition: SDR <-> HDR && (sdrSaturation != 1 || sdrBrightnessMultiplier != 1)
SH_FEAT_BLUR = (1 << 7), // condition: render:use_shader_blur_blend
SH_FEAT_ICC = (1 << 8), //
SH_FEAT_MIRROR = (1 << 9), // condition: mirror or screenshare
SH_FEAT_SDR_PREMUL_COMPAT = (1 << 10), // condition: unmanaged SDR surfaces drawn into linear workbuffer
SH_FEAT_RGBA = (1 << 0), // RGBA/RGBX texture sampling
SH_FEAT_DISCARD = (1 << 1), // RGBA/RGBX texture sampling
SH_FEAT_TINT = (1 << 2), // uniforms: tint; condition: applyTint
SH_FEAT_ROUNDING = (1 << 3), // uniforms: radius, roundingPower, topLeft, fullSize; condition: radius > 0
SH_FEAT_CM = (1 << 4), // uniforms: srcTFRange, dstTFRange, srcRefLuminance, convertMatrix; condition: !skipCM
SH_FEAT_TONEMAP = (1 << 5), // uniforms: maxLuminance, dstMaxLuminance, dstRefLuminance; condition: maxLuminance < dstMaxLuminance * 1.01
SH_FEAT_SDR_MOD = (1 << 6), // uniforms: sdrSaturation, sdrBrightnessMultiplier; condition: SDR <-> HDR && (sdrSaturation != 1 || sdrBrightnessMultiplier != 1)
SH_FEAT_BLUR = (1 << 7), // condition: render:use_shader_blur_blend
SH_FEAT_ICC = (1 << 8), //
SH_FEAT_MIRROR = (1 << 9), // condition: mirror or screenshare
// uniforms: targetPrimariesXYZ; condition: SH_FEAT_TONEMAP || SH_FEAT_SDR_MOD
};

View file

@ -114,19 +114,18 @@ void CGLElementRenderer::draw(WP<CTexPassElement> element, const CRegion& damage
.blurredBG = m_data.blurredBG,
// common settings
.damage = m_data.damage.empty() ? &damage : &m_data.damage,
.surface = m_data.surface,
.a = m_data.a,
.round = m_data.round,
.roundingPower = m_data.roundingPower,
.discardActive = m_data.discardActive,
.allowCustomUV = m_data.allowCustomUV,
.cmBackToSRGB = m_data.cmBackToSRGB,
.cmBackToSRGBSource = m_data.cmBackToSRGBSource,
.discardMode = m_data.ignoreAlpha.has_value() ? sc<uint32_t>(DISCARD_ALPHA) : m_data.discardMode,
.discardOpacity = m_data.ignoreAlpha.has_value() ? *m_data.ignoreAlpha : m_data.discardOpacity,
.clipRegion = m_data.clipRegion,
.currentLS = m_data.currentLS,
.damage = m_data.damage.empty() ? &damage : &m_data.damage,
.surface = m_data.surface,
.a = m_data.a,
.round = m_data.round,
.roundingPower = m_data.roundingPower,
.discardActive = m_data.discardActive,
.allowCustomUV = m_data.allowCustomUV,
.cmBackToSRGB = m_data.cmBackToSRGB,
.discardMode = m_data.ignoreAlpha.has_value() ? sc<uint32_t>(DISCARD_ALPHA) : m_data.discardMode,
.discardOpacity = m_data.ignoreAlpha.has_value() ? *m_data.ignoreAlpha : m_data.discardOpacity,
.clipRegion = m_data.clipRegion,
.currentLS = m_data.currentLS,
.primarySurfaceUVTopLeft = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft,
.primarySurfaceUVBottomRight = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight,

View file

@ -31,7 +31,6 @@ class CTexPassElement : public IPassElement {
std::optional<float> ignoreAlpha;
std::optional<bool> blockBlurOptimization;
bool cmBackToSRGB = false;
SP<CMonitor> cmBackToSRGBSource;
bool discardActive = false;
bool allowCustomUV = false;

View file

@ -224,25 +224,15 @@ vec4
#endif
#endif
) {
#if USE_SDR_PREMUL_COMPAT
// Compatibility path for unmanaged SDR translucent surfaces rendered into a linear workbuffer.
// Keep premultiplication during source TF decoding to avoid low-alpha hue/opacity drift.
pixColor.rgb = toLinearRGB(pixColor.rgb, srcTF);
#else
pixColor.rgb /= max(pixColor.a, 0.001);
pixColor.rgb = toLinearRGB(pixColor.rgb, srcTF);
#endif
#if USE_ICC
pixColor.rgb = applyIcc3DLut(pixColor.rgb, iccLut3D, iccLutSize);
pixColor.rgb *= pixColor.a;
#else
pixColor.rgb = convertMatrix * pixColor.rgb;
#if USE_SDR_PREMUL_COMPAT
pixColor.rgb = pixColor.rgb * (srcTFRange[1] - srcTFRange[0]) + srcTFRange[0] * pixColor.a;
#else
pixColor = toNit(pixColor, srcTFRange);
pixColor.rgb *= pixColor.a;
#endif
#if USE_TONEMAP
pixColor = tonemap(pixColor, dstxyz, maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance);
#endif

View file

@ -2,14 +2,13 @@
// Values here are only for highlighting and static checking
// 1 assumes that a shader either supports this feature or doesn't use any code supporting it
// 0 assumes that shader uses some code supporting the feature but will never have this feature enabled
#define USE_RGBA 1
#define USE_DISCARD 1
#define USE_TINT 1
#define USE_ROUNDING 1
#define USE_CM 1
#define USE_TONEMAP 1
#define USE_SDR_MOD 1
#define USE_BLUR 1
#define USE_ICC 0
#define USE_MIRROR 0
#define USE_SDR_PREMUL_COMPAT 1
#define USE_RGBA 1
#define USE_DISCARD 1
#define USE_TINT 1
#define USE_ROUNDING 1
#define USE_CM 1
#define USE_TONEMAP 1
#define USE_SDR_MOD 1
#define USE_BLUR 1
#define USE_ICC 0
#define USE_MIRROR 0