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 bool wcg = props->wideColorGamut.value_or(m_state.wideColorGamut);
|
||||||
const auto iccProfile = props->iccProfile.value_or(m_state.iccProfile);
|
const auto iccProfile = props->iccProfile.value_or(m_state.iccProfile);
|
||||||
if (colorSource == ColorProfileSource::ICC && !hdr && !wcg && iccProfile) {
|
if (colorSource == ColorProfileSource::ICC && !hdr && !wcg && iccProfile) {
|
||||||
const double brightness = iccProfile->brightness().value_or(200);
|
const double minBrightness = iccProfile->minBrightness().value_or(0);
|
||||||
return ColorDescription(iccProfile->colorimetry(), TransferFunction(TransferFunction::gamma22, 0, brightness), brightness, 0, brightness, brightness);
|
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 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));
|
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
|
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_handle(handle)
|
||||||
, m_colorimetry(colorimetry)
|
, m_colorimetry(colorimetry)
|
||||||
, m_bToATag(std::move(bToATag))
|
, m_bToATag(std::move(bToATag))
|
||||||
, m_vcgt(vcgt)
|
, 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_handle(handle)
|
||||||
, m_colorimetry(colorimetry)
|
, m_colorimetry(colorimetry)
|
||||||
, m_inverseEOTF(inverseEOTF)
|
, m_inverseEOTF(inverseEOTF)
|
||||||
, m_vcgt(vcgt)
|
, m_vcgt(vcgt)
|
||||||
, m_brightness(brightness)
|
, m_minBrightness(minBrightness)
|
||||||
|
, m_maxBrightness(maxBrightness)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,9 +41,14 @@ IccProfile::~IccProfile()
|
||||||
cmsCloseProfile(m_handle);
|
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
|
const Colorimetry &IccProfile::colorimetry() const
|
||||||
|
@ -317,11 +324,16 @@ std::unique_ptr<IccProfile> IccProfile::load(const QString &path)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<double> brightness;
|
std::optional<double> minBrightness;
|
||||||
|
std::optional<double> maxBrightness;
|
||||||
if (cmsCIEXYZ *luminance = static_cast<cmsCIEXYZ *>(cmsReadTag(handle, cmsSigLuminanceTag))) {
|
if (cmsCIEXYZ *luminance = static_cast<cmsCIEXYZ *>(cmsReadTag(handle, cmsSigLuminanceTag))) {
|
||||||
// for some reason, lcms exposes the luminance as a XYZ triple...
|
// for some reason, lcms exposes the luminance as a XYZ triple...
|
||||||
// only Y is non-zero, and it's the brightness in nits
|
// 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;
|
BToATagData lutData;
|
||||||
|
@ -333,7 +345,7 @@ std::unique_ptr<IccProfile> IccProfile::load(const QString &path)
|
||||||
// lut based profile, with relative colorimetric intent supported
|
// lut based profile, with relative colorimetric intent supported
|
||||||
auto data = parseBToATag(handle, cmsSigBToA1Tag);
|
auto data = parseBToATag(handle, cmsSigBToA1Tag);
|
||||||
if (data) {
|
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 {
|
} else {
|
||||||
qCWarning(KWIN_CORE, "Parsing BToA1 tag failed");
|
qCWarning(KWIN_CORE, "Parsing BToA1 tag failed");
|
||||||
return nullptr;
|
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
|
// lut based profile, with perceptual intent. The ICC docs say to use this as a fallback
|
||||||
auto data = parseBToATag(handle, cmsSigBToA0Tag);
|
auto data = parseBToATag(handle, cmsSigBToA0Tag);
|
||||||
if (data) {
|
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 {
|
} else {
|
||||||
qCWarning(KWIN_CORE, "Parsing BToA0 tag failed");
|
qCWarning(KWIN_CORE, "Parsing BToA0 tag failed");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -366,7 +378,7 @@ std::unique_ptr<IccProfile> IccProfile::load(const QString &path)
|
||||||
std::vector<std::unique_ptr<ColorPipelineStage>> stages;
|
std::vector<std::unique_ptr<ColorPipelineStage>> stages;
|
||||||
stages.push_back(std::make_unique<ColorPipelineStage>(cmsStageAllocToneCurves(nullptr, 3, toneCurves)));
|
stages.push_back(std::make_unique<ColorPipelineStage>(cmsStageAllocToneCurves(nullptr, 3, toneCurves)));
|
||||||
const auto inverseEOTF = std::make_shared<ColorTransformation>(std::move(stages));
|
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;
|
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, 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> brightness);
|
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();
|
~IccProfile();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,10 +52,8 @@ public:
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<ColorTransformation> vcgt() const;
|
std::shared_ptr<ColorTransformation> vcgt() const;
|
||||||
const Colorimetry &colorimetry() const;
|
const Colorimetry &colorimetry() const;
|
||||||
/**
|
std::optional<double> minBrightness() const;
|
||||||
* The brightness with a completely white output, in nits
|
std::optional<double> maxBrightness() const;
|
||||||
*/
|
|
||||||
std::optional<double> brightness() const;
|
|
||||||
|
|
||||||
static std::unique_ptr<IccProfile> load(const QString &path);
|
static std::unique_ptr<IccProfile> load(const QString &path);
|
||||||
|
|
||||||
|
@ -65,7 +63,8 @@ private:
|
||||||
const std::optional<BToATagData> m_bToATag;
|
const std::optional<BToATagData> m_bToATag;
|
||||||
const std::shared_ptr<ColorTransformation> m_inverseEOTF;
|
const std::shared_ptr<ColorTransformation> m_inverseEOTF;
|
||||||
const std::shared_ptr<ColorTransformation> m_vcgt;
|
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