diff --git a/hyprtester/src/tests/main/exec.cpp b/hyprtester/src/tests/main/exec.cpp index fd42cf06..a410494a 100644 --- a/hyprtester/src/tests/main/exec.cpp +++ b/hyprtester/src/tests/main/exec.cpp @@ -2,6 +2,7 @@ #include "../../shared.hpp" #include "../../hyprctlCompat.hpp" #include +#include #include #include #include @@ -15,40 +16,46 @@ using namespace Hyprutils::Memory; #define UP CUniquePointer #define SP CSharedPointer -static bool test() { +const static auto SLEEP_DURATIONS = std::array{1, 10}; + +static bool test() { NLog::log("{}Testing process spawning", Colors::GREEN); - // Note: POSIX sleep does not support fractional seconds, so - // can't sleep for less than 1 second. - OK(getFromSocket("/dispatch exec sleep 1")); + for (const auto duration : SLEEP_DURATIONS) { + // Note: POSIX sleep does not support fractional seconds, so + // can't sleep for less than 1 second. + OK(getFromSocket(std::format("/dispatch exec sleep {}", duration))); - // Ensure that sleep is our child - const std::string sleepPidS = Tests::execAndGet("pgrep sleep"); - pid_t sleepPid; - try { - sleepPid = std::stoull(sleepPidS); - } catch (...) { - NLog::log("{}Sleep was not spawned or several sleeps are running: pgrep returned '{}'", Colors::RED, sleepPidS); - return false; + // Ensure that sleep is our child + const std::string sleepPidS = Tests::execAndGet("pgrep sleep"); + pid_t sleepPid; + try { + sleepPid = std::stoull(sleepPidS); + } catch (...) { + NLog::log("{}Sleep was not spawned or several sleeps are running: pgrep returned '{}'", Colors::RED, sleepPidS); + continue; + } + + const std::string sleepParentComm = Tests::execAndGet("cat \"/proc/$(ps -o ppid:1= -p " + sleepPidS + ")/comm\""); + NLog::log("{}Expecting that sleep's parent is Hyprland", Colors::YELLOW); + EXPECT_CONTAINS(sleepParentComm, "Hyprland"); + + std::this_thread::sleep_for(std::chrono::seconds(duration)); + + // Ensure that sleep did not become a zombie + EXPECT(Tests::processAlive(sleepPid), false); + + // kill all + NLog::log("{}Killing all windows", Colors::YELLOW); + Tests::killAllWindows(); + + NLog::log("{}Expecting 0 windows", Colors::YELLOW); + EXPECT(Tests::windowCount(), 0); + + return !ret; } - const std::string sleepParentComm = Tests::execAndGet("cat \"/proc/$(ps -o ppid:1= -p " + sleepPidS + ")/comm\""); - NLog::log("{}Expecting that sleep's parent is Hyprland", Colors::YELLOW); - EXPECT_CONTAINS(sleepParentComm, "Hyprland"); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - - // Ensure that sleep did not become a zombie - EXPECT(Tests::processAlive(sleepPid), false); - - // kill all - NLog::log("{}Killing all windows", Colors::YELLOW); - Tests::killAllWindows(); - - NLog::log("{}Expecting 0 windows", Colors::YELLOW); - EXPECT(Tests::windowCount(), 0); - - return !ret; + return false; } REGISTER_TEST_FN(test) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index ebe13156..ef6ca535 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1568,10 +1568,10 @@ inline static const std::vector CONFIG_OPTIONS = { }, SConfigOptionDescription{ .value = "render:cm_sdr_eotf", - .description = "Default transfer function for displaying SDR apps. 0 - Use default value (Gamma 2.2), 1 - Treat unspecified as Gamma 2.2, 2 - Treat " - "unspecified and sRGB as Gamma 2.2, 3 - Treat unspecified as sRGB", - .type = CONFIG_OPTION_CHOICE, - .data = SConfigOptionDescription::SChoiceData{0, "default,gamma22,gamma22force,srgb"}, + .description = "Default transfer function for displaying SDR apps. default - Use default value (Gamma 2.2), gamma22 - Treat unspecified as Gamma 2.2, gamma22force - Treat " + "unspecified and sRGB as Gamma 2.2, srgb - Treat unspecified as sRGB", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"default"}, }, SConfigOptionDescription{ .value = "render:commit_timing_enabled", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index cd5b0ec8..cb38154e 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -795,7 +795,7 @@ CConfigManager::CConfigManager() { registerConfigVar("render:cm_auto_hdr", Hyprlang::INT{1}); registerConfigVar("render:new_render_scheduling", Hyprlang::INT{0}); registerConfigVar("render:non_shader_cm", Hyprlang::INT{3}); - registerConfigVar("render:cm_sdr_eotf", Hyprlang::INT{0}); + registerConfigVar("render:cm_sdr_eotf", {"default"}); registerConfigVar("render:commit_timing_enabled", Hyprlang::INT{1}); registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0}); @@ -859,7 +859,7 @@ CConfigManager::CConfigManager() { m_config->addSpecialConfigValue("monitorv2", "mirror", {STRVAL_EMPTY}); m_config->addSpecialConfigValue("monitorv2", "bitdepth", {STRVAL_EMPTY}); // TODO use correct type m_config->addSpecialConfigValue("monitorv2", "cm", {"auto"}); - m_config->addSpecialConfigValue("monitorv2", "sdr_eotf", Hyprlang::INT{0}); + m_config->addSpecialConfigValue("monitorv2", "sdr_eotf", {"default"}); m_config->addSpecialConfigValue("monitorv2", "sdrbrightness", Hyprlang::FLOAT{1.0}); m_config->addSpecialConfigValue("monitorv2", "sdrsaturation", Hyprlang::FLOAT{1.0}); m_config->addSpecialConfigValue("monitorv2", "vrr", Hyprlang::INT{0}); @@ -1209,8 +1209,18 @@ std::optional CConfigManager::handleMonitorv2(const std::string& ou if (VAL && VAL->m_bSetByUser) parser.parseCM(std::any_cast(VAL->getValue())); VAL = m_config->getSpecialConfigValuePtr("monitorv2", "sdr_eotf", output.c_str()); - if (VAL && VAL->m_bSetByUser) - parser.rule().sdrEotf = std::any_cast(VAL->getValue()); + if (VAL && VAL->m_bSetByUser) { + const std::string value = std::any_cast(VAL->getValue()); + // remap legacy + if (value == "0") + parser.rule().sdrEotf = NTransferFunction::TF_AUTO; + else if (value == "1") + parser.rule().sdrEotf = NTransferFunction::TF_SRGB; + else if (value == "2") + parser.rule().sdrEotf = NTransferFunction::TF_GAMMA22; + else + parser.rule().sdrEotf = NTransferFunction::fromString(value); + } VAL = m_config->getSpecialConfigValuePtr("monitorv2", "sdrbrightness", output.c_str()); if (VAL && VAL->m_bSetByUser) parser.rule().sdrBrightness = std::any_cast(VAL->getValue()); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index a29edc91..f287bff3 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -2,6 +2,7 @@ #include "MiscFunctions.hpp" #include "../macros.hpp" #include "SharedDefs.hpp" +#include "../helpers/TransferFunction.hpp" #include "math/Math.hpp" #include "../protocols/ColorManagement.hpp" #include "../Compositor.hpp" @@ -29,6 +30,7 @@ #include "../hyprerror/HyprError.hpp" #include "../layout/LayoutManager.hpp" #include "../i18n/Engine.hpp" +#include "../protocols/types/ColorManagement.hpp" #include "sync/SyncTimeline.hpp" #include "time/Time.hpp" #include "../desktop/view/LayerSurface.hpp" @@ -480,20 +482,41 @@ void CMonitor::onDisconnect(bool destroy) { std::erase_if(g_pCompositor->m_monitors, [&](PHLMONITOR& el) { return el.get() == this; }); } -void CMonitor::applyCMType(NCMType::eCMType cmType, int cmSdrEotf) { - auto oldImageDescription = m_imageDescription; - static auto PSDREOTF = CConfigValue("render:cm_sdr_eotf"); - auto chosenSdrEotf = cmSdrEotf == 0 ? (*PSDREOTF != 3 ? NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 : NColorManagement::CM_TRANSFER_FUNCTION_SRGB) : - (cmSdrEotf == 1 ? NColorManagement::CM_TRANSFER_FUNCTION_SRGB : NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22); +static NColorManagement::eTransferFunction chooseTF(NTransferFunction::eTF tf) { + const auto sdrEOTF = NTransferFunction::fromConfig(); - const auto masteringPrimaries = getMasteringPrimaries(); + switch (tf) { + case NTransferFunction::TF_DEFAULT: + case NTransferFunction::TF_GAMMA22: + case NTransferFunction::TF_FORCED_GAMMA22: return NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22; + case NTransferFunction::TF_SRGB: return NColorManagement::CM_TRANSFER_FUNCTION_SRGB; + + case NTransferFunction::TF_AUTO: // use global setting + switch (sdrEOTF) { + case NTransferFunction::TF_AUTO: return NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22; + default: return chooseTF(sdrEOTF); + } + + default: UNREACHABLE(); + } +} + +void CMonitor::applyCMType(NCMType::eCMType cmType, NTransferFunction::eTF cmSdrEotf) { + auto oldImageDescription = m_imageDescription; + const auto chosenSdrEotf = chooseTF(cmSdrEotf); + + const auto masteringPrimaries = getMasteringPrimaries(); const NColorManagement::SImageDescription::SPCMasteringLuminances masteringLuminances = getMasteringLuminances(); const auto maxFALL = this->maxFALL(); const auto maxCLL = this->maxCLL(); switch (cmType) { - case NCMType::CM_SRGB: m_imageDescription = CImageDescription::from({.transferFunction = chosenSdrEotf}); break; // assumes SImageDescription defaults to sRGB + case NCMType::CM_SRGB: + m_imageDescription = CImageDescription::from({.transferFunction = chosenSdrEotf, + .primariesNamed = NColorManagement::CM_PRIMARIES_SRGB, + .primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_SRGB)}); + break; // assumes SImageDescription defaults to sRGB case NCMType::CM_WIDE: m_imageDescription = CImageDescription::from({.transferFunction = chosenSdrEotf, .primariesNameSet = true, @@ -2152,11 +2175,11 @@ bool CMonitor::canNoShaderCM() { if (SRC_DESC_VALUE.icc.fd >= 0 || m_imageDescription->value().icc.fd >= 0) return false; // no ICC support - static auto PSDREOTF = CConfigValue("render:cm_sdr_eotf"); + const auto sdrEOTF = NTransferFunction::fromConfig(); // only primaries differ return ( (SRC_DESC_VALUE.transferFunction == m_imageDescription->value().transferFunction || - (*PSDREOTF == 2 && SRC_DESC_VALUE.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB && + (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && SRC_DESC_VALUE.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB && m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22)) && SRC_DESC_VALUE.transferFunctionPower == m_imageDescription->value().transferFunctionPower && (!inHDR() || SRC_DESC_VALUE.luminances == m_imageDescription->value().luminances) diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 37f3f16a..72e0cf66 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -23,6 +23,8 @@ #include #include +#include "../helpers/TransferFunction.hpp" + class CMonitorFrameScheduler; // Enum for the different types of auto directions, e.g. auto-left, auto-up. @@ -50,7 +52,7 @@ struct SMonitorRule { std::string mirrorOf = ""; bool enable10bit = false; NCMType::eCMType cmType = NCMType::CM_SRGB; - int sdrEotf = 0; + NTransferFunction::eTF sdrEotf = NTransferFunction::TF_DEFAULT; float sdrSaturation = 1.0f; // SDR -> HDR float sdrBrightness = 1.0f; // SDR -> HDR Desktop::CReservedArea reservedArea; @@ -137,7 +139,7 @@ class CMonitor { bool m_vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. bool m_enabled10bit = false; // as above, this can be TRUE even if 10 bit failed. NCMType::eCMType m_cmType = NCMType::CM_SRGB; - int m_sdrEotf = 0; + NTransferFunction::eTF m_sdrEotf = NTransferFunction::TF_DEFAULT; float m_sdrSaturation = 1.0f; float m_sdrBrightness = 1.0f; float m_sdrMinLuminance = 0.2f; @@ -284,7 +286,7 @@ class CMonitor { // methods void onConnect(bool noRule); void onDisconnect(bool destroy = false); - void applyCMType(NCMType::eCMType cmType, int cmSdrEotf); + void applyCMType(NCMType::eCMType cmType, NTransferFunction::eTF cmSdrEotf); bool applyMonitorRule(SMonitorRule* pMonitorRule, bool force = false); void addDamage(const pixman_region32_t* rg); void addDamage(const CRegion& rg); diff --git a/src/helpers/TransferFunction.cpp b/src/helpers/TransferFunction.cpp new file mode 100644 index 00000000..935f77fe --- /dev/null +++ b/src/helpers/TransferFunction.cpp @@ -0,0 +1,35 @@ +#include "TransferFunction.hpp" +#include "../config/ConfigValue.hpp" +#include "../event/EventBus.hpp" +#include +#include +#include + +using namespace NTransferFunction; + +static std::unordered_map const table = {{"default", TF_DEFAULT}, {"0", TF_DEFAULT}, {"auto", TF_AUTO}, {"srgb", TF_SRGB}, + {"3", TF_SRGB}, {"gamma22", TF_GAMMA22}, {"1", TF_GAMMA22}, {"gamma22force", TF_FORCED_GAMMA22}, + {"2", TF_FORCED_GAMMA22}}; + +eTF NTransferFunction::fromString(const std::string tfName) { + auto it = table.find(tfName); + if (it == table.end()) + return TF_DEFAULT; + return it->second; +} + +std::string NTransferFunction::toString(eTF tf) { + for (const auto& [key, value] : table) { + if (value == tf) + return key; + } + return ""; +} + +eTF NTransferFunction::fromConfig() { + static auto PSDREOTF = CConfigValue("render:cm_sdr_eotf"); + static auto sdrEOTF = NTransferFunction::fromString(*PSDREOTF); + static auto P = Event::bus()->m_events.config.reloaded.listen([]() { sdrEOTF = NTransferFunction::fromString(*PSDREOTF); }); + + return sdrEOTF; +} diff --git a/src/helpers/TransferFunction.hpp b/src/helpers/TransferFunction.hpp new file mode 100644 index 00000000..cbf35f37 --- /dev/null +++ b/src/helpers/TransferFunction.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace NTransferFunction { + enum eTF : uint8_t { + TF_DEFAULT = 0, + TF_AUTO = 1, + TF_SRGB = 2, + TF_GAMMA22 = 3, + TF_FORCED_GAMMA22 = 4, + }; + + eTF fromString(const std::string tfName); + std::string toString(eTF tf); + + eTF fromConfig(); +} diff --git a/src/protocols/types/ColorManagement.hpp b/src/protocols/types/ColorManagement.hpp index 3a1796a3..c1f58316 100644 --- a/src/protocols/types/ColorManagement.hpp +++ b/src/protocols/types/ColorManagement.hpp @@ -298,12 +298,17 @@ namespace NColorManagement { using PImageDescription = WP; - static const auto DEFAULT_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{}); + static const auto DEFAULT_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22, + .primariesNameSet = true, + .primariesNamed = NColorManagement::CM_PRIMARIES_SRGB, + .primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_SRGB), + .luminances = {.min = SDR_MIN_LUMINANCE, .max = 80, .reference = 80}}); + static const auto DEFAULT_HDR_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ, .primariesNameSet = true, .primariesNamed = NColorManagement::CM_PRIMARIES_BT2020, .primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020), - .luminances = {.min = 0, .max = 10000, .reference = 203}}); + .luminances = {.min = HDR_MIN_LUMINANCE, .max = 10000, .reference = 203}}); ; static const auto SCRGB_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{ .windowsScRGB = true, diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index d6c2c024..916091db 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -10,6 +10,7 @@ #include "../Compositor.hpp" #include "../helpers/MiscFunctions.hpp" #include "../helpers/CursorShapes.hpp" +#include "../helpers/TransferFunction.hpp" #include "../config/ConfigValue.hpp" #include "../config/ConfigManager.hpp" #include "../managers/PointerManager.hpp" @@ -1245,13 +1246,20 @@ static bool isHDR2SDR(const NColorManagement::SImageDescription& imageDescriptio void CHyprOpenGLImpl::passCMUniforms(WP shader, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) { - static auto PSDREOTF = CConfigValue("render:cm_sdr_eotf"); + const auto sdrEOTF = NTransferFunction::fromConfig(); - if (m_renderData.surface.valid() && - ((!m_renderData.surface->m_colorManagement.valid() && *PSDREOTF >= 1) || - (*PSDREOTF == 2 && m_renderData.surface->m_colorManagement.valid() && - imageDescription->value().transferFunction == NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB))) { - shader->setUniformInt(SHADER_SOURCE_TF, NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22); + if (m_renderData.surface.valid()) { + if (m_renderData.surface->m_colorManagement.valid()) { + if (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && imageDescription->value().transferFunction == NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB) + shader->setUniformInt(SHADER_SOURCE_TF, NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22); + else + shader->setUniformInt(SHADER_SOURCE_TF, imageDescription->value().transferFunction); + } else if (sdrEOTF == NTransferFunction::TF_SRGB) + shader->setUniformInt(SHADER_SOURCE_TF, NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB); + else if (sdrEOTF == NTransferFunction::TF_GAMMA22 || sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22) + shader->setUniformInt(SHADER_SOURCE_TF, NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22); + else + shader->setUniformInt(SHADER_SOURCE_TF, imageDescription->value().transferFunction); } else shader->setUniformInt(SHADER_SOURCE_TF, imageDescription->value().transferFunction); @@ -1377,16 +1385,16 @@ void CHyprOpenGLImpl::renderTextureInternal(SP tex, const CBox& box, c tex->setTexParameter(GL_TEXTURE_MIN_FILTER, tex->minFilter); } - const bool isHDRSurface = m_renderData.surface.valid() && m_renderData.surface->m_colorManagement.valid() ? m_renderData.surface->m_colorManagement->isHDR() : false; - const bool canPassHDRSurface = isHDRSurface && !m_renderData.surface->m_colorManagement->isWindowsScRGB(); // windows scRGB requires CM shader + const bool isHDRSurface = m_renderData.surface.valid() && m_renderData.surface->m_colorManagement.valid() ? m_renderData.surface->m_colorManagement->isHDR() : false; + const bool canPassHDRSurface = isHDRSurface && !m_renderData.surface->m_colorManagement->isWindowsScRGB(); // windows scRGB requires CM shader - const auto imageDescription = m_renderData.surface.valid() && m_renderData.surface->m_colorManagement.valid() ? - CImageDescription::from(m_renderData.surface->m_colorManagement->imageDescription()) : - (data.cmBackToSRGB ? data.cmBackToSRGBSource->m_imageDescription : DEFAULT_IMAGE_DESCRIPTION); + const auto imageDescription = m_renderData.surface.valid() && m_renderData.surface->m_colorManagement.valid() ? + CImageDescription::from(m_renderData.surface->m_colorManagement->imageDescription()) : + (data.cmBackToSRGB ? data.cmBackToSRGBSource->m_imageDescription : DEFAULT_IMAGE_DESCRIPTION); - static auto PSDREOTF = CConfigValue("render:cm_sdr_eotf"); - auto chosenSdrEotf = *PSDREOTF != 3 ? NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 : NColorManagement::CM_TRANSFER_FUNCTION_SRGB; - const auto targetImageDescription = + const auto sdrEOTF = NTransferFunction::fromConfig(); + auto chosenSdrEotf = sdrEOTF != NTransferFunction::TF_SRGB ? NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 : NColorManagement::CM_TRANSFER_FUNCTION_SRGB; + const auto targetImageDescription = data.cmBackToSRGB ? CImageDescription::from(NColorManagement::SImageDescription{.transferFunction = chosenSdrEotf}) : m_renderData.pMonitor->m_imageDescription; const bool skipCM = !*PENABLECM || !m_cmSupported /* CM unsupported or disabled */