mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-14 06:58:04 +02:00
Merge 5cfa6fcf9f into 6dc42e0f6d
This commit is contained in:
commit
30367f272c
27 changed files with 569 additions and 262 deletions
|
|
@ -349,6 +349,7 @@
|
|||
---| "render.ctm_animation"
|
||||
---| "render.direct_scanout"
|
||||
---| "render.expand_undersized_textures"
|
||||
---| "render.fp16_sdr_tf"
|
||||
---| "render.icc_vcgt_enabled"
|
||||
---| "render.keep_unmodified_copy"
|
||||
---| "render.new_render_scheduling"
|
||||
|
|
@ -1185,6 +1186,7 @@ hl = {}
|
|||
---@field ['render.ctm_animation'] integer|boolean
|
||||
---@field ['render.direct_scanout'] integer|boolean
|
||||
---@field ['render.expand_undersized_textures'] boolean
|
||||
---@field ['render.fp16_sdr_tf'] integer|boolean
|
||||
---@field ['render.icc_vcgt_enabled'] boolean
|
||||
---@field ['render.keep_unmodified_copy'] integer|boolean
|
||||
---@field ['render.new_render_scheduling'] boolean
|
||||
|
|
|
|||
|
|
@ -540,6 +540,8 @@ std::vector<SP<IValue>> Values::getConfigValues() {
|
|||
{.min = 0, .max = 2, .map = OptionMap{{"disable", 0}, {"enable", 1}, {"auto", 2}}}),
|
||||
MS<Int>("render:non_shader_cm_interop", "non_shader_cm interaction with ctm proto (hyprsunset and similar).", 2,
|
||||
{.min = 0, .max = 2, .map = OptionMap{{"disable", 0}, {"enable", 1}, {"auto", 2}}}),
|
||||
MS<Int>("render:fp16_sdr_tf", "Internal workbuffer transfer function for fp16 in SDR mode", 0,
|
||||
{.min = 0, .max = 2, .map = OptionMap{{"default", 0}, {"linear", 1}, {"monitor", 2}}}),
|
||||
|
||||
/*
|
||||
* cursor:
|
||||
|
|
@ -604,7 +606,7 @@ std::vector<SP<IValue>> Values::getConfigValues() {
|
|||
MS<Bool>("debug:fifo_pending_workaround", "Fifo workaround for empty pending list", false),
|
||||
MS<Bool>("debug:render_solitary_wo_damage", "Render solitary window with empty damage", false),
|
||||
MS<Bool>("debug:vfr", "controls the VFR status of Hyprland. Do not turn off unless debugging", true),
|
||||
MS<Int>("debug:invalidate_fp16", "allow fp16 buffer invalidation.", 2, {.min = 0, .max = 2, .map = OptionMap{{"disable", 0}, {"enable", 1}, {"auto", 2}}}),
|
||||
MS<Int>("debug:invalidate_fp16", "allow fp16 buffer invalidation.", 1, {.min = 0, .max = 2, .map = OptionMap{{"disable", 0}, {"enable", 1}, {"auto", 2}}}),
|
||||
|
||||
/*
|
||||
* layout:
|
||||
|
|
|
|||
|
|
@ -617,6 +617,7 @@ void CMonitor::applyCMType(NCMType::eCMType cmType, NTransferFunction::eTF cmSdr
|
|||
if (oldImageDescription != m_imageDescription) {
|
||||
if (PROTO::colorManagement)
|
||||
PROTO::colorManagement->onMonitorImageDescriptionChanged(m_self);
|
||||
m_blurFBDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2063,6 +2064,20 @@ bool CMonitor::attemptDirectScanout() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void CMonitor::handleDSleave() {
|
||||
Log::logger->log(Log::DEBUG, "Left a direct scanout.");
|
||||
m_lastScanout.reset();
|
||||
m_previousFSWindow.reset(); // recalc fs settings
|
||||
m_directScanoutIsActive = false;
|
||||
|
||||
// reset DRM format, but only if needed since it might modeset
|
||||
if (m_output->state->state().drmFormat != m_prevDrmFormat)
|
||||
m_output->state->setFormat(m_prevDrmFormat);
|
||||
|
||||
m_drmFormat = m_prevDrmFormat;
|
||||
m_blurFBDirty = true;
|
||||
}
|
||||
|
||||
bool CMonitor::canAttemptDirectScanoutFast() const {
|
||||
return !m_solitaryClient.expired() || !m_lastScanout.expired() || m_directScanoutIsActive;
|
||||
}
|
||||
|
|
@ -2549,9 +2564,42 @@ bool CMonitor::useFP16() {
|
|||
return shouldUse;
|
||||
}
|
||||
|
||||
PImageDescription CMonitor::workBufferImageDescription() {
|
||||
static const auto PFP16TF = CConfigValue<Hyprlang::INT>("render:fp16_sdr_tf");
|
||||
|
||||
if (!useFP16() && !m_imageDescription->value().icc.present)
|
||||
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;
|
||||
|
||||
const auto& cached = m_cachedInternalDescription->value();
|
||||
|
||||
// HDR
|
||||
if (isHDRLikeTF || value.windowsScRGB || *PFP16TF != 2) {
|
||||
if (cached.transferFunction != LINEAR_IMAGE_DESCRIPTION->value().transferFunction || cached.luminances != value.luminances)
|
||||
m_cachedInternalDescription = LINEAR_IMAGE_DESCRIPTION->with(value.luminances);
|
||||
return m_cachedInternalDescription;
|
||||
}
|
||||
|
||||
// SDR
|
||||
if (cached.transferFunction != chooseTF(m_sdrEotf))
|
||||
m_cachedInternalDescription = CImageDescription::from(SImageDescription{
|
||||
.transferFunction = chooseTF(m_sdrEotf),
|
||||
.primariesNameSet = true,
|
||||
// render:keep_unmodified_copy and other conditions that trigger MRT for screen sharing expect a work buffer with sRGB primaries
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB,
|
||||
.primaries = NColorPrimaries::BT709,
|
||||
});
|
||||
|
||||
return m_cachedInternalDescription;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -326,6 +326,7 @@ class CMonitor {
|
|||
bool updateTearing();
|
||||
uint16_t isDSBlocked(bool full = false);
|
||||
bool attemptDirectScanout();
|
||||
void handleDSleave();
|
||||
bool canAttemptDirectScanoutFast() const;
|
||||
bool isMultiGPU();
|
||||
void setCTM(const Mat3x3& ctm);
|
||||
|
|
@ -393,10 +394,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();
|
||||
|
|
@ -414,6 +416,9 @@ class CMonitor {
|
|||
|
||||
// Resources
|
||||
UP<Monitor::CMonitorResources> m_resources;
|
||||
// cached should contain one of predefined descriptions for FP16: sRGB primaries with either linear TF by default and in HDR mode or monitor's TF in SDR with render:fp16_sdr_tf = 2
|
||||
// avoids lookup for an id when ::from is used
|
||||
NColorManagement::PImageDescription m_cachedInternalDescription = NColorManagement::CImageDescription::from(NColorManagement::SImageDescription{});
|
||||
|
||||
struct {
|
||||
CHyprSignalListener frame;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
#include "ColorManagement.hpp"
|
||||
#include "../../macros.hpp"
|
||||
#include "helpers/TransferFunction.hpp"
|
||||
#include "../Color.hpp"
|
||||
#include "../TransferFunction.hpp"
|
||||
#include "../../render/Renderer.hpp"
|
||||
#include "render/types.hpp"
|
||||
#include <hyprutils/memory/UniquePtr.hpp>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
|
||||
using namespace NColorManagement;
|
||||
using namespace NTransferFunction;
|
||||
|
|
@ -208,6 +212,318 @@ Mat3x3 NColorManagement::adaptBradford(Hyprgraphics::CColor::xy srcW, Hyprgraphi
|
|||
return result;
|
||||
}
|
||||
|
||||
// sRGB constants
|
||||
#define SRGB_POW 2.4
|
||||
#define SRGB_CUT 0.0031308
|
||||
#define SRGB_SCALE 12.92
|
||||
#define SRGB_ALPHA 1.055
|
||||
|
||||
#define BT1886_POW (1.0 / 0.45)
|
||||
#define BT1886_CUT 0.018053968510807
|
||||
#define BT1886_SCALE 4.5
|
||||
#define BT1886_ALPHA (1.0 + 5.5 * BT1886_CUT)
|
||||
|
||||
// See http://car.france3.mars.free.fr/HD/INA-%2026%20jan%2006/SMPTE%20normes%20et%20confs/s240m.pdf
|
||||
#define ST240_POW (1.0 / 0.45)
|
||||
#define ST240_CUT 0.0228
|
||||
#define ST240_SCALE 4.0
|
||||
#define ST240_ALPHA 1.1115
|
||||
|
||||
#define ST428_POW 2.6
|
||||
#define ST428_SCALE (52.37 / 48.0)
|
||||
|
||||
// PQ constants
|
||||
#define PQ_M1 0.1593017578125
|
||||
#define PQ_M2 78.84375
|
||||
#define PQ_INV_M1 (1.0 / PQ_M1)
|
||||
#define PQ_INV_M2 (1.0 / PQ_M2)
|
||||
#define PQ_C1 0.8359375
|
||||
#define PQ_C2 18.8515625
|
||||
#define PQ_C3 18.6875
|
||||
|
||||
// HLG constants
|
||||
#define HLG_D_CUT (1.0 / 12.0)
|
||||
#define HLG_E_CUT 0.5
|
||||
#define HLG_A 0.17883277
|
||||
#define HLG_B 0.28466892
|
||||
#define HLG_C 0.55991073
|
||||
|
||||
static inline int sign(double value) {
|
||||
return value < 0 ? -1 : 1;
|
||||
}
|
||||
|
||||
// The primary source for these transfer functions is https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.1361-0-199802-W!!PDF-E.pdf
|
||||
static RGBAColor tfInvPQ(RGBAColor color) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
const double E = pow(std::clamp(color.v[i], 0.0, 1.0), PQ_INV_M2);
|
||||
color.v[i] = pow((std::max(E - PQ_C1, 0.0)) / (PQ_C2 - PQ_C3 * E), PQ_INV_M1);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tfInvHLG(RGBAColor color) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
const bool isLow = color.v[i] <= HLG_E_CUT;
|
||||
color.v[i] = isLow ? color.v[i] * color.v[i] / 3.0 : (exp((color.v[i] - HLG_C) / HLG_A) + HLG_B) / 12.0;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
// Many transfer functions (including sRGB) follow the same pattern: a linear
|
||||
// segment for small values and a power function for larger values. The
|
||||
// following function implements this pattern from which sRGB, BT.1886, and
|
||||
// others can be derived by plugging in the right constants.
|
||||
static RGBAColor tfInvLinPow(RGBAColor color, float gamma, float thres, float scale, float alpha) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
const bool isLow = color.v[i] <= thres * scale;
|
||||
color.v[i] = isLow ? color.v[i] / scale : pow((color.v[i] + alpha - 1.0) / alpha, gamma);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tfInvSRGB(RGBAColor color) {
|
||||
return tfInvLinPow(color, SRGB_POW, SRGB_CUT, SRGB_SCALE, SRGB_ALPHA);
|
||||
}
|
||||
|
||||
static RGBAColor tfInvExtSRGB(RGBAColor color) {
|
||||
// EXT sRGB is the sRGB transfer function mirrored around 0.
|
||||
const auto absColor = tfInvSRGB({{.r = abs(color.c.r), .g = abs(color.c.g), .b = abs(color.c.b), .a = color.c.a}});
|
||||
return {{
|
||||
.r = absColor.c.r * sign(color.c.r),
|
||||
.g = absColor.c.g * sign(color.c.g),
|
||||
.b = absColor.c.b * sign(color.c.b),
|
||||
.a = absColor.c.a,
|
||||
}};
|
||||
}
|
||||
|
||||
static RGBAColor tfInvBT1886(RGBAColor color) {
|
||||
return tfInvLinPow(color, BT1886_POW, BT1886_CUT, BT1886_SCALE, BT1886_ALPHA);
|
||||
}
|
||||
|
||||
static RGBAColor tfInvXVYCC(RGBAColor color) {
|
||||
// The inverse transfer function for XVYCC is the BT1886 transfer function mirrored around 0,
|
||||
// same as what EXT sRGB is to sRGB.
|
||||
const auto absColor = tfInvBT1886({{.r = abs(color.c.r), .g = abs(color.c.g), .b = abs(color.c.b), .a = color.c.a}});
|
||||
return {{
|
||||
.r = absColor.c.r * sign(color.c.r),
|
||||
.g = absColor.c.g * sign(color.c.g),
|
||||
.b = absColor.c.b * sign(color.c.b),
|
||||
.a = absColor.c.a,
|
||||
}};
|
||||
}
|
||||
|
||||
static RGBAColor tfInvST240(RGBAColor color) {
|
||||
return tfInvLinPow(color, ST240_POW, ST240_CUT, ST240_SCALE, ST240_ALPHA);
|
||||
}
|
||||
|
||||
// Forward transfer functions corresponding to the inverse functions above.
|
||||
static RGBAColor tfPQ(RGBAColor color) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
const double E = pow(std::clamp(color.v[i], 0.0, 1.0), PQ_M1);
|
||||
color.v[i] = pow((PQ_C1 + PQ_C2 * E) / (1.0 + PQ_C3 * E), PQ_M2);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tfHLG(RGBAColor color) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
const bool isLow = color.v[i] <= HLG_D_CUT;
|
||||
color.v[i] = isLow ? sqrt(std::max(color.v[i], 0.0) * 3.0) : HLG_A * log(std::max(12.0 * color.v[i] - HLG_B, 0.0001)) + HLG_C;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tfLinPow(RGBAColor color, float gamma, float thres, float scale, float alpha) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
const bool isLow = color.v[i] <= thres;
|
||||
color.v[i] = isLow ? color.v[i] * scale : pow(color.v[i], 1.0 / gamma) * alpha - (alpha - 1.0);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tfSRGB(RGBAColor color) {
|
||||
return tfLinPow(color, SRGB_POW, SRGB_CUT, SRGB_SCALE, SRGB_ALPHA);
|
||||
}
|
||||
|
||||
static RGBAColor tfExtSRGB(RGBAColor color) {
|
||||
// EXT sRGB is the sRGB transfer function mirrored around 0.
|
||||
const auto absColor = tfSRGB({{.r = abs(color.c.r), .g = abs(color.c.g), .b = abs(color.c.b), .a = color.c.a}});
|
||||
return {{
|
||||
.r = absColor.c.r * sign(color.c.r),
|
||||
.g = absColor.c.g * sign(color.c.g),
|
||||
.b = absColor.c.b * sign(color.c.b),
|
||||
.a = absColor.c.a,
|
||||
}};
|
||||
}
|
||||
|
||||
static RGBAColor tfBT1886(RGBAColor color) {
|
||||
return tfLinPow(color, BT1886_POW, BT1886_CUT, BT1886_SCALE, BT1886_ALPHA);
|
||||
}
|
||||
|
||||
static RGBAColor tfXVYCC(RGBAColor color) {
|
||||
// The transfer function for XVYCC is the BT1886 transfer function mirrored around 0,
|
||||
// same as what EXT sRGB is to sRGB.
|
||||
const auto absColor = tfBT1886({{.r = abs(color.c.r), .g = abs(color.c.g), .b = abs(color.c.b), .a = color.c.a}});
|
||||
return {{
|
||||
.r = absColor.c.r * sign(color.c.r),
|
||||
.g = absColor.c.g * sign(color.c.g),
|
||||
.b = absColor.c.b * sign(color.c.b),
|
||||
.a = absColor.c.a,
|
||||
}};
|
||||
}
|
||||
|
||||
static RGBAColor tfST240(RGBAColor color) {
|
||||
return tfLinPow(color, ST240_POW, ST240_CUT, ST240_SCALE, ST240_ALPHA);
|
||||
}
|
||||
|
||||
static RGBAColor tfST428(RGBAColor color) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
color.v[i] = pow(std::max(color.v[i], 0.0), ST428_POW) * ST428_SCALE;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tfInvST428(RGBAColor color) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
color.v[i] = pow(std::max(color.v[i], 0.0) / ST428_SCALE, 1.0 / ST428_POW);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tfGamma(RGBAColor color, float gamma) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
color.v[i] = pow(std::max(color.v[i], 0.0), gamma);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tfLog(RGBAColor color, float mult) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
color.v[i] = color.v[i] <= 0 ? 0.0 : exp((color.v[i] - 1.0) * mult * std::numbers::ln10);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tfInvLog(RGBAColor color, float mult, float min) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
color.v[i] = color.v[i] <= min ? 0.0 : 1.0 + log(color.v[i]) / std::numbers::ln10 / mult;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor toLinearRGB(RGBAColor color, eTransferFunction tf) {
|
||||
switch (tf) {
|
||||
case CM_TRANSFER_FUNCTION_LINEAR: return color;
|
||||
case CM_TRANSFER_FUNCTION_EXT_LINEAR: return color;
|
||||
case CM_TRANSFER_FUNCTION_ST2084_PQ: return tfInvPQ(color);
|
||||
case CM_TRANSFER_FUNCTION_GAMMA22: return tfGamma(color, 2.2);
|
||||
case CM_TRANSFER_FUNCTION_GAMMA28: return tfGamma(color, 2.8);
|
||||
case CM_TRANSFER_FUNCTION_HLG: return tfInvHLG(color);
|
||||
case CM_TRANSFER_FUNCTION_EXT_SRGB: return tfInvExtSRGB(color);
|
||||
case CM_TRANSFER_FUNCTION_BT1886: return tfInvBT1886(color);
|
||||
case CM_TRANSFER_FUNCTION_ST240: return tfInvST240(color);
|
||||
case CM_TRANSFER_FUNCTION_LOG_100: return tfLog(color, 2.0);
|
||||
case CM_TRANSFER_FUNCTION_LOG_316: return tfLog(color, 2.5);
|
||||
case CM_TRANSFER_FUNCTION_XVYCC: return tfInvXVYCC(color);
|
||||
case CM_TRANSFER_FUNCTION_ST428: return tfST428(color);
|
||||
case CM_TRANSFER_FUNCTION_SRGB:
|
||||
default: return tfInvSRGB(color);
|
||||
}
|
||||
}
|
||||
|
||||
static RGBAColor fromLinearRGB(RGBAColor color, eTransferFunction tf) {
|
||||
switch (tf) {
|
||||
case CM_TRANSFER_FUNCTION_EXT_LINEAR: return color;
|
||||
case CM_TRANSFER_FUNCTION_ST2084_PQ: return tfPQ(color);
|
||||
case CM_TRANSFER_FUNCTION_GAMMA22: return tfGamma(color, 1.0 / 2.2);
|
||||
case CM_TRANSFER_FUNCTION_GAMMA28: return tfGamma(color, 1.0 / 2.8);
|
||||
case CM_TRANSFER_FUNCTION_HLG: return tfHLG(color);
|
||||
case CM_TRANSFER_FUNCTION_EXT_SRGB: return tfExtSRGB(color);
|
||||
case CM_TRANSFER_FUNCTION_BT1886: return tfBT1886(color);
|
||||
case CM_TRANSFER_FUNCTION_ST240: return tfST240(color);
|
||||
case CM_TRANSFER_FUNCTION_LOG_100: return tfInvLog(color, 2.0, 0.01);
|
||||
case CM_TRANSFER_FUNCTION_LOG_316: return tfInvLog(color, 2.5, sqrt(10.0) / 1000.0);
|
||||
case CM_TRANSFER_FUNCTION_XVYCC: return tfXVYCC(color);
|
||||
case CM_TRANSFER_FUNCTION_ST428: return tfInvST428(color);
|
||||
case CM_TRANSFER_FUNCTION_SRGB:
|
||||
default: return tfSRGB(color);
|
||||
}
|
||||
}
|
||||
|
||||
static RGBAColor toNit(RGBAColor color, Render::STFRange range) {
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
color.v[i] = color.v[i] * (range.max - range.min) + range.min;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor fromLinearNit(RGBAColor color, eTransferFunction tf, Render::STFRange range) {
|
||||
if (tf == CM_TRANSFER_FUNCTION_LINEAR)
|
||||
return color;
|
||||
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
color.v[i] = (color.v[i] - range.min * color.c.a) / (range.max - range.min);
|
||||
}
|
||||
color /= std::max(color.c.a, 0.001);
|
||||
color = fromLinearRGB(color, tf);
|
||||
color *= color.c.a;
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor saturate(RGBAColor color, std::array<std::array<double, 3>, 3> primaries, float saturation) {
|
||||
if (saturation == 1.0)
|
||||
return color;
|
||||
|
||||
std::array<double, 3> colorArr = {color.v[0], color.v[1], color.v[2]};
|
||||
std::array<double, 3> brightness = {primaries[1][0], primaries[1][1], primaries[1][2]};
|
||||
const auto Y = std::inner_product(colorArr.begin(), colorArr.end(), brightness.begin(), 0.0);
|
||||
for (uint i = 0; i <= 2; i++) {
|
||||
color.v[i] = (color.v[i] * saturation) + (Y * (1.0 - saturation));
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static RGBAColor tonemap(RGBAColor color, std::array<std::array<double, 3>, 3> dstXYZ, float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance) {
|
||||
// TODO source color is expected to be in sRGB colorspace and tonamepping shouldn't be needed
|
||||
return color;
|
||||
}
|
||||
|
||||
RGBAColor NColorManagement::convertColor(RGBAColor color, PImageDescription srcDesc, PImageDescription dstDesc) {
|
||||
const auto settings =
|
||||
g_pHyprRenderer->getCMSettings(srcDesc, dstDesc, nullptr, true, g_pHyprRenderer->m_renderData.pMonitor ? g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance : -1,
|
||||
g_pHyprRenderer->m_renderData.pMonitor ? g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance : -1);
|
||||
|
||||
color /= std::max(color.c.a, 0.001);
|
||||
color = toLinearRGB(color, srcDesc->value().transferFunction);
|
||||
if (dstDesc->value().icc.present) {
|
||||
// color.rgb = applyIcc3DLut(color.rgb, iccLut3D, iccLutSize);
|
||||
color *= color.c.a;
|
||||
} else {
|
||||
const auto convertMatrix = srcDesc->getPrimaries()->convertMatrix(dstDesc->getPrimaries());
|
||||
const auto converted = convertMatrix * Hyprgraphics::CColor::XYZ{.x = color.c.r, .y = color.c.g, .z = color.c.b};
|
||||
color.c.r = converted.x;
|
||||
color.c.g = converted.y;
|
||||
color.c.b = converted.z;
|
||||
if (srcDesc->value().transferFunction != CM_TRANSFER_FUNCTION_LINEAR)
|
||||
color = toNit(color, settings.srcTFRange);
|
||||
color *= color.c.a;
|
||||
if (settings.needsTonemap)
|
||||
color = tonemap(color, settings.dstPrimaries2XYZ, settings.maxLuminance, settings.dstMaxLuminance, settings.dstRefLuminance, settings.srcRefLuminance);
|
||||
|
||||
color = fromLinearNit(color, dstDesc->value().transferFunction, settings.dstTFRange);
|
||||
if (settings.needsSDRmod) {
|
||||
color = saturate(color, settings.dstPrimaries2XYZ, settings.sdrSaturation);
|
||||
color *= settings.sdrBrightnessMultiplier;
|
||||
}
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
CHyprColor NColorManagement::convertColor(const CHyprColor& color, PImageDescription srcDesc, PImageDescription dstDesc) {
|
||||
const auto& converted = convertColor(RGBAColor{{.r = color.r, .g = color.g, .b = color.b, .a = color.a}}, srcDesc, dstDesc);
|
||||
return CHyprColor(converted.c.r, converted.c.g, converted.c.b, converted.c.a);
|
||||
}
|
||||
|
||||
PImageDescription NColorManagement::getDefaultImageDescription() {
|
||||
const auto TF = fromConfig();
|
||||
switch (TF) {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
#include "color-management-v1.hpp"
|
||||
#include <format>
|
||||
#include <hyprgraphics/color/Color.hpp>
|
||||
#include "../../helpers/memory/Memory.hpp"
|
||||
#include "../../helpers/math/Math.hpp"
|
||||
#include "../memory/Memory.hpp"
|
||||
#include "../math/Math.hpp"
|
||||
#include "../Color.hpp"
|
||||
#include "../../debug/log/Logger.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
|
@ -45,6 +47,7 @@ namespace NColorManagement {
|
|||
};
|
||||
|
||||
enum eTransferFunction : uint8_t {
|
||||
CM_TRANSFER_FUNCTION_LINEAR = 0,
|
||||
CM_TRANSFER_FUNCTION_BT1886 = 1,
|
||||
CM_TRANSFER_FUNCTION_GAMMA22 = 2,
|
||||
CM_TRANSFER_FUNCTION_GAMMA28 = 3,
|
||||
|
|
@ -68,9 +71,14 @@ namespace NColorManagement {
|
|||
inline ePrimaries convertPrimaries(wpColorManagerV1Primaries primaries) {
|
||||
return sc<ePrimaries>(primaries);
|
||||
}
|
||||
inline wpColorManagerV1TransferFunction convertTransferFunction(eTransferFunction tf) {
|
||||
inline wpColorManagerV1TransferFunction convertTransferFunction(eTransferFunction tf, bool useV1SRGB = true) {
|
||||
switch (tf) {
|
||||
case CM_TRANSFER_FUNCTION_SRGB: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_COMPOUND_POWER_2_4;
|
||||
case CM_TRANSFER_FUNCTION_LINEAR:
|
||||
Log::logger->log(Log::TRACE,
|
||||
"CM_TRANSFER_FUNCTION_LINEAR is internal and buffers with this TF shouldn't go outside. Returning "
|
||||
"WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR for preferred description instead");
|
||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
case CM_TRANSFER_FUNCTION_SRGB: return useV1SRGB ? WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB : WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_COMPOUND_POWER_2_4;
|
||||
default: return sc<wpColorManagerV1TransferFunction>(tf);
|
||||
}
|
||||
}
|
||||
|
|
@ -82,6 +90,7 @@ namespace NColorManagement {
|
|||
}
|
||||
inline std::string tfToString(eTransferFunction tf) {
|
||||
switch (tf) {
|
||||
case CM_TRANSFER_FUNCTION_LINEAR: return "TF:INTERNAL LINEAR NOT NORMALISED";
|
||||
case CM_TRANSFER_FUNCTION_BT1886: return "TF:BT1886";
|
||||
case CM_TRANSFER_FUNCTION_GAMMA22: return "TF:GAMMA22";
|
||||
case CM_TRANSFER_FUNCTION_GAMMA28: return "TF:GAMMA28";
|
||||
|
|
@ -349,8 +358,32 @@ namespace NColorManagement {
|
|||
SImageDescription m_imageDescription;
|
||||
};
|
||||
|
||||
union RGBAColor {
|
||||
struct {
|
||||
double r = 0, g = 0, b = 0, a = 0;
|
||||
} c;
|
||||
double v[4];
|
||||
|
||||
RGBAColor& operator*=(double value) {
|
||||
c.r *= value;
|
||||
c.g *= value;
|
||||
c.b *= value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RGBAColor& operator/=(double value) {
|
||||
c.r /= value;
|
||||
c.g /= value;
|
||||
c.b /= value;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
using PImageDescription = WP<const CImageDescription>;
|
||||
|
||||
RGBAColor convertColor(RGBAColor color, PImageDescription srcDesc, PImageDescription dstDesc);
|
||||
CHyprColor convertColor(const CHyprColor& color, PImageDescription srcDesc, PImageDescription dstDesc);
|
||||
|
||||
PImageDescription getDefaultImageDescription();
|
||||
|
||||
static const auto DEFAULT_GAMMA22_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
|
||||
|
|
@ -393,6 +426,17 @@ namespace NColorManagement {
|
|||
.primaries = NColorPrimaries::BT709,
|
||||
.luminances = {.min = 0, .max = 10000, .reference = 80},
|
||||
});
|
||||
|
||||
// For internal use only
|
||||
// not normalised to 0.0 - 1.0
|
||||
// luminance values should be set to default SDR settings in SDR mode and to output settings in HDR mode
|
||||
// keep srgb primaries to avoid conversions for image exports
|
||||
static const auto LINEAR_NN_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
|
||||
.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_LINEAR,
|
||||
.primariesNameSet = true,
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB,
|
||||
.primaries = NColorPrimaries::BT709,
|
||||
});
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -807,7 +807,7 @@ CColorManagementImageDescriptionInfo::CColorManagementImageDescriptionInfo(SP<CW
|
|||
if (m_settings.primariesNameSet)
|
||||
m_resource->sendPrimariesNamed(m_settings.primariesNamed);
|
||||
|
||||
m_resource->sendTfNamed(m_settings.transferFunction);
|
||||
m_resource->sendTfNamed(convertTransferFunction(m_settings.transferFunction, m_resource->version() == 1));
|
||||
|
||||
if (m_settings.transferFunctionPower != 1.0f)
|
||||
m_resource->sendTfPower(std::round(m_settings.transferFunctionPower * 10000));
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "../managers/screenshare/ScreenshareManager.hpp"
|
||||
#include "../notification/NotificationOverlay.hpp"
|
||||
#include "errorOverlay/Overlay.hpp"
|
||||
#include "helpers/Color.hpp"
|
||||
#include "macros.hpp"
|
||||
#include "pass/TexPassElement.hpp"
|
||||
#include "pass/RectPassElement.hpp"
|
||||
|
|
@ -758,6 +759,7 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, SP<IFra
|
|||
|
||||
g_pHyprRenderer->bindFB(g_pHyprRenderer->m_renderData.pMonitor->resources()->getUnusedWorkBuffer());
|
||||
m_offloadedFramebuffer = true;
|
||||
GLFB(g_pHyprRenderer->m_renderData.currentFB)->clearAfterInvalidation();
|
||||
|
||||
g_pHyprRenderer->m_renderData.mainFB = g_pHyprRenderer->m_renderData.currentFB;
|
||||
g_pHyprRenderer->m_renderData.outFB = fb ? fb : dc<CHyprGLRenderer*>(g_pHyprRenderer.get())->m_currentRenderbuffer->getFB();
|
||||
|
|
@ -1062,6 +1064,19 @@ void CHyprOpenGLImpl::renderRectWithBlurInternal(const CBox& box, const CHyprCol
|
|||
renderRectWithDamageInternal(box, col, data);
|
||||
}
|
||||
|
||||
using ColorConversionKey = std::tuple<float, float, float, float, uint64_t>;
|
||||
static std::map<ColorConversionKey, CHyprColor> colorConversionCache;
|
||||
|
||||
static CHyprColor getConvertedColor(const CHyprColor& color) {
|
||||
const auto targetId = g_pHyprRenderer->workBufferImageDescription()->id();
|
||||
const ColorConversionKey key = {color.r, color.g, color.b, color.a, targetId};
|
||||
if (colorConversionCache.contains(key))
|
||||
return colorConversionCache[key];
|
||||
const auto converted = convertColor(color, DEFAULT_SRGB_IMAGE_DESCRIPTION, g_pHyprRenderer->workBufferImageDescription());
|
||||
colorConversionCache[key] = converted;
|
||||
return converted;
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderRectWithDamageInternal(const CBox& box, const CHyprColor& col, const SRectRenderData& data) {
|
||||
auto& m_renderData = g_pHyprRenderer->m_renderData;
|
||||
RASSERT((box.width > 0 && box.height > 0), "Tried to render rect with width/height < 0!");
|
||||
|
|
@ -1078,7 +1093,10 @@ void CHyprOpenGLImpl::renderRectWithDamageInternal(const CBox& box, const CHyprC
|
|||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||
|
||||
// premultiply the color as well as we don't work with straight alpha
|
||||
shader->setUniformFloat4(SHADER_COLOR, col.r * col.a, col.g * col.a, col.b * col.a, col.a);
|
||||
const auto premultiplied = CHyprColor(col.r * col.a, col.g * col.a, col.b * col.a, col.a);
|
||||
const auto converted = getConvertedColor(premultiplied);
|
||||
shader->setUniformFloat4(SHADER_COLOR, converted.r, converted.g, converted.b, converted.a);
|
||||
shader->setUniformFloat4(SHADER_COLOR_SRGB, premultiplied.r, premultiplied.g, premultiplied.b, premultiplied.a);
|
||||
|
||||
CBox transformedBox = box;
|
||||
transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x,
|
||||
|
|
@ -1298,7 +1316,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 +1329,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
|
||||
|
|
@ -1660,6 +1678,7 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
|
|||
static auto PBLEND = CConfigValue<Config::INTEGER>("render:use_shader_blur_blend");
|
||||
|
||||
PMIRRORSWAPFB->bind();
|
||||
GLFB(PMIRRORSWAPFB)->clearAfterInvalidation();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
|
|
@ -1754,6 +1773,7 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
|
|||
// draw the things.
|
||||
// first draw is swap -> mirr
|
||||
PMIRRORFB->bind();
|
||||
GLFB(PMIRRORFB)->clearAfterInvalidation();
|
||||
PMIRRORSWAPFB->getTexture()->bind();
|
||||
|
||||
// damage region will be scaled, make a temp
|
||||
|
|
@ -2240,14 +2260,12 @@ 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()->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, getDefaultImageDescription());
|
||||
auto shader = useShader(getShaderVariant(SH_FRAG_SHADOW, globalFeatures()));
|
||||
|
||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||
shader->setUniformFloat4(SHADER_COLOR, col.r, col.g, col.b, col.a * a);
|
||||
const auto converted = getConvertedColor(col);
|
||||
shader->setUniformFloat4(SHADER_COLOR, converted.r, converted.g, converted.b, converted.a * a);
|
||||
shader->setUniformFloat4(SHADER_COLOR_SRGB, col.r, col.g, col.b, col.a * a);
|
||||
|
||||
const auto TOPLEFT = Vector2D(range + round, range + round);
|
||||
const auto BOTTOMRIGHT = Vector2D(newBox.width - (range + round), newBox.height - (range + round));
|
||||
|
|
@ -2334,14 +2352,12 @@ 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()->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, getDefaultImageDescription());
|
||||
auto shader = useShader(getShaderVariant(SH_FRAG_INNER_GLOW, globalFeatures()));
|
||||
|
||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||
shader->setUniformFloat4(SHADER_COLOR, col.r, col.g, col.b, col.a * a);
|
||||
const auto converted = getConvertedColor(col);
|
||||
shader->setUniformFloat4(SHADER_COLOR, converted.r, converted.g, converted.b, converted.a * a);
|
||||
shader->setUniformFloat4(SHADER_COLOR_SRGB, col.r, col.g, col.b, col.a * a);
|
||||
|
||||
const auto TOPLEFT = Vector2D(round, round);
|
||||
const auto BOTTOMRIGHT = Vector2D(newBox.width - round, newBox.height - round);
|
||||
|
|
@ -2385,7 +2401,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());
|
||||
|
||||
|
|
@ -2398,7 +2415,6 @@ void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
|
|||
.round = 0,
|
||||
.discardActive = false,
|
||||
.allowCustomUV = false,
|
||||
.cmBackToSRGB = true,
|
||||
});
|
||||
|
||||
blend(true);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -2020,18 +2020,8 @@ void IHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
|
|||
}
|
||||
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
|
||||
if (pMonitor->m_output->state->state().drmFormat != pMonitor->m_prevDrmFormat)
|
||||
pMonitor->m_output->state->setFormat(pMonitor->m_prevDrmFormat);
|
||||
|
||||
pMonitor->m_drmFormat = pMonitor->m_prevDrmFormat;
|
||||
}
|
||||
} else if (!pMonitor->m_lastScanout.expired() || pMonitor->m_directScanoutIsActive)
|
||||
pMonitor->handleDSleave();
|
||||
}
|
||||
|
||||
Event::bus()->m_events.render.pre.emit(pMonitor);
|
||||
|
|
@ -3049,6 +3039,7 @@ void IHyprRenderer::makeSnapshot(PHLWINDOW pWindow) {
|
|||
const auto PFRAMEBUFFER = ref->m_snapshotFB;
|
||||
|
||||
PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888);
|
||||
PFRAMEBUFFER->setImageDescription(workBufferImageDescription());
|
||||
|
||||
beginFullFakeRender(PMONITOR, fakeDamage, PFRAMEBUFFER);
|
||||
|
||||
|
|
@ -3090,6 +3081,7 @@ void IHyprRenderer::makeSnapshot(PHLLS pLayer) {
|
|||
const auto PFRAMEBUFFER = pLayer->m_snapshotFB;
|
||||
|
||||
PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888);
|
||||
PFRAMEBUFFER->setImageDescription(workBufferImageDescription());
|
||||
|
||||
beginFullFakeRender(PMONITOR, fakeDamage, PFRAMEBUFFER);
|
||||
|
||||
|
|
@ -3132,6 +3124,7 @@ void IHyprRenderer::makeSnapshot(WP<Desktop::View::CPopup> popup) {
|
|||
const auto PFRAMEBUFFER = popup->m_snapshotFB;
|
||||
|
||||
PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888);
|
||||
PFRAMEBUFFER->setImageDescription(workBufferImageDescription());
|
||||
|
||||
beginFullFakeRender(PMONITOR, fakeDamage, PFRAMEBUFFER);
|
||||
|
||||
|
|
@ -3314,14 +3307,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) {
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ void CShader::getUniformLocations() {
|
|||
|
||||
m_uniformLocations[SHADER_PROJ] = getUniform("proj");
|
||||
m_uniformLocations[SHADER_COLOR] = getUniform("color");
|
||||
m_uniformLocations[SHADER_COLOR_SRGB] = getUniform("colorSRGB");
|
||||
m_uniformLocations[SHADER_ALPHA_MATTE] = getUniform("texMatte");
|
||||
m_uniformLocations[SHADER_TEX_TYPE] = getUniform("texType");
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
enum eShaderUniform : uint8_t {
|
||||
SHADER_PROJ = 0,
|
||||
SHADER_COLOR,
|
||||
SHADER_COLOR_SRGB,
|
||||
SHADER_ALPHA_MATTE,
|
||||
SHADER_TEX_TYPE,
|
||||
SHADER_SOURCE_TF,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -171,4 +171,15 @@ void CGLFramebuffer::invalidate(const std::vector<GLenum>& attachments) {
|
|||
return;
|
||||
|
||||
glInvalidateFramebuffer(GL_FRAMEBUFFER, attachments.size(), attachments.data());
|
||||
m_cleared = false;
|
||||
}
|
||||
|
||||
void CGLFramebuffer::clearAfterInvalidation() {
|
||||
if (m_cleared)
|
||||
return;
|
||||
|
||||
m_cleared = true;
|
||||
glClearColor(0, 0, 0, 0);
|
||||
g_pHyprOpenGL->scissor(nullptr);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,15 @@ namespace Render::GL {
|
|||
GLuint getFBID();
|
||||
void invalidate(const std::vector<GLenum>& attachments);
|
||||
|
||||
// clear at most once per invalidate()
|
||||
void clearAfterInvalidation();
|
||||
|
||||
protected:
|
||||
bool internalAlloc(int w, int h, DRMFormat format = DRM_FORMAT_ARGB8888) override;
|
||||
|
||||
private:
|
||||
GLuint m_fb = -1;
|
||||
GLuint m_fb = -1;
|
||||
bool m_cleared = false;
|
||||
|
||||
friend class CGLRenderbuffer;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -104,10 +104,10 @@ vec4 blur1(vec2 v_texcoord, sampler2D tex, float radius, vec2 halfpixel, int pas
|
|||
// 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);
|
||||
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);
|
||||
|
||||
vec4 color = sum / 8.0;
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ vec3 tfST240(vec3 color) {
|
|||
|
||||
vec3 toLinearRGB(vec3 color, int tf) {
|
||||
switch (tf) {
|
||||
case CM_TRANSFER_FUNCTION_LINEAR: return color;
|
||||
case CM_TRANSFER_FUNCTION_EXT_LINEAR: return color;
|
||||
case CM_TRANSFER_FUNCTION_ST2084_PQ: return tfInvPQ(color);
|
||||
case CM_TRANSFER_FUNCTION_GAMMA22: return pow(max(color, vec3(0.0)), vec3(2.2));
|
||||
|
|
@ -179,7 +180,7 @@ vec3 fromLinearRGB(vec3 color, int tf) {
|
|||
}
|
||||
|
||||
vec4 fromLinear(vec4 color, int tf) {
|
||||
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
||||
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR || tf == CM_TRANSFER_FUNCTION_LINEAR)
|
||||
return color;
|
||||
|
||||
color.rgb /= max(color.a, 0.001);
|
||||
|
|
@ -189,6 +190,9 @@ vec4 fromLinear(vec4 color, int tf) {
|
|||
}
|
||||
|
||||
vec4 fromLinearNit(vec4 color, int tf, vec2 range) {
|
||||
if (tf == CM_TRANSFER_FUNCTION_LINEAR)
|
||||
return color;
|
||||
|
||||
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);
|
||||
|
|
@ -231,7 +235,8 @@ vec4
|
|||
pixColor.rgb *= pixColor.a;
|
||||
#else
|
||||
pixColor.rgb = convertMatrix * pixColor.rgb;
|
||||
pixColor = toNit(pixColor, srcTFRange);
|
||||
if (srcTF != CM_TRANSFER_FUNCTION_LINEAR)
|
||||
pixColor = toNit(pixColor, srcTFRange);
|
||||
pixColor.rgb *= pixColor.a;
|
||||
#if USE_TONEMAP
|
||||
pixColor = tonemap(pixColor, dstxyz, maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance);
|
||||
|
|
@ -258,4 +263,4 @@ vec4
|
|||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef CONSTANTS_H
|
||||
#define CONSTANTS_H
|
||||
//enum eTransferFunction
|
||||
#define CM_TRANSFER_FUNCTION_LINEAR 0 // not normalised
|
||||
#define CM_TRANSFER_FUNCTION_BT1886 1
|
||||
#define CM_TRANSFER_FUNCTION_GAMMA22 2
|
||||
#define CM_TRANSFER_FUNCTION_GAMMA28 3
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ precision highp float;
|
|||
in vec4 v_color;
|
||||
in vec2 v_texcoord;
|
||||
|
||||
uniform int sourceTF; // eTransferFunction
|
||||
uniform int targetTF; // eTransferFunction
|
||||
uniform mat3 targetPrimariesXYZ;
|
||||
|
||||
uniform vec4 colorSRGB;
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 fullSize;
|
||||
|
|
@ -20,38 +17,22 @@ uniform float roundingPower;
|
|||
uniform float range;
|
||||
uniform float shadowPower;
|
||||
|
||||
#if USE_CM
|
||||
#include "cm_helpers.glsl"
|
||||
#include "CM.glsl"
|
||||
#endif
|
||||
|
||||
#include "inner_glow.glsl"
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
#if USE_MIRROR
|
||||
layout(location = 1) out vec4 mirrorColor;
|
||||
#endif
|
||||
void main() {
|
||||
vec4 pixColor = v_color;
|
||||
|
||||
fragColor = getInnerGlow(pixColor, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight
|
||||
#if USE_CM
|
||||
,
|
||||
sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||
#if USE_ICC
|
||||
,
|
||||
iccLut3D, iccLutSize
|
||||
#if USE_MIRROR
|
||||
vec4[2] pixColors =
|
||||
#else
|
||||
#if USE_TONEMAP || USE_SDR_MOD
|
||||
,
|
||||
targetPrimariesXYZ
|
||||
fragColor =
|
||||
#endif
|
||||
#if USE_TONEMAP
|
||||
,
|
||||
maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
|
||||
getInnerGlow(pixColor, colorSRGB, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight);
|
||||
#if USE_MIRROR
|
||||
fragColor = pixColors[0];
|
||||
mirrorColor = pixColors[1];
|
||||
#endif
|
||||
#if USE_SDR_MOD
|
||||
,
|
||||
sdrSaturation, sdrBrightnessMultiplier
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
#ifndef INNER_GLOW_GLSL
|
||||
#define INNER_GLOW_GLSL
|
||||
|
||||
#include "cm_helpers.glsl"
|
||||
|
||||
float innerGlowAlpha(float distFromEdge, float range, float glowPower) {
|
||||
if (distFromEdge >= range)
|
||||
return 0.0;
|
||||
|
|
@ -26,29 +24,7 @@ float innerGlowSmin(float a, float b, float k) {
|
|||
return min(a, b) - h * h * h * k * (1.0 / 6.0);
|
||||
}
|
||||
|
||||
vec4 getInnerGlow(vec4 pixColor, vec2 v_texcoord, float radius, float roundingPower, vec2 topLeft, vec2 fullSize, float range, float glowPower, vec2 bottomRight
|
||||
#if USE_CM
|
||||
,
|
||||
int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
|
||||
#if USE_ICC
|
||||
,
|
||||
highp sampler3D iccLut3D, float iccLutSize
|
||||
#else
|
||||
#if USE_TONEMAP || USE_SDR_MOD
|
||||
,
|
||||
mat3 targetPrimariesXYZ
|
||||
#endif
|
||||
#if USE_TONEMAP
|
||||
,
|
||||
float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance
|
||||
#endif
|
||||
#if USE_SDR_MOD
|
||||
,
|
||||
float sdrSaturation, float sdrBrightnessMultiplier
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
vec4 getInnerGlow(vec4 pixColor, vec4 colorSRGB, vec2 v_texcoord, float radius, float roundingPower, vec2 topLeft, vec2 fullSize, float range, float glowPower, vec2 bottomRight) {
|
||||
vec2 pixCoord = fullSize * v_texcoord;
|
||||
|
||||
// clip to the rounded rectangle shape using actual SDF
|
||||
|
|
@ -79,28 +55,15 @@ vec4 getInnerGlow(vec4 pixColor, vec2 v_texcoord, float radius, float roundingPo
|
|||
// premultiply
|
||||
pixColor.rgb *= pixColor[3];
|
||||
|
||||
#if USE_CM
|
||||
pixColor = doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||
#if USE_ICC
|
||||
,
|
||||
iccLut3D, iccLutSize
|
||||
#if USE_MIRROR
|
||||
vec4[2] pixColors;
|
||||
pixColors[0] = pixColor;
|
||||
pixColors[1] = colorSRGB;
|
||||
pixColors[1].a = pixColor.a;
|
||||
pixColors[1].rgb *= pixColors[1].a;
|
||||
return pixColors;
|
||||
#else
|
||||
#if USE_TONEMAP || USE_SDR_MOD
|
||||
,
|
||||
targetPrimariesXYZ
|
||||
#endif
|
||||
#if USE_TONEMAP
|
||||
,
|
||||
maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
|
||||
#endif
|
||||
#if USE_SDR_MOD
|
||||
,
|
||||
sdrSaturation, sdrBrightnessMultiplier
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
|
||||
return pixColor;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
precision highp float;
|
||||
in vec4 v_color;
|
||||
|
||||
uniform vec4 colorSRGB;
|
||||
#if USE_ROUNDING
|
||||
uniform float radius;
|
||||
uniform float roundingPower;
|
||||
|
|
@ -28,6 +29,10 @@ void main() {
|
|||
|
||||
fragColor = pixColor;
|
||||
#if USE_MIRROR
|
||||
mirrorColor = fragColor;
|
||||
#if USE_ROUNDING
|
||||
mirrorColor = rounding(colorSRGB, radius, roundingPower, topLeft, fullSize);
|
||||
#else
|
||||
mirrorColor = colorSRGB;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ precision highp float;
|
|||
in vec4 v_color;
|
||||
in vec2 v_texcoord;
|
||||
|
||||
uniform int sourceTF; // eTransferFunction
|
||||
uniform int targetTF; // eTransferFunction
|
||||
uniform mat3 targetPrimariesXYZ;
|
||||
|
||||
uniform vec4 colorSRGB;
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 windowTopLeft;
|
||||
|
|
@ -23,11 +20,6 @@ uniform float range;
|
|||
uniform float shadowPower;
|
||||
uniform float thick;
|
||||
|
||||
#if USE_CM
|
||||
#include "cm_helpers.glsl"
|
||||
#include "CM.glsl"
|
||||
#endif
|
||||
|
||||
#include "shadow.glsl"
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
|
@ -41,29 +33,7 @@ void main() {
|
|||
#else
|
||||
fragColor =
|
||||
#endif
|
||||
getShadow(pixColor, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight, windowTopLeft, windowBottomRight, thick
|
||||
#if USE_CM
|
||||
,
|
||||
sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||
#if USE_ICC
|
||||
,
|
||||
iccLut3D, iccLutSize
|
||||
#else
|
||||
#if USE_TONEMAP || USE_SDR_MOD
|
||||
,
|
||||
targetPrimariesXYZ
|
||||
#endif
|
||||
#if USE_TONEMAP
|
||||
,
|
||||
maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
|
||||
#endif
|
||||
#if USE_SDR_MOD
|
||||
,
|
||||
sdrSaturation, sdrBrightnessMultiplier
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
getShadow(pixColor, colorSRGB, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight, windowTopLeft, windowBottomRight, thick);
|
||||
#if USE_MIRROR
|
||||
fragColor = pixColors[0];
|
||||
mirrorColor = pixColors[1];
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#ifndef SHADOW_GLSL
|
||||
#define SHADOW_GLSL
|
||||
|
||||
#include "cm_helpers.glsl"
|
||||
#include "rounding.glsl"
|
||||
|
||||
float pixAlphaRoundedDistance(float distanceToCorner, float radius, float range, float shadowPower) {
|
||||
|
|
@ -54,30 +53,8 @@ vec4[2]
|
|||
#else
|
||||
vec4
|
||||
#endif
|
||||
getShadow(vec4 pixColor, vec2 v_texcoord, float borderRadius, float roundingPower, vec2 topLeft, vec2 fullSize, float range, float shadowPower, vec2 bottomRight,
|
||||
vec2 windowTopLeft, vec2 windowBottomRight, float windowRadius
|
||||
#if USE_CM
|
||||
,
|
||||
int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
|
||||
#if USE_ICC
|
||||
,
|
||||
highp sampler3D iccLut3D, float iccLutSize
|
||||
#else
|
||||
#if USE_TONEMAP || USE_SDR_MOD
|
||||
,
|
||||
mat3 targetPrimariesXYZ
|
||||
#endif
|
||||
#if USE_TONEMAP
|
||||
,
|
||||
float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance
|
||||
#endif
|
||||
#if USE_SDR_MOD
|
||||
,
|
||||
float sdrSaturation, float sdrBrightnessMultiplier
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
getShadow(vec4 pixColor, vec4 colorSRGB, vec2 v_texcoord, float borderRadius, float roundingPower, vec2 topLeft, vec2 fullSize, float range, float shadowPower, vec2 bottomRight,
|
||||
vec2 windowTopLeft, vec2 windowBottomRight, float windowRadius) {
|
||||
float radius = range + borderRadius;
|
||||
float originalAlpha = pixColor[3];
|
||||
|
||||
|
|
@ -144,33 +121,12 @@ vec4
|
|||
// premultiply
|
||||
pixColor.rgb *= pixColor[3];
|
||||
|
||||
#if USE_CM
|
||||
#if USE_MIRROR
|
||||
vec4[2] pixColors =
|
||||
#else
|
||||
pixColor =
|
||||
#endif
|
||||
doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||
#if USE_ICC
|
||||
,
|
||||
iccLut3D, iccLutSize
|
||||
#else
|
||||
#if USE_TONEMAP || USE_SDR_MOD
|
||||
,
|
||||
targetPrimariesXYZ
|
||||
#endif
|
||||
#if USE_TONEMAP
|
||||
,
|
||||
maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
|
||||
#endif
|
||||
#if USE_SDR_MOD
|
||||
,
|
||||
sdrSaturation, sdrBrightnessMultiplier
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#if USE_MIRROR
|
||||
vec4[2] pixColors;
|
||||
pixColors[0] = pixColor;
|
||||
pixColors[1] = colorSRGB;
|
||||
pixColors[1].a = pixColor.a;
|
||||
pixColors[1].rgb *= pixColors[1].a;
|
||||
return pixColors;
|
||||
#else
|
||||
return pixColor;
|
||||
|
|
|
|||
|
|
@ -50,21 +50,16 @@ vec4 tonemap(vec4 color, mat3 dstXYZ, float maxLuminance, float dstMaxLuminance,
|
|||
float E = pow(clamp(ICtCp[0], 0.0, 1.0), PQ_INV_M2);
|
||||
float luminance = pow((max(E - PQ_C1, 0.0)) / (PQ_C2 - PQ_C3 * E), PQ_INV_M1) * HDR_MAX_LUMINANCE;
|
||||
|
||||
float linearPart = min(luminance, dstRefLuminance);
|
||||
float luminanceAboveRef = max(luminance - dstRefLuminance, 0.0);
|
||||
float maxExcessLuminance = max(maxLuminance - dstRefLuminance, 1.0);
|
||||
float shoulder = log((luminanceAboveRef / maxExcessLuminance + 1.0) * (M_E - 1.0));
|
||||
float mappedHigh = shoulder * (dstMaxLuminance - dstRefLuminance);
|
||||
float newLum = clamp(linearPart + mappedHigh, 0.0, dstMaxLuminance);
|
||||
float luminanceRatio = max(luminance / dstRefLuminance, 0.0);
|
||||
float srcScale = maxLuminance / dstRefLuminance;
|
||||
float dstScale = dstMaxLuminance / dstRefLuminance;
|
||||
float v = (dstScale * (1.0 + srcScale) - srcScale) / pow(srcScale, 2.0);
|
||||
float newLuminance = (luminanceRatio * (1.0 + luminanceRatio * v) / (1.0 + luminanceRatio)) * dstRefLuminance;
|
||||
|
||||
// scale src to dst reference
|
||||
float refScale = dstRefLuminance / srcRefLuminance;
|
||||
E = pow(clamp(newLuminance / HDR_MAX_LUMINANCE, 0.0, 1.0), PQ_M1);
|
||||
ICtCp[0] = pow((PQ_C1 + PQ_C2 * E) / (1.0 + PQ_C3 * E), PQ_M2);
|
||||
|
||||
// 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]);
|
||||
color = vec4(fromLMS * toLinear(vec4(ICtCpPQInv * ICtCp, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb * HDR_MAX_LUMINANCE, color[3]);
|
||||
|
||||
return clamp(color, 0.0, dstMaxLuminance);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue