core/iccprofile: read and use the black point for black point compensation
This commit is contained in:
parent
6f79597f13
commit
0fdc3b2633
3 changed files with 32 additions and 20 deletions
|
@ -360,8 +360,9 @@ ColorDescription DrmOutput::createColorDescription(const std::shared_ptr<OutputC
|
|||
const bool wcg = props->wideColorGamut.value_or(m_state.wideColorGamut);
|
||||
const auto iccProfile = props->iccProfile.value_or(m_state.iccProfile);
|
||||
if (colorSource == ColorProfileSource::ICC && !hdr && !wcg && iccProfile) {
|
||||
const double brightness = iccProfile->brightness().value_or(200);
|
||||
return ColorDescription(iccProfile->colorimetry(), TransferFunction(TransferFunction::gamma22, 0, brightness), brightness, 0, brightness, brightness);
|
||||
const double minBrightness = iccProfile->minBrightness().value_or(0);
|
||||
const double maxBrightness = iccProfile->maxBrightness().value_or(200);
|
||||
return ColorDescription(iccProfile->colorimetry(), TransferFunction(TransferFunction::gamma22, minBrightness, maxBrightness), maxBrightness, minBrightness, maxBrightness, maxBrightness);
|
||||
}
|
||||
const bool screenSupportsHdr = m_connector->edid()->isValid() && m_connector->edid()->supportsBT2020() && m_connector->edid()->supportsPQ();
|
||||
const bool driverSupportsHdr = m_connector->colorspace.isValid() && m_connector->hdrMetadata.isValid() && (m_connector->colorspace.hasEnum(DrmConnector::Colorspace::BT2020_RGB) || m_connector->colorspace.hasEnum(DrmConnector::Colorspace::BT2020_YCC));
|
||||
|
|
|
@ -16,21 +16,23 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
IccProfile::IccProfile(cmsHPROFILE handle, const Colorimetry &colorimetry, BToATagData &&bToATag, const std::shared_ptr<ColorTransformation> &vcgt, std::optional<double> brightness)
|
||||
IccProfile::IccProfile(cmsHPROFILE handle, const Colorimetry &colorimetry, BToATagData &&bToATag, const std::shared_ptr<ColorTransformation> &vcgt, std::optional<double> minBrightness, std::optional<double> maxBrightness)
|
||||
: m_handle(handle)
|
||||
, m_colorimetry(colorimetry)
|
||||
, m_bToATag(std::move(bToATag))
|
||||
, m_vcgt(vcgt)
|
||||
, m_brightness(brightness)
|
||||
, m_minBrightness(minBrightness)
|
||||
, m_maxBrightness(maxBrightness)
|
||||
{
|
||||
}
|
||||
|
||||
IccProfile::IccProfile(cmsHPROFILE handle, const Colorimetry &colorimetry, const std::shared_ptr<ColorTransformation> &inverseEOTF, const std::shared_ptr<ColorTransformation> &vcgt, std::optional<double> brightness)
|
||||
IccProfile::IccProfile(cmsHPROFILE handle, const Colorimetry &colorimetry, const std::shared_ptr<ColorTransformation> &inverseEOTF, const std::shared_ptr<ColorTransformation> &vcgt, std::optional<double> minBrightness, std::optional<double> maxBrightness)
|
||||
: m_handle(handle)
|
||||
, m_colorimetry(colorimetry)
|
||||
, m_inverseEOTF(inverseEOTF)
|
||||
, m_vcgt(vcgt)
|
||||
, m_brightness(brightness)
|
||||
, m_minBrightness(minBrightness)
|
||||
, m_maxBrightness(maxBrightness)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -39,9 +41,14 @@ IccProfile::~IccProfile()
|
|||
cmsCloseProfile(m_handle);
|
||||
}
|
||||
|
||||
std::optional<double> IccProfile::brightness() const
|
||||
std::optional<double> IccProfile::minBrightness() const
|
||||
{
|
||||
return m_brightness;
|
||||
return m_minBrightness;
|
||||
}
|
||||
|
||||
std::optional<double> IccProfile::maxBrightness() const
|
||||
{
|
||||
return m_maxBrightness;
|
||||
}
|
||||
|
||||
const Colorimetry &IccProfile::colorimetry() const
|
||||
|
@ -317,11 +324,16 @@ std::unique_ptr<IccProfile> IccProfile::load(const QString &path)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<double> brightness;
|
||||
std::optional<double> minBrightness;
|
||||
std::optional<double> maxBrightness;
|
||||
if (cmsCIEXYZ *luminance = static_cast<cmsCIEXYZ *>(cmsReadTag(handle, cmsSigLuminanceTag))) {
|
||||
// for some reason, lcms exposes the luminance as a XYZ triple...
|
||||
// only Y is non-zero, and it's the brightness in nits
|
||||
brightness = luminance->Y;
|
||||
maxBrightness = luminance->Y;
|
||||
cmsCIEXYZ blackPoint;
|
||||
if (cmsDetectDestinationBlackPoint(&blackPoint, handle, INTENT_RELATIVE_COLORIMETRIC, 0)) {
|
||||
minBrightness = blackPoint.Y * luminance->Y;
|
||||
}
|
||||
}
|
||||
|
||||
BToATagData lutData;
|
||||
|
@ -333,7 +345,7 @@ std::unique_ptr<IccProfile> IccProfile::load(const QString &path)
|
|||
// lut based profile, with relative colorimetric intent supported
|
||||
auto data = parseBToATag(handle, cmsSigBToA1Tag);
|
||||
if (data) {
|
||||
return std::make_unique<IccProfile>(handle, Colorimetry(red, green, blue, white), std::move(*data), vcgt, brightness);
|
||||
return std::make_unique<IccProfile>(handle, Colorimetry(red, green, blue, white), std::move(*data), vcgt, minBrightness, maxBrightness);
|
||||
} else {
|
||||
qCWarning(KWIN_CORE, "Parsing BToA1 tag failed");
|
||||
return nullptr;
|
||||
|
@ -343,7 +355,7 @@ std::unique_ptr<IccProfile> IccProfile::load(const QString &path)
|
|||
// lut based profile, with perceptual intent. The ICC docs say to use this as a fallback
|
||||
auto data = parseBToATag(handle, cmsSigBToA0Tag);
|
||||
if (data) {
|
||||
return std::make_unique<IccProfile>(handle, Colorimetry(red, green, blue, white), std::move(*data), vcgt, brightness);
|
||||
return std::make_unique<IccProfile>(handle, Colorimetry(red, green, blue, white), std::move(*data), vcgt, minBrightness, maxBrightness);
|
||||
} else {
|
||||
qCWarning(KWIN_CORE, "Parsing BToA0 tag failed");
|
||||
return nullptr;
|
||||
|
@ -366,7 +378,7 @@ std::unique_ptr<IccProfile> IccProfile::load(const QString &path)
|
|||
std::vector<std::unique_ptr<ColorPipelineStage>> stages;
|
||||
stages.push_back(std::make_unique<ColorPipelineStage>(cmsStageAllocToneCurves(nullptr, 3, toneCurves)));
|
||||
const auto inverseEOTF = std::make_shared<ColorTransformation>(std::move(stages));
|
||||
return std::make_unique<IccProfile>(handle, Colorimetry(red, green, blue, white), inverseEOTF, vcgt, brightness);
|
||||
return std::make_unique<IccProfile>(handle, Colorimetry(red, green, blue, white), inverseEOTF, vcgt, minBrightness, maxBrightness);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ public:
|
|||
std::unique_ptr<ColorTransformation> A;
|
||||
};
|
||||
|
||||
explicit IccProfile(cmsHPROFILE handle, const Colorimetry &colorimetry, BToATagData &&bToATag, const std::shared_ptr<ColorTransformation> &vcgt, std::optional<double> brightness);
|
||||
explicit IccProfile(cmsHPROFILE handle, const Colorimetry &colorimetry, const std::shared_ptr<ColorTransformation> &inverseEOTF, const std::shared_ptr<ColorTransformation> &vcgt, std::optional<double> brightness);
|
||||
explicit IccProfile(cmsHPROFILE handle, const Colorimetry &colorimetry, BToATagData &&bToATag, const std::shared_ptr<ColorTransformation> &vcgt, std::optional<double> minBrightness, std::optional<double> maxBrightness);
|
||||
explicit IccProfile(cmsHPROFILE handle, const Colorimetry &colorimetry, const std::shared_ptr<ColorTransformation> &inverseEOTF, const std::shared_ptr<ColorTransformation> &vcgt, std::optional<double> minBrightness, std::optional<double> maxBrightness);
|
||||
~IccProfile();
|
||||
|
||||
/**
|
||||
|
@ -52,10 +52,8 @@ public:
|
|||
*/
|
||||
std::shared_ptr<ColorTransformation> vcgt() const;
|
||||
const Colorimetry &colorimetry() const;
|
||||
/**
|
||||
* The brightness with a completely white output, in nits
|
||||
*/
|
||||
std::optional<double> brightness() const;
|
||||
std::optional<double> minBrightness() const;
|
||||
std::optional<double> maxBrightness() const;
|
||||
|
||||
static std::unique_ptr<IccProfile> load(const QString &path);
|
||||
|
||||
|
@ -65,7 +63,8 @@ private:
|
|||
const std::optional<BToATagData> m_bToATag;
|
||||
const std::shared_ptr<ColorTransformation> m_inverseEOTF;
|
||||
const std::shared_ptr<ColorTransformation> m_vcgt;
|
||||
const std::optional<double> m_brightness;
|
||||
const std::optional<double> m_minBrightness;
|
||||
const std::optional<double> m_maxBrightness;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue