renderer: add simple color management (#9506)
Adds proper color management and transformations for CM surfaces.
This commit is contained in:
parent
e86d3a14e4
commit
8c97cb7858
14 changed files with 823 additions and 179 deletions
|
|
@ -1378,6 +1378,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||||
.type = CONFIG_OPTION_BOOL,
|
.type = CONFIG_OPTION_BOOL,
|
||||||
.data = SConfigOptionDescription::SBoolData{true},
|
.data = SConfigOptionDescription::SBoolData{true},
|
||||||
},
|
},
|
||||||
|
SConfigOptionDescription{
|
||||||
|
.value = "render:cm_fs_passthrough",
|
||||||
|
.description = "Passthrough color settings for fullscreen apps when possible",
|
||||||
|
.type = CONFIG_OPTION_BOOL,
|
||||||
|
.data = SConfigOptionDescription::SBoolData{true},
|
||||||
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cursor:
|
* cursor:
|
||||||
|
|
@ -1764,18 +1770,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||||
.type = CONFIG_OPTION_BOOL,
|
.type = CONFIG_OPTION_BOOL,
|
||||||
.data = SConfigOptionDescription::SBoolData{true},
|
.data = SConfigOptionDescription::SBoolData{true},
|
||||||
},
|
},
|
||||||
SConfigOptionDescription{
|
|
||||||
.value = "experimental:wide_color_gamut",
|
|
||||||
.description = "force wide color gamut for all supported outputs",
|
|
||||||
.type = CONFIG_OPTION_BOOL,
|
|
||||||
.data = SConfigOptionDescription::SBoolData{false},
|
|
||||||
},
|
|
||||||
SConfigOptionDescription{
|
|
||||||
.value = "experimental:hdr",
|
|
||||||
.description = "force static hdr for all supported outputs",
|
|
||||||
.type = CONFIG_OPTION_BOOL,
|
|
||||||
.data = SConfigOptionDescription::SBoolData{false},
|
|
||||||
},
|
|
||||||
SConfigOptionDescription{
|
SConfigOptionDescription{
|
||||||
.value = "experimental:xx_color_management_v4",
|
.value = "experimental:xx_color_management_v4",
|
||||||
.description = "enable color management protocol",
|
.description = "enable color management protocol",
|
||||||
|
|
|
||||||
|
|
@ -692,12 +692,11 @@ CConfigManager::CConfigManager() {
|
||||||
registerConfigVar("render:xp_mode", Hyprlang::INT{0});
|
registerConfigVar("render:xp_mode", Hyprlang::INT{0});
|
||||||
registerConfigVar("render:ctm_animation", Hyprlang::INT{2});
|
registerConfigVar("render:ctm_animation", Hyprlang::INT{2});
|
||||||
registerConfigVar("render:allow_early_buffer_release", Hyprlang::INT{1});
|
registerConfigVar("render:allow_early_buffer_release", Hyprlang::INT{1});
|
||||||
|
registerConfigVar("render:cm_fs_passthrough", Hyprlang::INT{1});
|
||||||
|
|
||||||
registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0});
|
registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0});
|
||||||
registerConfigVar("ecosystem:no_donation_nag", Hyprlang::INT{0});
|
registerConfigVar("ecosystem:no_donation_nag", Hyprlang::INT{0});
|
||||||
|
|
||||||
registerConfigVar("experimental:wide_color_gamut", Hyprlang::INT{0});
|
|
||||||
registerConfigVar("experimental:hdr", Hyprlang::INT{0});
|
|
||||||
registerConfigVar("experimental:xx_color_management_v4", Hyprlang::INT{0});
|
registerConfigVar("experimental:xx_color_management_v4", Hyprlang::INT{0});
|
||||||
|
|
||||||
// devices
|
// devices
|
||||||
|
|
@ -2042,6 +2041,32 @@ std::optional<std::string> CConfigManager::handleMonitor(const std::string& comm
|
||||||
} else if (ARGS[argno] == "bitdepth") {
|
} else if (ARGS[argno] == "bitdepth") {
|
||||||
newrule.enable10bit = ARGS[argno + 1] == "10";
|
newrule.enable10bit = ARGS[argno + 1] == "10";
|
||||||
argno++;
|
argno++;
|
||||||
|
} else if (ARGS[argno] == "cm") {
|
||||||
|
if (ARGS[argno + 1] == "auto")
|
||||||
|
newrule.cmType = CM_AUTO;
|
||||||
|
else if (ARGS[argno + 1] == "srgb")
|
||||||
|
newrule.cmType = CM_SRGB;
|
||||||
|
else if (ARGS[argno + 1] == "wide")
|
||||||
|
newrule.cmType = CM_WIDE;
|
||||||
|
else if (ARGS[argno + 1] == "edid")
|
||||||
|
newrule.cmType = CM_EDID;
|
||||||
|
else if (ARGS[argno + 1] == "hdr")
|
||||||
|
newrule.cmType = CM_HDR;
|
||||||
|
else if (ARGS[argno + 1] == "hdredid")
|
||||||
|
newrule.cmType = CM_HDR_EDID;
|
||||||
|
else
|
||||||
|
error = "invalid cm ";
|
||||||
|
argno++;
|
||||||
|
} else if (ARGS[argno] == "sdrsaturation") {
|
||||||
|
try {
|
||||||
|
newrule.sdrSaturation = stof(ARGS[argno + 1]);
|
||||||
|
} catch (...) { error = "invalid sdrsaturation "; }
|
||||||
|
argno++;
|
||||||
|
} else if (ARGS[argno] == "sdrbrightness") {
|
||||||
|
try {
|
||||||
|
newrule.sdrBrightness = stof(ARGS[argno + 1]);
|
||||||
|
} catch (...) { error = "invalid sdrbrightness "; }
|
||||||
|
argno++;
|
||||||
} else if (ARGS[argno] == "transform") {
|
} else if (ARGS[argno] == "transform") {
|
||||||
if (!isNumber(ARGS[argno + 1])) {
|
if (!isNumber(ARGS[argno + 1])) {
|
||||||
error = "invalid transform ";
|
error = "invalid transform ";
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include "MiscFunctions.hpp"
|
#include "MiscFunctions.hpp"
|
||||||
#include "../macros.hpp"
|
#include "../macros.hpp"
|
||||||
#include "math/Math.hpp"
|
#include "math/Math.hpp"
|
||||||
|
#include "../protocols/ColorManagement.hpp"
|
||||||
#include "sync/SyncReleaser.hpp"
|
#include "sync/SyncReleaser.hpp"
|
||||||
#include "../Compositor.hpp"
|
#include "../Compositor.hpp"
|
||||||
#include "../config/ConfigValue.hpp"
|
#include "../config/ConfigValue.hpp"
|
||||||
|
|
@ -412,7 +413,8 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
|
||||||
if (!force && DELTALESSTHAN(vecPixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(vecPixelSize.y, RULE->resolution.y, 1) &&
|
if (!force && DELTALESSTHAN(vecPixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(vecPixelSize.y, RULE->resolution.y, 1) &&
|
||||||
DELTALESSTHAN(refreshRate, RULE->refreshRate, 1) && setScale == RULE->scale &&
|
DELTALESSTHAN(refreshRate, RULE->refreshRate, 1) && setScale == RULE->scale &&
|
||||||
((DELTALESSTHAN(vecPosition.x, RULE->offset.x, 1) && DELTALESSTHAN(vecPosition.y, RULE->offset.y, 1)) || RULE->offset == Vector2D(-INT32_MAX, -INT32_MAX)) &&
|
((DELTALESSTHAN(vecPosition.x, RULE->offset.x, 1) && DELTALESSTHAN(vecPosition.y, RULE->offset.y, 1)) || RULE->offset == Vector2D(-INT32_MAX, -INT32_MAX)) &&
|
||||||
transform == RULE->transform && RULE->enable10bit == enabled10bit && !std::memcmp(&customDrmMode, &RULE->drmMode, sizeof(customDrmMode))) {
|
transform == RULE->transform && RULE->enable10bit == enabled10bit && RULE->cmType == cmType && RULE->sdrSaturation == sdrSaturation &&
|
||||||
|
RULE->sdrBrightness == sdrBrightness && !std::memcmp(&customDrmMode, &RULE->drmMode, sizeof(customDrmMode))) {
|
||||||
|
|
||||||
Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", szName);
|
Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", szName);
|
||||||
|
|
||||||
|
|
@ -670,6 +672,66 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
|
||||||
|
|
||||||
enabled10bit = set10bit;
|
enabled10bit = set10bit;
|
||||||
|
|
||||||
|
auto oldImageDescription = imageDescription;
|
||||||
|
cmType = RULE->cmType;
|
||||||
|
switch (cmType) {
|
||||||
|
case CM_AUTO: cmType = enabled10bit && output->parsedEDID.supportsBT2020 ? CM_WIDE : CM_SRGB; break;
|
||||||
|
case CM_EDID: cmType = output->parsedEDID.chromaticityCoords.has_value() ? CM_EDID : CM_SRGB; break;
|
||||||
|
case CM_HDR:
|
||||||
|
case CM_HDR_EDID:
|
||||||
|
cmType = output->parsedEDID.supportsBT2020 && output->parsedEDID.hdrMetadata.has_value() && output->parsedEDID.hdrMetadata->supportsPQ ? cmType : CM_SRGB;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
switch (cmType) {
|
||||||
|
case CM_SRGB: imageDescription = {}; break; // assumes SImageDescirption defaults to sRGB
|
||||||
|
case CM_WIDE:
|
||||||
|
imageDescription = {.primariesNameSet = true,
|
||||||
|
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||||
|
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020)};
|
||||||
|
break;
|
||||||
|
case CM_EDID:
|
||||||
|
imageDescription = {.primariesNameSet = false,
|
||||||
|
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||||
|
.primaries = {
|
||||||
|
.red = {.x = output->parsedEDID.chromaticityCoords->red.x, .y = output->parsedEDID.chromaticityCoords->red.y},
|
||||||
|
.green = {.x = output->parsedEDID.chromaticityCoords->green.x, .y = output->parsedEDID.chromaticityCoords->green.y},
|
||||||
|
.blue = {.x = output->parsedEDID.chromaticityCoords->blue.x, .y = output->parsedEDID.chromaticityCoords->blue.y},
|
||||||
|
.white = {.x = output->parsedEDID.chromaticityCoords->white.x, .y = output->parsedEDID.chromaticityCoords->white.y},
|
||||||
|
}};
|
||||||
|
break;
|
||||||
|
case CM_HDR:
|
||||||
|
imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
|
||||||
|
.primariesNameSet = true,
|
||||||
|
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||||
|
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
|
||||||
|
.luminances = {.min = 0, .max = 10000, .reference = 203}};
|
||||||
|
break;
|
||||||
|
case CM_HDR_EDID:
|
||||||
|
imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
|
||||||
|
.primariesNameSet = false,
|
||||||
|
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||||
|
.primaries = output->parsedEDID.chromaticityCoords.has_value() ?
|
||||||
|
NColorManagement::SPCPRimaries{
|
||||||
|
.red = {.x = output->parsedEDID.chromaticityCoords->red.x, .y = output->parsedEDID.chromaticityCoords->red.y},
|
||||||
|
.green = {.x = output->parsedEDID.chromaticityCoords->green.x, .y = output->parsedEDID.chromaticityCoords->green.y},
|
||||||
|
.blue = {.x = output->parsedEDID.chromaticityCoords->blue.x, .y = output->parsedEDID.chromaticityCoords->blue.y},
|
||||||
|
.white = {.x = output->parsedEDID.chromaticityCoords->white.x, .y = output->parsedEDID.chromaticityCoords->white.y},
|
||||||
|
} :
|
||||||
|
NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
|
||||||
|
.luminances = {.min = output->parsedEDID.hdrMetadata->desiredContentMinLuminance,
|
||||||
|
.max = output->parsedEDID.hdrMetadata->desiredContentMaxLuminance,
|
||||||
|
.reference = output->parsedEDID.hdrMetadata->desiredMaxFrameAverageLuminance}};
|
||||||
|
|
||||||
|
break;
|
||||||
|
default: UNREACHABLE();
|
||||||
|
}
|
||||||
|
if (oldImageDescription != imageDescription)
|
||||||
|
PROTO::colorManagement->onMonitorImageDescriptionChanged(self);
|
||||||
|
|
||||||
|
sdrSaturation = RULE->sdrSaturation;
|
||||||
|
sdrBrightness = RULE->sdrBrightness;
|
||||||
|
|
||||||
Vector2D logicalSize = vecPixelSize / scale;
|
Vector2D logicalSize = vecPixelSize / scale;
|
||||||
if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) {
|
if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) {
|
||||||
// invalid scale, will produce fractional pixels.
|
// invalid scale, will produce fractional pixels.
|
||||||
|
|
|
||||||
|
|
@ -28,18 +28,30 @@ enum eAutoDirs : uint8_t {
|
||||||
DIR_AUTO_RIGHT
|
DIR_AUTO_RIGHT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum eCMType : uint8_t {
|
||||||
|
CM_AUTO = 0, // subject to change. srgb for 8bpc, wide for 10bpc if supported
|
||||||
|
CM_SRGB, // default, sRGB primaries
|
||||||
|
CM_WIDE, // wide color gamut, BT2020 primaries
|
||||||
|
CM_EDID, // primaries from edid (known to be inaccurate)
|
||||||
|
CM_HDR, // wide color gamut and HDR PQ transfer function
|
||||||
|
CM_HDR_EDID, // same as CM_HDR with edid primaries
|
||||||
|
};
|
||||||
|
|
||||||
struct SMonitorRule {
|
struct SMonitorRule {
|
||||||
eAutoDirs autoDir = DIR_AUTO_NONE;
|
eAutoDirs autoDir = DIR_AUTO_NONE;
|
||||||
std::string name = "";
|
std::string name = "";
|
||||||
Vector2D resolution = Vector2D(1280, 720);
|
Vector2D resolution = Vector2D(1280, 720);
|
||||||
Vector2D offset = Vector2D(0, 0);
|
Vector2D offset = Vector2D(0, 0);
|
||||||
float scale = 1;
|
float scale = 1;
|
||||||
float refreshRate = 60; // Hz
|
float refreshRate = 60; // Hz
|
||||||
bool disabled = false;
|
bool disabled = false;
|
||||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
std::string mirrorOf = "";
|
std::string mirrorOf = "";
|
||||||
bool enable10bit = false;
|
bool enable10bit = false;
|
||||||
drmModeModeInfo drmMode = {};
|
eCMType cmType = CM_SRGB;
|
||||||
|
float sdrSaturation = 1.0f; // SDR -> HDR
|
||||||
|
float sdrBrightness = 1.0f; // SDR -> HDR
|
||||||
|
drmModeModeInfo drmMode = {};
|
||||||
std::optional<int> vrr;
|
std::optional<int> vrr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -108,6 +120,9 @@ class CMonitor {
|
||||||
bool dpmsStatus = true;
|
bool dpmsStatus = true;
|
||||||
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||||
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||||
|
eCMType cmType = CM_SRGB;
|
||||||
|
float sdrSaturation = 1.0f;
|
||||||
|
float sdrBrightness = 1.0f;
|
||||||
bool createdByUser = false;
|
bool createdByUser = false;
|
||||||
bool isUnsafeFallback = false;
|
bool isUnsafeFallback = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,46 +14,47 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
|
||||||
if UNLIKELY (!good())
|
if UNLIKELY (!good())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC);
|
||||||
|
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_PRIMARIES);
|
||||||
|
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES);
|
||||||
|
|
||||||
if (PROTO::colorManagement->m_debug) {
|
if (PROTO::colorManagement->m_debug) {
|
||||||
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_ICC_V2_V4);
|
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_ICC_V2_V4);
|
||||||
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC);
|
|
||||||
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_PRIMARIES);
|
|
||||||
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_TF_POWER);
|
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_TF_POWER);
|
||||||
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES);
|
|
||||||
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES);
|
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES);
|
||||||
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_EXTENDED_TARGET_VOLUME);
|
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_EXTENDED_TARGET_VOLUME);
|
||||||
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_WINDOWS_SCRGB);
|
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_WINDOWS_SCRGB);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_SRGB);
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_SRGB);
|
||||||
if (PROTO::colorManagement->m_debug) {
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_BT2020);
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_BT2020); // HDR for fullscreen only
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_PAL_M);
|
||||||
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_PAL);
|
||||||
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_NTSC);
|
||||||
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_GENERIC_FILM);
|
||||||
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_DCI_P3);
|
||||||
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_DISPLAY_P3);
|
||||||
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB);
|
||||||
|
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_PAL_M);
|
if (PROTO::colorManagement->m_debug) {
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_PAL);
|
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_NTSC);
|
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_GENERIC_FILM);
|
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_CIE1931_XYZ);
|
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_CIE1931_XYZ);
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_DCI_P3);
|
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_DISPLAY_P3);
|
|
||||||
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB);
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB);
|
||||||
if (PROTO::colorManagement->m_debug) {
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22);
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ); // HDR for fullscreen only
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28);
|
||||||
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR);
|
||||||
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ);
|
||||||
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG);
|
||||||
|
|
||||||
|
if (PROTO::colorManagement->m_debug) {
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886);
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886);
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22);
|
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28);
|
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST240);
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST240);
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR);
|
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_100);
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_100);
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_316);
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_316);
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_XVYCC);
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_XVYCC);
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB);
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB);
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST428);
|
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST428);
|
||||||
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL);
|
m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL);
|
||||||
|
|
@ -162,11 +163,6 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
|
||||||
m_resource->setCreateParametricCreator([](CWpColorManagerV1* r, uint32_t id) {
|
m_resource->setCreateParametricCreator([](CWpColorManagerV1* r, uint32_t id) {
|
||||||
LOGM(TRACE, "New parametric creator for id={}", id);
|
LOGM(TRACE, "New parametric creator for id={}", id);
|
||||||
|
|
||||||
if (!PROTO::colorManagement->m_debug) {
|
|
||||||
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "Parametric creator is not supported");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto RESOURCE = PROTO::colorManagement->m_vParametricCreators.emplace_back(
|
const auto RESOURCE = PROTO::colorManagement->m_vParametricCreators.emplace_back(
|
||||||
makeShared<CColorManagementParametricCreator>(makeShared<CWpImageDescriptionCreatorParamsV1>(r->client(), r->version(), id)));
|
makeShared<CColorManagementParametricCreator>(makeShared<CWpImageDescriptionCreatorParamsV1>(r->client(), r->version(), id)));
|
||||||
|
|
||||||
|
|
@ -536,6 +532,10 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CWpImage
|
||||||
switch (tf) {
|
switch (tf) {
|
||||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB: break;
|
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB: break;
|
||||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ: break;
|
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ: break;
|
||||||
|
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR: break;
|
||||||
|
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22: break;
|
||||||
|
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28: break;
|
||||||
|
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG: break;
|
||||||
default: r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_TF, "Unsupported transfer function"); return;
|
default: r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_TF, "Unsupported transfer function"); return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -566,11 +566,6 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CWpImage
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PROTO::colorManagement->m_debug && primaries != WP_COLOR_MANAGER_V1_PRIMARIES_SRGB) {
|
|
||||||
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_PRIMARIES_NAMED, "Unsupported primaries");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (primaries) {
|
switch (primaries) {
|
||||||
case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB:
|
case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB:
|
||||||
case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
|
case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
|
||||||
|
|
@ -580,14 +575,18 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CWpImage
|
||||||
case WP_COLOR_MANAGER_V1_PRIMARIES_GENERIC_FILM:
|
case WP_COLOR_MANAGER_V1_PRIMARIES_GENERIC_FILM:
|
||||||
case WP_COLOR_MANAGER_V1_PRIMARIES_DCI_P3:
|
case WP_COLOR_MANAGER_V1_PRIMARIES_DCI_P3:
|
||||||
case WP_COLOR_MANAGER_V1_PRIMARIES_DISPLAY_P3:
|
case WP_COLOR_MANAGER_V1_PRIMARIES_DISPLAY_P3:
|
||||||
case WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB:
|
case WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB: break;
|
||||||
settings.primariesNameSet = true;
|
default:
|
||||||
settings.primariesNamed = convertPrimaries((wpColorManagerV1Primaries)primaries);
|
if (!PROTO::colorManagement->m_debug) {
|
||||||
settings.primaries = getPrimaries(settings.primariesNamed);
|
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_PRIMARIES_NAMED, "Unsupported primaries");
|
||||||
valuesSet |= PC_PRIMARIES;
|
return;
|
||||||
break;
|
}
|
||||||
default: r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_PRIMARIES_NAMED, "Unsupported primaries");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
settings.primariesNameSet = true;
|
||||||
|
settings.primariesNamed = convertPrimaries((wpColorManagerV1Primaries)primaries);
|
||||||
|
settings.primaries = getPrimaries(settings.primariesNamed);
|
||||||
|
valuesSet |= PC_PRIMARIES;
|
||||||
});
|
});
|
||||||
m_resource->setSetPrimaries(
|
m_resource->setSetPrimaries(
|
||||||
[this](CWpImageDescriptionCreatorParamsV1* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) {
|
[this](CWpImageDescriptionCreatorParamsV1* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) {
|
||||||
|
|
@ -618,10 +617,6 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CWpImage
|
||||||
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_LUMINANCE, "Invalid luminances");
|
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_LUMINANCE, "Invalid luminances");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!PROTO::colorManagement->m_debug) {
|
|
||||||
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "Luminances aren't supported");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum};
|
settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum};
|
||||||
valuesSet |= PC_LUMINANCES;
|
valuesSet |= PC_LUMINANCES;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "ColorManagement.hpp"
|
#include "ColorManagement.hpp"
|
||||||
#include "color-management-v1.hpp"
|
#include "color-management-v1.hpp"
|
||||||
#include "types/ColorManagement.hpp"
|
#include "types/ColorManagement.hpp"
|
||||||
|
#include "xx-color-management-v4.hpp"
|
||||||
|
|
||||||
using namespace NColorManagement;
|
using namespace NColorManagement;
|
||||||
|
|
||||||
|
|
@ -40,20 +41,22 @@ CXXColorManager::CXXColorManager(SP<CXxColorManagerV4> resource_) : resource(res
|
||||||
resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_LUMINANCES);
|
resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_LUMINANCES);
|
||||||
|
|
||||||
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_SRGB);
|
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_SRGB);
|
||||||
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M);
|
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M);
|
||||||
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL);
|
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL);
|
||||||
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_NTSC);
|
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_NTSC);
|
||||||
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM);
|
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM);
|
||||||
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_BT2020);
|
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_BT2020);
|
||||||
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ);
|
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ);
|
||||||
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3);
|
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3);
|
||||||
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3);
|
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3);
|
||||||
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB);
|
resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB);
|
||||||
|
|
||||||
// resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22);
|
resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22);
|
||||||
|
resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA28);
|
||||||
|
resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_HLG);
|
||||||
resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB);
|
resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB);
|
||||||
resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ);
|
resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ);
|
||||||
// resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR);
|
resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR);
|
||||||
|
|
||||||
resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL);
|
resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL);
|
||||||
// resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE);
|
// resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE);
|
||||||
|
|
@ -396,8 +399,12 @@ CXXColorManagementParametricCreator::CXXColorManagementParametricCreator(SP<CXxI
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (tf) {
|
switch (tf) {
|
||||||
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB: break;
|
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22:
|
||||||
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ: break;
|
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA28:
|
||||||
|
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_HLG:
|
||||||
|
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB:
|
||||||
|
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
|
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR: break;
|
||||||
default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF, "Unsupported transfer function"); return;
|
default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF, "Unsupported transfer function"); return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,15 +429,17 @@ CXXColorManagementParametricCreator::CXXColorManagementParametricCreator(SP<CXxI
|
||||||
|
|
||||||
switch (primaries) {
|
switch (primaries) {
|
||||||
case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB:
|
case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB:
|
||||||
settings.primariesNameSet = true;
|
case XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M:
|
||||||
settings.primariesNamed = convertPrimaries(getWPPrimaries(XX_COLOR_MANAGER_V4_PRIMARIES_SRGB));
|
case XX_COLOR_MANAGER_V4_PRIMARIES_PAL:
|
||||||
settings.primaries = NColorPrimaries::BT709;
|
case XX_COLOR_MANAGER_V4_PRIMARIES_NTSC:
|
||||||
valuesSet |= PC_PRIMARIES;
|
case XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM:
|
||||||
break;
|
|
||||||
case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020:
|
case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020:
|
||||||
|
case XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3:
|
||||||
|
case XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3:
|
||||||
|
case XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB:
|
||||||
settings.primariesNameSet = true;
|
settings.primariesNameSet = true;
|
||||||
settings.primariesNamed = convertPrimaries(getWPPrimaries(XX_COLOR_MANAGER_V4_PRIMARIES_BT2020));
|
settings.primariesNamed = convertPrimaries(getWPPrimaries((xxColorManagerV4Primaries)primaries));
|
||||||
settings.primaries = NColorPrimaries::BT2020;
|
settings.primaries = getPrimaries(settings.primariesNamed);
|
||||||
valuesSet |= PC_PRIMARIES;
|
valuesSet |= PC_PRIMARIES;
|
||||||
break;
|
break;
|
||||||
default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, "Unsupported primaries");
|
default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, "Unsupported primaries");
|
||||||
|
|
|
||||||
|
|
@ -48,10 +48,17 @@ namespace NColorManagement {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SPCPRimaries {
|
struct SPCPRimaries {
|
||||||
struct {
|
struct xy { //NOLINT(readability-identifier-naming)
|
||||||
float x = 0;
|
float x = 0;
|
||||||
float y = 0;
|
float y = 0;
|
||||||
|
|
||||||
|
bool operator==(const xy& p2) const {
|
||||||
|
return x == p2.x && y == p2.y;
|
||||||
|
}
|
||||||
} red, green, blue, white;
|
} red, green, blue, white;
|
||||||
|
bool operator==(const SPCPRimaries& p2) const {
|
||||||
|
return red == p2.red && green == p2.green && blue == p2.blue && white == p2.white;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace NColorPrimaries {
|
namespace NColorPrimaries {
|
||||||
|
|
@ -102,6 +109,7 @@ namespace NColorManagement {
|
||||||
.blue = {.x = 0.150, .y = 0.060},
|
.blue = {.x = 0.150, .y = 0.060},
|
||||||
.white = {.x = 0.314, .y = 0.351},
|
.white = {.x = 0.314, .y = 0.351},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const auto DISPLAY_P3 = SPCPRimaries{
|
static const auto DISPLAY_P3 = SPCPRimaries{
|
||||||
.red = {.x = 0.680, .y = 0.320},
|
.red = {.x = 0.680, .y = 0.320},
|
||||||
.green = {.x = 0.265, .y = 0.690},
|
.green = {.x = 0.265, .y = 0.690},
|
||||||
|
|
@ -125,6 +133,9 @@ namespace NColorManagement {
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
uint32_t length = 0;
|
uint32_t length = 0;
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
|
bool operator==(const SIccFile& i2) const {
|
||||||
|
return fd == i2.fd;
|
||||||
|
}
|
||||||
} icc;
|
} icc;
|
||||||
|
|
||||||
bool windowsScRGB = false;
|
bool windowsScRGB = false;
|
||||||
|
|
@ -135,7 +146,8 @@ namespace NColorManagement {
|
||||||
bool primariesNameSet = false;
|
bool primariesNameSet = false;
|
||||||
ePrimaries primariesNamed = CM_PRIMARIES_SRGB;
|
ePrimaries primariesNamed = CM_PRIMARIES_SRGB;
|
||||||
// primaries are stored as FP values with the same scale as standard defines (0.0 - 1.0)
|
// primaries are stored as FP values with the same scale as standard defines (0.0 - 1.0)
|
||||||
// wayland protocol expects int32_t values multiplied by 10000
|
// wayland protocol expects int32_t values multiplied by 1000000
|
||||||
|
// xx protocol expects int32_t values multiplied by 10000
|
||||||
// drm expects uint16_t values multiplied by 50000
|
// drm expects uint16_t values multiplied by 50000
|
||||||
// frog protocol expects drm values
|
// frog protocol expects drm values
|
||||||
SPCPRimaries primaries, masteringPrimaries;
|
SPCPRimaries primaries, masteringPrimaries;
|
||||||
|
|
@ -146,13 +158,32 @@ namespace NColorManagement {
|
||||||
float min = 0.2; // 0.2 cd/m²
|
float min = 0.2; // 0.2 cd/m²
|
||||||
uint32_t max = 80; // 80 cd/m²
|
uint32_t max = 80; // 80 cd/m²
|
||||||
uint32_t reference = 80; // 80 cd/m²
|
uint32_t reference = 80; // 80 cd/m²
|
||||||
|
bool operator==(const SPCLuminances& l2) const {
|
||||||
|
return min == l2.min && max == l2.max && reference == l2.reference;
|
||||||
|
}
|
||||||
} luminances;
|
} luminances;
|
||||||
struct SPCMasteringLuminances {
|
struct SPCMasteringLuminances {
|
||||||
float min = 0;
|
float min = 0;
|
||||||
uint32_t max = 0;
|
uint32_t max = 0;
|
||||||
|
bool operator==(const SPCMasteringLuminances& l2) const {
|
||||||
|
return min == l2.min && max == l2.max;
|
||||||
|
}
|
||||||
} masteringLuminances;
|
} masteringLuminances;
|
||||||
|
|
||||||
uint32_t maxCLL = 0;
|
uint32_t maxCLL = 0;
|
||||||
uint32_t maxFALL = 0;
|
uint32_t maxFALL = 0;
|
||||||
|
|
||||||
|
bool operator==(const SImageDescription& d2) const {
|
||||||
|
return (id != 0 && id == d2.id) ||
|
||||||
|
(icc == d2.icc && windowsScRGB == d2.windowsScRGB && transferFunction == d2.transferFunction && transferFunctionPower == d2.transferFunctionPower &&
|
||||||
|
((primariesNameSet && primariesNamed == d2.primariesNameSet) || (primaries == d2.primaries)) && masteringPrimaries == d2.masteringPrimaries &&
|
||||||
|
luminances == d2.luminances && masteringLuminances == d2.masteringLuminances && maxCLL == d2.maxCLL && maxFALL == d2.maxFALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SPCPRimaries& getPrimaries() const {
|
||||||
|
if (primariesNameSet || primaries == SPCPRimaries{})
|
||||||
|
return NColorManagement::getPrimaries(primariesNamed);
|
||||||
|
return primaries;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "../desktop/LayerSurface.hpp"
|
#include "../desktop/LayerSurface.hpp"
|
||||||
#include "../protocols/LayerShell.hpp"
|
#include "../protocols/LayerShell.hpp"
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
|
#include "../protocols/ColorManagement.hpp"
|
||||||
#include "../managers/HookSystemManager.hpp"
|
#include "../managers/HookSystemManager.hpp"
|
||||||
#include "../managers/input/InputManager.hpp"
|
#include "../managers/input/InputManager.hpp"
|
||||||
#include "pass/TexPassElement.hpp"
|
#include "pass/TexPassElement.hpp"
|
||||||
|
|
@ -20,6 +21,7 @@
|
||||||
#include <gbm.h>
|
#include <gbm.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
using namespace Hyprutils::OS;
|
using namespace Hyprutils::OS;
|
||||||
|
using namespace NColorManagement;
|
||||||
|
|
||||||
const std::vector<const char*> ASSET_PATHS = {
|
const std::vector<const char*> ASSET_PATHS = {
|
||||||
#ifdef DATAROOTDIR
|
#ifdef DATAROOTDIR
|
||||||
|
|
@ -866,6 +868,39 @@ void CHyprOpenGLImpl::initShaders() {
|
||||||
m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius");
|
m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius");
|
||||||
m_RenderData.pCurrentMonData->m_shQUAD.roundingPower = glGetUniformLocation(prog, "roundingPower");
|
m_RenderData.pCurrentMonData->m_shQUAD.roundingPower = glGetUniformLocation(prog, "roundingPower");
|
||||||
|
|
||||||
|
#ifndef GLES2
|
||||||
|
prog = createProgram(TEXVERTSRC320, TEXFRAGSRCCM);
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.program = prog;
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.proj = glGetUniformLocation(prog, "proj");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.tex = glGetUniformLocation(prog, "tex");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.texType = glGetUniformLocation(prog, "texType");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.skipCM = glGetUniformLocation(prog, "skipCM");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.sourceTF = glGetUniformLocation(prog, "sourceTF");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.targetTF = glGetUniformLocation(prog, "targetTF");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.sourcePrimaries = glGetUniformLocation(prog, "sourcePrimaries");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.targetPrimaries = glGetUniformLocation(prog, "targetPrimaries");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.maxLuminance = glGetUniformLocation(prog, "maxLuminance");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.dstMaxLuminance = glGetUniformLocation(prog, "dstMaxLuminance");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.dstRefLuminance = glGetUniformLocation(prog, "dstRefLuminance");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.sdrSaturation = glGetUniformLocation(prog, "sdrSaturation");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.sdrBrightness = glGetUniformLocation(prog, "sdrBrightnessMultiplier");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.alphaMatte = glGetUniformLocation(prog, "texMatte");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.alpha = glGetUniformLocation(prog, "alpha");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.texAttrib = glGetAttribLocation(prog, "texcoord");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.matteTexAttrib = glGetAttribLocation(prog, "texcoordMatte");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.posAttrib = glGetAttribLocation(prog, "pos");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.discardAlpha = glGetUniformLocation(prog, "discardAlpha");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.topLeft = glGetUniformLocation(prog, "topLeft");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.fullSize = glGetUniformLocation(prog, "fullSize");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.radius = glGetUniformLocation(prog, "radius");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.roundingPower = glGetUniformLocation(prog, "roundingPower");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.applyTint = glGetUniformLocation(prog, "applyTint");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.tint = glGetUniformLocation(prog, "tint");
|
||||||
|
m_RenderData.pCurrentMonData->m_shCM.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte");
|
||||||
|
#endif
|
||||||
|
|
||||||
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA);
|
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA);
|
||||||
m_RenderData.pCurrentMonData->m_shRGBA.program = prog;
|
m_RenderData.pCurrentMonData->m_shRGBA.program = prog;
|
||||||
m_RenderData.pCurrentMonData->m_shRGBA.proj = glGetUniformLocation(prog, "proj");
|
m_RenderData.pCurrentMonData->m_shRGBA.proj = glGetUniformLocation(prog, "proj");
|
||||||
|
|
@ -1280,7 +1315,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
|
||||||
CBox newBox = box;
|
CBox newBox = box;
|
||||||
m_RenderData.renderModif.applyToBox(newBox);
|
m_RenderData.renderModif.applyToBox(newBox);
|
||||||
|
|
||||||
static auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
|
static auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
|
||||||
|
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
||||||
|
|
||||||
// get the needed transform for this texture
|
// get the needed transform for this texture
|
||||||
const bool TRANSFORMS_MATCH = wlTransformToHyprutils(m_RenderData.pMonitor->transform) == tex->m_eTransform; // FIXME: combine them properly!!!
|
const bool TRANSFORMS_MATCH = wlTransformToHyprutils(m_RenderData.pMonitor->transform) == tex->m_eTransform; // FIXME: combine them properly!!!
|
||||||
|
|
@ -1304,6 +1340,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
|
||||||
|
|
||||||
const bool CRASHING = m_bApplyFinalShader && g_pHyprRenderer->m_bCrashingInProgress;
|
const bool CRASHING = m_bApplyFinalShader && g_pHyprRenderer->m_bCrashingInProgress;
|
||||||
|
|
||||||
|
auto texType = tex->m_iType;
|
||||||
|
|
||||||
if (CRASHING) {
|
if (CRASHING) {
|
||||||
shader = &m_RenderData.pCurrentMonData->m_shGLITCH;
|
shader = &m_RenderData.pCurrentMonData->m_shGLITCH;
|
||||||
usingFinalShader = true;
|
usingFinalShader = true;
|
||||||
|
|
@ -1316,16 +1354,27 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
|
||||||
usingFinalShader = true;
|
usingFinalShader = true;
|
||||||
} else {
|
} else {
|
||||||
switch (tex->m_iType) {
|
switch (tex->m_iType) {
|
||||||
|
#ifdef GLES2
|
||||||
case TEXTURE_RGBA: shader = &m_RenderData.pCurrentMonData->m_shRGBA; break;
|
case TEXTURE_RGBA: shader = &m_RenderData.pCurrentMonData->m_shRGBA; break;
|
||||||
case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shRGBX; break;
|
case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shRGBX; break;
|
||||||
case TEXTURE_EXTERNAL: shader = &m_RenderData.pCurrentMonData->m_shEXT; break;
|
#else
|
||||||
|
case TEXTURE_RGBA:
|
||||||
|
case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shCM; break;
|
||||||
|
#endif
|
||||||
|
case TEXTURE_EXTERNAL: shader = &m_RenderData.pCurrentMonData->m_shEXT; break; // might be unused
|
||||||
default: RASSERT(false, "tex->m_iTarget unsupported!");
|
default: RASSERT(false, "tex->m_iTarget unsupported!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.RGBX.valueOrDefault())
|
if (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.RGBX.valueOrDefault()) {
|
||||||
|
#ifdef GLES2
|
||||||
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
|
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
|
||||||
|
#else
|
||||||
|
shader = &m_RenderData.pCurrentMonData->m_shCM;
|
||||||
|
#endif
|
||||||
|
texType = TEXTURE_RGBX;
|
||||||
|
}
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(tex->m_iTarget, tex->m_iTexID);
|
glBindTexture(tex->m_iTarget, tex->m_iTexID);
|
||||||
|
|
@ -1350,6 +1399,49 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
|
||||||
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
|
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
|
||||||
#endif
|
#endif
|
||||||
glUniform1i(shader->tex, 0);
|
glUniform1i(shader->tex, 0);
|
||||||
|
#ifndef GLES2
|
||||||
|
if (!usingFinalShader && (texType == TEXTURE_RGBA || texType == TEXTURE_RGBX)) {
|
||||||
|
const bool skipCM = *PPASS && m_RenderData.pMonitor->activeWorkspace && m_RenderData.pMonitor->activeWorkspace->m_bHasFullscreenWindow &&
|
||||||
|
m_RenderData.pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
|
||||||
|
glUniform1i(shader->texType, texType);
|
||||||
|
glUniform1i(shader->skipCM, skipCM);
|
||||||
|
if (!skipCM) {
|
||||||
|
const auto imageDescription =
|
||||||
|
m_RenderData.surface.valid() && m_RenderData.surface->colorManagement.valid() ? m_RenderData.surface->colorManagement->imageDescription() : SImageDescription{};
|
||||||
|
glUniform1i(shader->sourceTF, imageDescription.transferFunction);
|
||||||
|
glUniform1i(shader->targetTF, m_RenderData.pMonitor->imageDescription.transferFunction);
|
||||||
|
const auto sourcePrimaries =
|
||||||
|
imageDescription.primariesNameSet || imageDescription.primaries == SPCPRimaries{} ? getPrimaries(imageDescription.primariesNamed) : imageDescription.primaries;
|
||||||
|
const auto targetPrimaries = m_RenderData.pMonitor->imageDescription.primariesNameSet || m_RenderData.pMonitor->imageDescription.primaries == SPCPRimaries{} ?
|
||||||
|
getPrimaries(m_RenderData.pMonitor->imageDescription.primariesNamed) :
|
||||||
|
m_RenderData.pMonitor->imageDescription.primaries;
|
||||||
|
|
||||||
|
const GLfloat glSourcePrimaries[8] = {
|
||||||
|
sourcePrimaries.red.x, sourcePrimaries.red.y, sourcePrimaries.green.x, sourcePrimaries.green.y,
|
||||||
|
sourcePrimaries.blue.x, sourcePrimaries.blue.y, sourcePrimaries.white.x, sourcePrimaries.white.y,
|
||||||
|
};
|
||||||
|
const GLfloat glTargetPrimaries[8] = {
|
||||||
|
targetPrimaries.red.x, targetPrimaries.red.y, targetPrimaries.green.x, targetPrimaries.green.y,
|
||||||
|
targetPrimaries.blue.x, targetPrimaries.blue.y, targetPrimaries.white.x, targetPrimaries.white.y,
|
||||||
|
};
|
||||||
|
glUniformMatrix4x2fv(shader->sourcePrimaries, 1, false, glSourcePrimaries);
|
||||||
|
glUniformMatrix4x2fv(shader->targetPrimaries, 1, false, glTargetPrimaries);
|
||||||
|
|
||||||
|
const float maxLuminance = imageDescription.luminances.max > 0 ? imageDescription.luminances.max : imageDescription.luminances.reference;
|
||||||
|
glUniform1f(shader->maxLuminance, maxLuminance * m_RenderData.pMonitor->imageDescription.luminances.reference / imageDescription.luminances.reference);
|
||||||
|
glUniform1f(shader->dstMaxLuminance, m_RenderData.pMonitor->imageDescription.luminances.max > 0 ? m_RenderData.pMonitor->imageDescription.luminances.max : 10000);
|
||||||
|
glUniform1f(shader->dstRefLuminance, m_RenderData.pMonitor->imageDescription.luminances.reference);
|
||||||
|
glUniform1f(shader->sdrSaturation,
|
||||||
|
m_RenderData.pMonitor->sdrSaturation > 0 && m_RenderData.pMonitor->imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
|
||||||
|
m_RenderData.pMonitor->sdrSaturation :
|
||||||
|
1.0f);
|
||||||
|
glUniform1f(shader->sdrBrightness,
|
||||||
|
m_RenderData.pMonitor->sdrBrightness > 0 && m_RenderData.pMonitor->imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
|
||||||
|
m_RenderData.pMonitor->sdrBrightness :
|
||||||
|
1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((usingFinalShader && *PDT == 0) || CRASHING) {
|
if ((usingFinalShader && *PDT == 0) || CRASHING) {
|
||||||
glUniform1f(shader->time, m_tGlobalTimer.getSeconds() - shader->initialTime);
|
glUniform1f(shader->time, m_tGlobalTimer.getSeconds() - shader->initialTime);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include <hyprutils/os/FileDescriptor.hpp>
|
#include <hyprutils/os/FileDescriptor.hpp>
|
||||||
|
|
||||||
#include "../debug/TracyDefines.hpp"
|
#include "../debug/TracyDefines.hpp"
|
||||||
|
#include "../protocols/core/Compositor.hpp"
|
||||||
|
|
||||||
struct gbm_device;
|
struct gbm_device;
|
||||||
class CHyprRenderer;
|
class CHyprRenderer;
|
||||||
|
|
@ -105,41 +106,42 @@ struct SMonitorRenderData {
|
||||||
CShader m_shSHADOW;
|
CShader m_shSHADOW;
|
||||||
CShader m_shBORDER1;
|
CShader m_shBORDER1;
|
||||||
CShader m_shGLITCH;
|
CShader m_shGLITCH;
|
||||||
//
|
CShader m_shCM;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SCurrentRenderData {
|
struct SCurrentRenderData {
|
||||||
PHLMONITORREF pMonitor;
|
PHLMONITORREF pMonitor;
|
||||||
Mat3x3 projection;
|
Mat3x3 projection;
|
||||||
Mat3x3 savedProjection;
|
Mat3x3 savedProjection;
|
||||||
Mat3x3 monitorProjection;
|
Mat3x3 monitorProjection;
|
||||||
|
|
||||||
SMonitorRenderData* pCurrentMonData = nullptr;
|
SMonitorRenderData* pCurrentMonData = nullptr;
|
||||||
CFramebuffer* currentFB = nullptr; // current rendering to
|
CFramebuffer* currentFB = nullptr; // current rendering to
|
||||||
CFramebuffer* mainFB = nullptr; // main to render to
|
CFramebuffer* mainFB = nullptr; // main to render to
|
||||||
CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc)
|
CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc)
|
||||||
|
|
||||||
CRegion damage;
|
CRegion damage;
|
||||||
CRegion finalDamage; // damage used for funal off -> main
|
CRegion finalDamage; // damage used for funal off -> main
|
||||||
|
|
||||||
SRenderModifData renderModif;
|
SRenderModifData renderModif;
|
||||||
float mouseZoomFactor = 1.f;
|
float mouseZoomFactor = 1.f;
|
||||||
bool mouseZoomUseMouse = true; // true by default
|
bool mouseZoomUseMouse = true; // true by default
|
||||||
bool useNearestNeighbor = false;
|
bool useNearestNeighbor = false;
|
||||||
bool blockScreenShader = false;
|
bool blockScreenShader = false;
|
||||||
bool simplePass = false;
|
bool simplePass = false;
|
||||||
|
|
||||||
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||||
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||||
|
|
||||||
CBox clipBox = {}; // scaled coordinates
|
CBox clipBox = {}; // scaled coordinates
|
||||||
CRegion clipRegion;
|
CRegion clipRegion;
|
||||||
|
|
||||||
uint32_t discardMode = DISCARD_OPAQUE;
|
uint32_t discardMode = DISCARD_OPAQUE;
|
||||||
float discardOpacity = 0.f;
|
float discardOpacity = 0.f;
|
||||||
|
|
||||||
PHLLSREF currentLS;
|
PHLLSREF currentLS;
|
||||||
PHLWINDOWREF currentWindow;
|
PHLWINDOWREF currentWindow;
|
||||||
|
WP<CWLSurfaceResource> surface;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CEGLSync {
|
class CEGLSync {
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@
|
||||||
#include "pass/RendererHintsPassElement.hpp"
|
#include "pass/RendererHintsPassElement.hpp"
|
||||||
#include "pass/SurfacePassElement.hpp"
|
#include "pass/SurfacePassElement.hpp"
|
||||||
#include "debug/Log.hpp"
|
#include "debug/Log.hpp"
|
||||||
#include "protocols/ColorManagement.hpp"
|
#include "../protocols/ColorManagement.hpp"
|
||||||
#if AQUAMARINE_VERSION_NUMBER > 702 // >0.7.2
|
#if AQUAMARINE_VERSION_NUMBER > 702 // >0.7.2
|
||||||
#include "protocols/types/ContentType.hpp"
|
#include "../protocols/types/ContentType.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||||
|
|
@ -1409,78 +1409,40 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const auto BT709 = Aquamarine::IOutput::SChromaticityCoords{
|
static const hdr_output_metadata NO_HDR_METADATA = {.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}};
|
||||||
.red = Aquamarine::IOutput::xy{.x = 0.64, .y = 0.33},
|
|
||||||
.green = Aquamarine::IOutput::xy{.x = 0.30, .y = 0.60},
|
|
||||||
.blue = Aquamarine::IOutput::xy{.x = 0.15, .y = 0.06},
|
|
||||||
.white = Aquamarine::IOutput::xy{.x = 0.3127, .y = 0.3290},
|
|
||||||
};
|
|
||||||
|
|
||||||
static hdr_output_metadata createHDRMetadata(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid) {
|
static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamarine::IOutput::SParsedEDID edid) {
|
||||||
if (eotf == 0)
|
|
||||||
return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR
|
|
||||||
|
|
||||||
const auto toNits = [](float value) { return uint16_t(std::round(value)); };
|
|
||||||
const auto to16Bit = [](float value) { return uint16_t(std::round(value * 50000)); };
|
|
||||||
const auto colorimetry = edid.chromaticityCoords.value_or(BT709);
|
|
||||||
|
|
||||||
Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x,
|
|
||||||
colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y);
|
|
||||||
Debug::log(TRACE, "ColorManagement max avg {}, min {}, max {}", edid.hdrMetadata->desiredMaxFrameAverageLuminance, edid.hdrMetadata->desiredContentMinLuminance,
|
|
||||||
edid.hdrMetadata->desiredContentMaxLuminance);
|
|
||||||
return hdr_output_metadata{
|
|
||||||
.metadata_type = 0,
|
|
||||||
.hdmi_metadata_type1 =
|
|
||||||
hdr_metadata_infoframe{
|
|
||||||
.eotf = eotf,
|
|
||||||
.metadata_type = 0,
|
|
||||||
.display_primaries =
|
|
||||||
{
|
|
||||||
{.x = to16Bit(colorimetry.red.x), .y = to16Bit(colorimetry.red.y)},
|
|
||||||
{.x = to16Bit(colorimetry.green.x), .y = to16Bit(colorimetry.green.y)},
|
|
||||||
{.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)},
|
|
||||||
},
|
|
||||||
.white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)},
|
|
||||||
.max_display_mastering_luminance = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance),
|
|
||||||
.min_display_mastering_luminance = toNits(edid.hdrMetadata->desiredContentMinLuminance * 10000),
|
|
||||||
.max_cll = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance),
|
|
||||||
.max_fall = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamarine::IOutput::SParsedEDID edid) {
|
|
||||||
if (settings.transferFunction != CM_TRANSFER_FUNCTION_ST2084_PQ)
|
if (settings.transferFunction != CM_TRANSFER_FUNCTION_ST2084_PQ)
|
||||||
return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR
|
return NO_HDR_METADATA; // empty metadata for SDR
|
||||||
|
|
||||||
const auto toNits = [](uint32_t value) { return uint16_t(std::round(value)); };
|
const auto toNits = [](uint32_t value) { return uint16_t(std::round(value)); };
|
||||||
const auto to16Bit = [](uint32_t value) { return uint16_t(std::round(value * 50000)); };
|
const auto to16Bit = [](uint32_t value) { return uint16_t(std::round(value * 50000)); };
|
||||||
|
|
||||||
auto colorimetry = settings.primaries;
|
auto colorimetry = settings.primariesNameSet || settings.primaries == SPCPRimaries{} ? getPrimaries(settings.primariesNamed) : settings.primaries;
|
||||||
auto luminances = settings.masteringLuminances.max > 0 ?
|
auto luminances = settings.masteringLuminances.max > 0 ?
|
||||||
settings.masteringLuminances :
|
settings.masteringLuminances :
|
||||||
SImageDescription::SPCMasteringLuminances{.min = edid.hdrMetadata->desiredContentMinLuminance, .max = edid.hdrMetadata->desiredContentMaxLuminance};
|
SImageDescription::SPCMasteringLuminances{.min = edid.hdrMetadata->desiredContentMinLuminance, .max = edid.hdrMetadata->desiredContentMaxLuminance};
|
||||||
|
|
||||||
Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x,
|
Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x,
|
||||||
colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y);
|
colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y);
|
||||||
Debug::log(TRACE, "ColorManagement min {}, max {}, cll {}, fall {}", luminances.min, luminances.max, settings.maxCLL, settings.maxFALL);
|
Debug::log(TRACE, "ColorManagement min {}, max {}, cll {}, fall {}", luminances.min, luminances.max, settings.maxCLL, settings.maxFALL);
|
||||||
return hdr_output_metadata{
|
return hdr_output_metadata{
|
||||||
.metadata_type = 0,
|
.metadata_type = 0,
|
||||||
.hdmi_metadata_type1 =
|
.hdmi_metadata_type1 =
|
||||||
hdr_metadata_infoframe{
|
hdr_metadata_infoframe{
|
||||||
.eotf = 2,
|
.eotf = 2,
|
||||||
.metadata_type = 0,
|
.metadata_type = 0,
|
||||||
.display_primaries =
|
.display_primaries =
|
||||||
{
|
{
|
||||||
{.x = to16Bit(colorimetry.red.x), .y = to16Bit(colorimetry.red.y)},
|
{.x = to16Bit(colorimetry.red.x), .y = to16Bit(colorimetry.red.y)},
|
||||||
{.x = to16Bit(colorimetry.green.x), .y = to16Bit(colorimetry.green.y)},
|
{.x = to16Bit(colorimetry.green.x), .y = to16Bit(colorimetry.green.y)},
|
||||||
{.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)},
|
{.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)},
|
||||||
},
|
},
|
||||||
.white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)},
|
.white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)},
|
||||||
.max_display_mastering_luminance = toNits(luminances.max),
|
.max_display_mastering_luminance = toNits(luminances.max),
|
||||||
.min_display_mastering_luminance = toNits(luminances.min * 10000),
|
.min_display_mastering_luminance = toNits(luminances.min * 10000),
|
||||||
.max_cll = toNits(settings.maxCLL),
|
.max_cll = toNits(settings.maxCLL),
|
||||||
.max_fall = toNits(settings.maxFALL),
|
.max_fall = toNits(settings.maxFALL),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1495,12 +1457,14 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
||||||
if (inFD.isValid())
|
if (inFD.isValid())
|
||||||
pMonitor->output->state->setExplicitInFence(inFD.get());
|
pMonitor->output->state->setExplicitInFence(inFD.get());
|
||||||
|
|
||||||
static auto PHDR = CConfigValue<Hyprlang::INT>("experimental:hdr");
|
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
||||||
|
const bool PHDR = pMonitor->imageDescription.transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ;
|
||||||
|
|
||||||
const bool SUPPORTSPQ = pMonitor->output->parsedEDID.hdrMetadata.has_value() ? pMonitor->output->parsedEDID.hdrMetadata->supportsPQ : false;
|
const bool SUPPORTSPQ = pMonitor->output->parsedEDID.hdrMetadata.has_value() ? pMonitor->output->parsedEDID.hdrMetadata->supportsPQ : false;
|
||||||
Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, SUPPORTSPQ);
|
Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, SUPPORTSPQ);
|
||||||
|
|
||||||
if (pMonitor->output->parsedEDID.supportsBT2020 && SUPPORTSPQ) {
|
if (pMonitor->output->parsedEDID.supportsBT2020 && SUPPORTSPQ) {
|
||||||
if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) {
|
if (*PPASS && pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) {
|
||||||
const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow();
|
const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow();
|
||||||
const auto ROOT_SURF = WINDOW->m_pWLSurface->resource();
|
const auto ROOT_SURF = WINDOW->m_pWLSurface->resource();
|
||||||
const auto SURF =
|
const auto SURF =
|
||||||
|
|
@ -1512,18 +1476,17 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
||||||
SURF->colorManagement->setHDRMetadata(createHDRMetadata(SURF->colorManagement->imageDescription(), pMonitor->output->parsedEDID));
|
SURF->colorManagement->setHDRMetadata(createHDRMetadata(SURF->colorManagement->imageDescription(), pMonitor->output->parsedEDID));
|
||||||
if (needsHdrMetadataUpdate)
|
if (needsHdrMetadataUpdate)
|
||||||
pMonitor->output->state->setHDRMetadata(SURF->colorManagement->hdrMetadata());
|
pMonitor->output->state->setHDRMetadata(SURF->colorManagement->hdrMetadata());
|
||||||
} else if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != *PHDR)
|
} else if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != PHDR)
|
||||||
pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID));
|
pMonitor->output->state->setHDRMetadata(PHDR ? createHDRMetadata(pMonitor->imageDescription, pMonitor->output->parsedEDID) : NO_HDR_METADATA);
|
||||||
pMonitor->m_previousFSWindow = WINDOW;
|
pMonitor->m_previousFSWindow = WINDOW;
|
||||||
} else {
|
} else {
|
||||||
if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != *PHDR)
|
if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != PHDR)
|
||||||
pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID));
|
pMonitor->output->state->setHDRMetadata(PHDR ? createHDRMetadata(pMonitor->imageDescription, pMonitor->output->parsedEDID) : NO_HDR_METADATA);
|
||||||
pMonitor->m_previousFSWindow.reset();
|
pMonitor->m_previousFSWindow.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto PWIDE = CConfigValue<Hyprlang::INT>("experimental:wide_color_gamut");
|
const bool needsWCG = pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2 || pMonitor->imageDescription.primariesNamed == CM_PRIMARIES_BT2020;
|
||||||
const bool needsWCG = *PWIDE || pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2;
|
|
||||||
if (pMonitor->output->state->state().wideColorGamut != needsWCG) {
|
if (pMonitor->output->state->state().wideColorGamut != needsWCG) {
|
||||||
Debug::log(TRACE, "Setting wide color gamut {}", needsWCG ? "on" : "off");
|
Debug::log(TRACE, "Setting wide color gamut {}", needsWCG ? "on" : "off");
|
||||||
pMonitor->output->state->setWideColorGamut(needsWCG);
|
pMonitor->output->state->setWideColorGamut(needsWCG);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,17 @@ class CShader {
|
||||||
GLint proj = -1;
|
GLint proj = -1;
|
||||||
GLint color = -1;
|
GLint color = -1;
|
||||||
GLint alphaMatte = -1;
|
GLint alphaMatte = -1;
|
||||||
|
GLint texType = -1;
|
||||||
|
GLint skipCM = -1;
|
||||||
|
GLint sourceTF = -1;
|
||||||
|
GLint targetTF = -1;
|
||||||
|
GLint sourcePrimaries = -1;
|
||||||
|
GLint targetPrimaries = -1;
|
||||||
|
GLint maxLuminance = -1;
|
||||||
|
GLint dstMaxLuminance = -1;
|
||||||
|
GLint dstRefLuminance = -1;
|
||||||
|
GLint sdrSaturation = -1; // sdr -> hdr saturation
|
||||||
|
GLint sdrBrightness = -1; // sdr -> hdr brightness multiplier
|
||||||
GLint tex = -1;
|
GLint tex = -1;
|
||||||
GLint alpha = -1;
|
GLint alpha = -1;
|
||||||
GLint posAttrib = -1;
|
GLint posAttrib = -1;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ CSurfacePassElement::CSurfacePassElement(const CSurfacePassElement::SRenderData&
|
||||||
|
|
||||||
void CSurfacePassElement::draw(const CRegion& damage) {
|
void CSurfacePassElement::draw(const CRegion& damage) {
|
||||||
g_pHyprOpenGL->m_RenderData.currentWindow = data.pWindow;
|
g_pHyprOpenGL->m_RenderData.currentWindow = data.pWindow;
|
||||||
|
g_pHyprOpenGL->m_RenderData.surface = data.surface;
|
||||||
g_pHyprOpenGL->m_RenderData.currentLS = data.pLS;
|
g_pHyprOpenGL->m_RenderData.currentLS = data.pLS;
|
||||||
g_pHyprOpenGL->m_RenderData.clipBox = data.clipBox;
|
g_pHyprOpenGL->m_RenderData.clipBox = data.clipBox;
|
||||||
g_pHyprOpenGL->m_RenderData.discardMode = data.discardMode;
|
g_pHyprOpenGL->m_RenderData.discardMode = data.discardMode;
|
||||||
|
|
@ -36,6 +37,7 @@ void CSurfacePassElement::draw(const CRegion& damage) {
|
||||||
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
|
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
|
||||||
g_pHyprOpenGL->m_bEndFrame = false;
|
g_pHyprOpenGL->m_bEndFrame = false;
|
||||||
g_pHyprOpenGL->m_RenderData.currentWindow.reset();
|
g_pHyprOpenGL->m_RenderData.currentWindow.reset();
|
||||||
|
g_pHyprOpenGL->m_RenderData.surface.reset();
|
||||||
g_pHyprOpenGL->m_RenderData.currentLS.reset();
|
g_pHyprOpenGL->m_RenderData.currentLS.reset();
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
|
||||||
439
src/render/shaders/CM.frag
Normal file
439
src/render/shaders/CM.frag
Normal file
|
|
@ -0,0 +1,439 @@
|
||||||
|
R"#(
|
||||||
|
#version 320 es
|
||||||
|
//#extension GL_OES_EGL_image_external : require
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
in vec2 v_texcoord;
|
||||||
|
uniform sampler2D tex;
|
||||||
|
//uniform samplerExternalOES texture0;
|
||||||
|
|
||||||
|
uniform int texType; // eTextureType: 0 - rgba, 1 - rgbx, 2 - ext
|
||||||
|
uniform int skipCM;
|
||||||
|
uniform int sourceTF; // eTransferFunction
|
||||||
|
uniform int targetTF; // eTransferFunction
|
||||||
|
uniform mat4x2 sourcePrimaries;
|
||||||
|
uniform mat4x2 targetPrimaries;
|
||||||
|
uniform float maxLuminance;
|
||||||
|
uniform float dstMaxLuminance;
|
||||||
|
uniform float dstRefLuminance;
|
||||||
|
uniform float sdrSaturation;
|
||||||
|
uniform float sdrBrightnessMultiplier;
|
||||||
|
|
||||||
|
uniform float alpha;
|
||||||
|
|
||||||
|
uniform vec2 topLeft;
|
||||||
|
uniform vec2 fullSize;
|
||||||
|
uniform float radius;
|
||||||
|
uniform float roundingPower;
|
||||||
|
|
||||||
|
uniform int discardOpaque;
|
||||||
|
uniform int discardAlpha;
|
||||||
|
uniform float discardAlphaValue;
|
||||||
|
|
||||||
|
uniform int applyTint;
|
||||||
|
uniform vec3 tint;
|
||||||
|
|
||||||
|
//enum eTransferFunction
|
||||||
|
#define CM_TRANSFER_FUNCTION_BT1886 1
|
||||||
|
#define CM_TRANSFER_FUNCTION_GAMMA22 2
|
||||||
|
#define CM_TRANSFER_FUNCTION_GAMMA28 3
|
||||||
|
#define CM_TRANSFER_FUNCTION_ST240 4
|
||||||
|
#define CM_TRANSFER_FUNCTION_EXT_LINEAR 5
|
||||||
|
#define CM_TRANSFER_FUNCTION_LOG_100 6
|
||||||
|
#define CM_TRANSFER_FUNCTION_LOG_316 7
|
||||||
|
#define CM_TRANSFER_FUNCTION_XVYCC 8
|
||||||
|
#define CM_TRANSFER_FUNCTION_SRGB 9
|
||||||
|
#define CM_TRANSFER_FUNCTION_EXT_SRGB 10
|
||||||
|
#define CM_TRANSFER_FUNCTION_ST2084_PQ 11
|
||||||
|
#define CM_TRANSFER_FUNCTION_ST428 12
|
||||||
|
#define CM_TRANSFER_FUNCTION_HLG 13
|
||||||
|
|
||||||
|
// sRGB constants
|
||||||
|
#define SRGB_POW 2.4
|
||||||
|
#define SRGB_INV_POW (1.0 / SRGB_POW)
|
||||||
|
#define SRGB_D_CUT 0.04045
|
||||||
|
#define SRGB_E_CUT 0.0031308
|
||||||
|
#define SRGB_LO 12.92
|
||||||
|
#define SRGB_HI 1.055
|
||||||
|
#define SRGB_HI_ADD 0.055
|
||||||
|
|
||||||
|
// 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 (sqrt(3.0) * pow(HLG_D_CUT, 0.5))
|
||||||
|
#define HLG_A 0.17883277
|
||||||
|
#define HLG_B 0.28466892
|
||||||
|
#define HLG_C 0.55991073
|
||||||
|
|
||||||
|
#define SDR_MIN_LUMINANCE 0.2
|
||||||
|
#define SDR_MAX_LUMINANCE 80.0
|
||||||
|
#define HDR_MIN_LUMINANCE 0.005
|
||||||
|
#define HDR_MAX_LUMINANCE 10000.0
|
||||||
|
#define HLG_MAX_LUMINANCE 1000.0
|
||||||
|
|
||||||
|
// smoothing constant for the edge: more = blurrier, but smoother
|
||||||
|
#define M_PI 3.1415926535897932384626433832795
|
||||||
|
#define M_E 2.718281828459045
|
||||||
|
#define SMOOTHING_CONSTANT (M_PI / 5.34665792551)
|
||||||
|
|
||||||
|
vec4 rounding(vec4 color) {
|
||||||
|
highp vec2 pixCoord = vec2(gl_FragCoord);
|
||||||
|
pixCoord -= topLeft + fullSize * 0.5;
|
||||||
|
pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
|
||||||
|
pixCoord -= fullSize * 0.5 - radius;
|
||||||
|
pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix dont make it top-left
|
||||||
|
|
||||||
|
if (pixCoord.x + pixCoord.y > radius) {
|
||||||
|
float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0/roundingPower);
|
||||||
|
|
||||||
|
if (dist > radius + SMOOTHING_CONSTANT)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0));
|
||||||
|
|
||||||
|
color *= normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 xy2xyz(vec2 xy) {
|
||||||
|
if (xy.y == 0.0)
|
||||||
|
return vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
return vec3(xy.x / xy.y, 1.0, (1.0 - xy.x - xy.y) / xy.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 saturate(vec4 color, mat3 primaries, float saturation) {
|
||||||
|
if (saturation == 1.0)
|
||||||
|
return color;
|
||||||
|
vec3 brightness = vec3(primaries[1][0], primaries[1][1], primaries[1][2]);
|
||||||
|
float Y = dot(color.rgb, brightness);
|
||||||
|
return vec4(mix(vec3(Y), color.rgb, saturation), color[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 toLinearRGB(vec3 color, int tf) {
|
||||||
|
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
||||||
|
return color;
|
||||||
|
|
||||||
|
bvec3 isLow;
|
||||||
|
vec3 lo;
|
||||||
|
vec3 hi;
|
||||||
|
switch (tf) {
|
||||||
|
case CM_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
|
vec3 E = pow(clamp(color.rgb, vec3(0.0), vec3(1.0)), vec3(PQ_INV_M2));
|
||||||
|
return pow(
|
||||||
|
(max(E - PQ_C1, vec3(0.0))) / (PQ_C2 - PQ_C3 * E),
|
||||||
|
vec3(PQ_INV_M1)
|
||||||
|
);
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
return pow(max(color.rgb, vec3(0.0)), vec3(2.2));
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA28:
|
||||||
|
return pow(max(color.rgb, vec3(0.0)), vec3(2.8));
|
||||||
|
case CM_TRANSFER_FUNCTION_HLG:
|
||||||
|
isLow = lessThanEqual(color.rgb, vec3(HLG_D_CUT));
|
||||||
|
lo = sqrt(3.0) * pow(color.rgb, vec3(0.5));
|
||||||
|
hi = HLG_A * log(12.0 * color.rgb - HLG_B) + HLG_C;
|
||||||
|
return mix(hi, lo, isLow);
|
||||||
|
case CM_TRANSFER_FUNCTION_BT1886:
|
||||||
|
case CM_TRANSFER_FUNCTION_ST240:
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_100:
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_316:
|
||||||
|
case CM_TRANSFER_FUNCTION_XVYCC:
|
||||||
|
case CM_TRANSFER_FUNCTION_EXT_SRGB:
|
||||||
|
case CM_TRANSFER_FUNCTION_ST428:
|
||||||
|
|
||||||
|
case CM_TRANSFER_FUNCTION_SRGB:
|
||||||
|
default:
|
||||||
|
isLow = lessThanEqual(color.rgb, vec3(SRGB_D_CUT));
|
||||||
|
lo = color.rgb / SRGB_LO;
|
||||||
|
hi = pow((color.rgb + SRGB_HI_ADD) / SRGB_HI, vec3(SRGB_POW));
|
||||||
|
return mix(hi, lo, isLow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 toLinear(vec4 color, int tf) {
|
||||||
|
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
||||||
|
return color;
|
||||||
|
|
||||||
|
color.rgb /= max(color.a, 0.001);
|
||||||
|
color.rgb = toLinearRGB(color.rgb, tf);
|
||||||
|
color.rgb *= color.a;
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 toNit(vec4 color, int tf) {
|
||||||
|
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
||||||
|
color.rgb = color.rgb * SDR_MAX_LUMINANCE;
|
||||||
|
else {
|
||||||
|
|
||||||
|
switch (tf) {
|
||||||
|
case CM_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
|
color.rgb = color.rgb * (HDR_MAX_LUMINANCE - HDR_MIN_LUMINANCE) + HDR_MIN_LUMINANCE; break;
|
||||||
|
case CM_TRANSFER_FUNCTION_HLG:
|
||||||
|
color.rgb = color.rgb * (HLG_MAX_LUMINANCE - HDR_MIN_LUMINANCE) + HDR_MIN_LUMINANCE; break;
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA28:
|
||||||
|
case CM_TRANSFER_FUNCTION_BT1886:
|
||||||
|
case CM_TRANSFER_FUNCTION_ST240:
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_100:
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_316:
|
||||||
|
case CM_TRANSFER_FUNCTION_XVYCC:
|
||||||
|
case CM_TRANSFER_FUNCTION_EXT_SRGB:
|
||||||
|
case CM_TRANSFER_FUNCTION_ST428:
|
||||||
|
case CM_TRANSFER_FUNCTION_SRGB:
|
||||||
|
default:
|
||||||
|
color.rgb = color.rgb * (SDR_MAX_LUMINANCE - SDR_MIN_LUMINANCE) + SDR_MIN_LUMINANCE; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fromLinearRGB(vec3 color, int tf) {
|
||||||
|
bvec3 isLow;
|
||||||
|
vec3 lo;
|
||||||
|
vec3 hi;
|
||||||
|
|
||||||
|
switch (tf) {
|
||||||
|
case CM_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||||
|
return color;
|
||||||
|
case CM_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
|
vec3 E = pow(clamp(color.rgb, vec3(0.0), vec3(1.0)), vec3(PQ_M1));
|
||||||
|
return pow(
|
||||||
|
(vec3(PQ_C1) + PQ_C2 * E) / (vec3(1.0) + PQ_C3 * E),
|
||||||
|
vec3(PQ_M2)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
return pow(max(color.rgb, vec3(0.0)), vec3(1.0 / 2.2));
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA28:
|
||||||
|
return pow(max(color.rgb, vec3(0.0)), vec3(1.0 / 2.8));
|
||||||
|
case CM_TRANSFER_FUNCTION_HLG:
|
||||||
|
isLow = lessThanEqual(color.rgb, vec3(HLG_E_CUT));
|
||||||
|
lo = pow(color.rgb / sqrt(3.0), vec3(2.0));
|
||||||
|
hi = (pow(vec3(M_E), (color.rgb - HLG_C) / HLG_A) + HLG_B) / 12.0;
|
||||||
|
return mix(hi, lo, isLow);
|
||||||
|
case CM_TRANSFER_FUNCTION_BT1886:
|
||||||
|
case CM_TRANSFER_FUNCTION_ST240:
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_100:
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_316:
|
||||||
|
case CM_TRANSFER_FUNCTION_XVYCC:
|
||||||
|
case CM_TRANSFER_FUNCTION_EXT_SRGB:
|
||||||
|
case CM_TRANSFER_FUNCTION_ST428:
|
||||||
|
|
||||||
|
case CM_TRANSFER_FUNCTION_SRGB:
|
||||||
|
default:
|
||||||
|
isLow = lessThanEqual(color.rgb, vec3(SRGB_E_CUT));
|
||||||
|
lo = color.rgb * SRGB_LO;
|
||||||
|
hi = pow(color.rgb, vec3(SRGB_INV_POW)) * SRGB_HI - SRGB_HI_ADD;
|
||||||
|
return mix(hi, lo, isLow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 fromLinear(vec4 color, int tf) {
|
||||||
|
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
||||||
|
return color;
|
||||||
|
|
||||||
|
color.rgb /= max(color.a, 0.001);
|
||||||
|
color.rgb = fromLinearRGB(color.rgb, tf);
|
||||||
|
color.rgb *= color.a;
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 fromLinearNit(vec4 color, int tf) {
|
||||||
|
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
||||||
|
color.rgb = color.rgb / SDR_MAX_LUMINANCE;
|
||||||
|
else {
|
||||||
|
color.rgb /= max(color.a, 0.001);
|
||||||
|
|
||||||
|
switch (tf) {
|
||||||
|
case CM_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
|
color.rgb = (color.rgb - HDR_MIN_LUMINANCE) / (HDR_MAX_LUMINANCE - HDR_MIN_LUMINANCE); break;
|
||||||
|
case CM_TRANSFER_FUNCTION_HLG:
|
||||||
|
color.rgb = (color.rgb - HDR_MIN_LUMINANCE) / (HLG_MAX_LUMINANCE - HDR_MIN_LUMINANCE); break;
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA28:
|
||||||
|
case CM_TRANSFER_FUNCTION_BT1886:
|
||||||
|
case CM_TRANSFER_FUNCTION_ST240:
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_100:
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_316:
|
||||||
|
case CM_TRANSFER_FUNCTION_XVYCC:
|
||||||
|
case CM_TRANSFER_FUNCTION_EXT_SRGB:
|
||||||
|
case CM_TRANSFER_FUNCTION_ST428:
|
||||||
|
case CM_TRANSFER_FUNCTION_SRGB:
|
||||||
|
default:
|
||||||
|
color.rgb = (color.rgb - SDR_MIN_LUMINANCE) / (SDR_MAX_LUMINANCE - SDR_MIN_LUMINANCE); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
color.rgb = fromLinearRGB(color.rgb, tf);
|
||||||
|
|
||||||
|
color.rgb *= color.a;
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat3 primaries2xyz(mat4x2 primaries) {
|
||||||
|
vec3 r = xy2xyz(primaries[0]);
|
||||||
|
vec3 g = xy2xyz(primaries[1]);
|
||||||
|
vec3 b = xy2xyz(primaries[2]);
|
||||||
|
vec3 w = xy2xyz(primaries[3]);
|
||||||
|
|
||||||
|
mat3 invMat = inverse(
|
||||||
|
mat3(
|
||||||
|
r.x, r.y, r.z,
|
||||||
|
g.x, g.y, g.z,
|
||||||
|
b.x, b.y, b.z
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec3 s = invMat * w;
|
||||||
|
|
||||||
|
return mat3(
|
||||||
|
s.r * r.x, s.r * r.y, s.r * r.z,
|
||||||
|
s.g * g.x, s.g * g.y, s.g * g.z,
|
||||||
|
s.b * b.x, s.b * b.y, s.b * b.z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// const vec2 D65 = vec2(0.3127, 0.3290);
|
||||||
|
const mat3 Bradford = mat3(
|
||||||
|
0.8951, 0.2664, -0.1614,
|
||||||
|
-0.7502, 1.7135, 0.0367,
|
||||||
|
0.0389, -0.0685, 1.0296
|
||||||
|
);
|
||||||
|
const mat3 BradfordInv = inverse(Bradford);
|
||||||
|
|
||||||
|
mat3 adaptWhite(vec2 src, vec2 dst) {
|
||||||
|
if (src == dst)
|
||||||
|
return mat3(
|
||||||
|
1.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
vec3 srcXYZ = xy2xyz(src);
|
||||||
|
vec3 dstXYZ = xy2xyz(dst);
|
||||||
|
vec3 factors = (Bradford * dstXYZ) / (Bradford * srcXYZ);
|
||||||
|
|
||||||
|
return BradfordInv * mat3(
|
||||||
|
factors.x, 0.0, 0.0,
|
||||||
|
0.0, factors.y, 0.0,
|
||||||
|
0.0, 0.0, factors.z
|
||||||
|
) * Bradford;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 convertPrimaries(vec4 color, mat3 src, vec2 srcWhite, mat3 dst, vec2 dstWhite) {
|
||||||
|
mat3 convMat = inverse(dst) * adaptWhite(srcWhite, dstWhite) * src;
|
||||||
|
return vec4(convMat * color.rgb, color[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mat3 BT2020toLMS = mat3(
|
||||||
|
0.3592, 0.6976, -0.0358,
|
||||||
|
-0.1922, 1.1004, 0.0755,
|
||||||
|
0.0070, 0.0749, 0.8434
|
||||||
|
);
|
||||||
|
const mat3 LMStoBT2020 = inverse(BT2020toLMS);
|
||||||
|
|
||||||
|
const mat3 ICtCpPQ = transpose(mat3(
|
||||||
|
2048.0, 2048.0, 0.0,
|
||||||
|
6610.0, -13613.0, 7003.0,
|
||||||
|
17933.0, -17390.0, -543.0
|
||||||
|
) / 4096.0);
|
||||||
|
const mat3 ICtCpPQInv = inverse(ICtCpPQ);
|
||||||
|
|
||||||
|
const mat3 ICtCpHLG = transpose(mat3(
|
||||||
|
2048.0, 2048.0, 0.0,
|
||||||
|
3625.0, -7465.0, 3840.0,
|
||||||
|
9500.0, -9212.0, -288.0
|
||||||
|
) / 4096.0);
|
||||||
|
const mat3 ICtCpHLGInv = inverse(ICtCpHLG);
|
||||||
|
|
||||||
|
vec4 tonemap(vec4 color, mat3 dstXYZ) {
|
||||||
|
if (maxLuminance < dstMaxLuminance * 1.01)
|
||||||
|
return vec4(clamp(color.rgb, vec3(0.0), vec3(dstMaxLuminance)), color[3]);
|
||||||
|
|
||||||
|
mat3 toLMS = BT2020toLMS * dstXYZ;
|
||||||
|
mat3 fromLMS = inverse(dstXYZ) * LMStoBT2020;
|
||||||
|
|
||||||
|
vec3 lms = fromLinear(vec4((toLMS * color.rgb) / HDR_MAX_LUMINANCE, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb;
|
||||||
|
vec3 ICtCp = ICtCpPQ * lms;
|
||||||
|
|
||||||
|
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 srcScale = maxLuminance / dstRefLuminance;
|
||||||
|
float dstScale = dstMaxLuminance / dstRefLuminance;
|
||||||
|
|
||||||
|
float minScale = min(srcScale, 1.5);
|
||||||
|
float dimming = 1.0 / clamp(minScale / dstScale, 1.0, minScale);
|
||||||
|
float refLuminance = dstRefLuminance * dimming;
|
||||||
|
|
||||||
|
float low = min(luminance * dimming, refLuminance);
|
||||||
|
float highlight = clamp((luminance / dstRefLuminance - 1.0) / (srcScale - 1.0), 0.0, 1.0);
|
||||||
|
float high = log(highlight * (M_E - 1.0) + 1.0) * (dstMaxLuminance - refLuminance);
|
||||||
|
luminance = low + high;
|
||||||
|
|
||||||
|
E = pow(clamp(ICtCp[0], 0.0, 1.0), PQ_M1);
|
||||||
|
ICtCp[0] = pow(
|
||||||
|
(PQ_C1 + PQ_C2 * E) / (1.0 + PQ_C3 * E),
|
||||||
|
PQ_M2
|
||||||
|
) / HDR_MAX_LUMINANCE;
|
||||||
|
return vec4(fromLMS * toLinear(vec4(ICtCpPQInv * ICtCp, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb * HDR_MAX_LUMINANCE, color[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
void main() {
|
||||||
|
vec4 pixColor;
|
||||||
|
if (texType == 1)
|
||||||
|
pixColor = vec4(texture(tex, v_texcoord).rgb, 1.0);
|
||||||
|
// else if (texType == 2)
|
||||||
|
// pixColor = texture(texture0, v_texcoord);
|
||||||
|
else // assume rgba
|
||||||
|
pixColor = texture(tex, v_texcoord);
|
||||||
|
|
||||||
|
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
if (discardAlpha == 1 && pixColor[3] <= discardAlphaValue)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
if (skipCM == 0) {
|
||||||
|
pixColor.rgb /= max(pixColor.a, 0.001);
|
||||||
|
pixColor.rgb = toLinearRGB(pixColor.rgb, sourceTF);
|
||||||
|
mat3 srcxyz = primaries2xyz(sourcePrimaries);
|
||||||
|
mat3 dstxyz;
|
||||||
|
if (sourcePrimaries == targetPrimaries)
|
||||||
|
dstxyz = srcxyz;
|
||||||
|
else {
|
||||||
|
dstxyz = primaries2xyz(targetPrimaries);
|
||||||
|
pixColor = convertPrimaries(pixColor, srcxyz, sourcePrimaries[3], dstxyz, targetPrimaries[3]);
|
||||||
|
}
|
||||||
|
pixColor = toNit(pixColor, sourceTF);
|
||||||
|
pixColor.rgb *= pixColor.a;
|
||||||
|
pixColor = tonemap(pixColor, dstxyz);
|
||||||
|
if (sourceTF == CM_TRANSFER_FUNCTION_SRGB && targetTF == CM_TRANSFER_FUNCTION_ST2084_PQ)
|
||||||
|
pixColor = saturate(pixColor, srcxyz, sdrSaturation);
|
||||||
|
pixColor *= sdrBrightnessMultiplier;
|
||||||
|
pixColor = fromLinearNit(pixColor, targetTF);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (applyTint == 1)
|
||||||
|
pixColor = vec4(pixColor.rgb * tint.rgb, pixColor[3]);
|
||||||
|
|
||||||
|
if (radius > 0.0)
|
||||||
|
pixColor = rounding(pixColor);
|
||||||
|
|
||||||
|
fragColor = pixColor * alpha;
|
||||||
|
}
|
||||||
|
)#"
|
||||||
|
|
@ -94,6 +94,10 @@ void main() {
|
||||||
v_texcoord = texcoord;
|
v_texcoord = texcoord;
|
||||||
})#";
|
})#";
|
||||||
|
|
||||||
|
inline const std::string TEXFRAGSRCCM =
|
||||||
|
#include "CM.frag"
|
||||||
|
;
|
||||||
|
|
||||||
inline const std::string TEXFRAGSRCRGBA = R"#(
|
inline const std::string TEXFRAGSRCRGBA = R"#(
|
||||||
precision highp float;
|
precision highp float;
|
||||||
varying vec2 v_texcoord; // is in 0-1
|
varying vec2 v_texcoord; // is in 0-1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue