core/colorspace: add rendering intents
Rendering intents describe how to handle mapping between different colorspaces, what to do with out of gamut values and what to do if the whitepoint doesn't match. This way, clients can choose which behavior their content should get.
This commit is contained in:
parent
e9680f6425
commit
833476a111
40 changed files with 155 additions and 68 deletions
|
@ -70,11 +70,16 @@ void TestColorspaces::roundtripConversion()
|
||||||
const QVector3D green(0, 1, 0);
|
const QVector3D green(0, 1, 0);
|
||||||
const QVector3D blue(0, 0, 1);
|
const QVector3D blue(0, 0, 1);
|
||||||
const QVector3D white(1, 1, 1);
|
const QVector3D white(1, 1, 1);
|
||||||
|
constexpr std::array renderingIntents = {
|
||||||
QVERIFY(compareVectors(dst.mapTo(src.mapTo(red, dst), src), red, requiredAccuracy));
|
RenderingIntent::RelativeColorimetric,
|
||||||
QVERIFY(compareVectors(dst.mapTo(src.mapTo(green, dst), src), green, requiredAccuracy));
|
RenderingIntent::AbsoluteColorimetric,
|
||||||
QVERIFY(compareVectors(dst.mapTo(src.mapTo(blue, dst), src), blue, requiredAccuracy));
|
};
|
||||||
QVERIFY(compareVectors(dst.mapTo(src.mapTo(white, dst), src), white, requiredAccuracy));
|
for (const RenderingIntent intent : renderingIntents) {
|
||||||
|
QVERIFY(compareVectors(dst.mapTo(src.mapTo(red, dst, intent), src, intent), red, requiredAccuracy));
|
||||||
|
QVERIFY(compareVectors(dst.mapTo(src.mapTo(green, dst, intent), src, intent), green, requiredAccuracy));
|
||||||
|
QVERIFY(compareVectors(dst.mapTo(src.mapTo(blue, dst, intent), src, intent), blue, requiredAccuracy));
|
||||||
|
QVERIFY(compareVectors(dst.mapTo(src.mapTo(white, dst, intent), src, intent), white, requiredAccuracy));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestColorspaces::nonNormalizedPrimaries()
|
void TestColorspaces::nonNormalizedPrimaries()
|
||||||
|
@ -83,7 +88,7 @@ void TestColorspaces::nonNormalizedPrimaries()
|
||||||
const auto from = Colorimetry::fromName(NamedColorimetry::BT709);
|
const auto from = Colorimetry::fromName(NamedColorimetry::BT709);
|
||||||
const auto to = Colorimetry(Colorimetry::xyToXYZ(from.red()) * 2, Colorimetry::xyToXYZ(from.green()) * 2, Colorimetry::xyToXYZ(from.blue()) * 2, Colorimetry::xyToXYZ(from.white()) * 2);
|
const auto to = Colorimetry(Colorimetry::xyToXYZ(from.red()) * 2, Colorimetry::xyToXYZ(from.green()) * 2, Colorimetry::xyToXYZ(from.blue()) * 2, Colorimetry::xyToXYZ(from.white()) * 2);
|
||||||
|
|
||||||
const auto convertedWhite = from.toOther(to) * QVector3D(1, 1, 1);
|
const auto convertedWhite = from.toOther(to, RenderingIntent::RelativeColorimetric) * QVector3D(1, 1, 1);
|
||||||
QCOMPARE_LE(std::abs(1 - convertedWhite.x()), s_resolution10bit);
|
QCOMPARE_LE(std::abs(1 - convertedWhite.x()), s_resolution10bit);
|
||||||
QCOMPARE_LE(std::abs(1 - convertedWhite.y()), s_resolution10bit);
|
QCOMPARE_LE(std::abs(1 - convertedWhite.y()), s_resolution10bit);
|
||||||
QCOMPARE_LE(std::abs(1 - convertedWhite.z()), s_resolution10bit);
|
QCOMPARE_LE(std::abs(1 - convertedWhite.z()), s_resolution10bit);
|
||||||
|
@ -110,11 +115,18 @@ void TestColorspaces::testIdentityTransformation()
|
||||||
QFETCH(TransferFunction::Type, transferFunction);
|
QFETCH(TransferFunction::Type, transferFunction);
|
||||||
const ColorDescription color(colorimetry, TransferFunction(transferFunction), 100, 0, 100, 100);
|
const ColorDescription color(colorimetry, TransferFunction(transferFunction), 100, 0, 100, 100);
|
||||||
|
|
||||||
const auto pipeline = ColorPipeline::create(color, color);
|
constexpr std::array renderingIntents = {
|
||||||
if (!pipeline.isIdentity()) {
|
RenderingIntent::Perceptual,
|
||||||
qWarning() << pipeline;
|
RenderingIntent::RelativeColorimetric,
|
||||||
|
RenderingIntent::AbsoluteColorimetric,
|
||||||
|
};
|
||||||
|
for (const RenderingIntent intent : renderingIntents) {
|
||||||
|
const auto pipeline = ColorPipeline::create(color, color, intent);
|
||||||
|
if (!pipeline.isIdentity()) {
|
||||||
|
qWarning() << pipeline;
|
||||||
|
}
|
||||||
|
QVERIFY(pipeline.isIdentity());
|
||||||
}
|
}
|
||||||
QVERIFY(pipeline.isIdentity());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestColorspaces::testColorPipeline_data()
|
void TestColorspaces::testColorPipeline_data()
|
||||||
|
@ -124,17 +136,22 @@ void TestColorspaces::testColorPipeline_data()
|
||||||
QTest::addColumn<QVector3D>("dstBlack");
|
QTest::addColumn<QVector3D>("dstBlack");
|
||||||
QTest::addColumn<QVector3D>("dstGray");
|
QTest::addColumn<QVector3D>("dstGray");
|
||||||
QTest::addColumn<QVector3D>("dstWhite");
|
QTest::addColumn<QVector3D>("dstWhite");
|
||||||
|
QTest::addColumn<RenderingIntent>("intent");
|
||||||
|
|
||||||
QTest::addRow("sRGB -> rec.2020") << ColorDescription(NamedColorimetry::BT709, TransferFunction(TransferFunction::gamma22), TransferFunction::defaultReferenceLuminanceFor(TransferFunction::gamma22), 0, std::nullopt, std::nullopt)
|
QTest::addRow("sRGB -> rec.2020 relative colorimetric")
|
||||||
<< ColorDescription(NamedColorimetry::BT2020, TransferFunction(TransferFunction::PerceptualQuantizer), 500, 0, std::nullopt, std::nullopt)
|
<< ColorDescription(NamedColorimetry::BT709, TransferFunction(TransferFunction::gamma22), TransferFunction::defaultReferenceLuminanceFor(TransferFunction::gamma22), 0, std::nullopt, std::nullopt)
|
||||||
<< QVector3D(0.044, 0.044, 0.044)
|
<< ColorDescription(NamedColorimetry::BT2020, TransferFunction(TransferFunction::PerceptualQuantizer), 500, 0, std::nullopt, std::nullopt)
|
||||||
<< QVector3D(0.517, 0.517, 0.517)
|
<< QVector3D(0.044, 0.044, 0.044)
|
||||||
<< QVector3D(0.677, 0.677, 0.677);
|
<< QVector3D(0.517, 0.517, 0.517)
|
||||||
QTest::addRow("sRGB -> scRGB") << ColorDescription(NamedColorimetry::BT709, TransferFunction(TransferFunction::gamma22), TransferFunction::defaultReferenceLuminanceFor(TransferFunction::gamma22), 0, std::nullopt, std::nullopt)
|
<< QVector3D(0.677, 0.677, 0.677)
|
||||||
<< ColorDescription(NamedColorimetry::BT709, TransferFunction(TransferFunction::linear, 0, 80), 80, 0, std::nullopt, std::nullopt)
|
<< RenderingIntent::RelativeColorimetric;
|
||||||
<< QVector3D(0.0001, 0.0001, 0.0001)
|
QTest::addRow("sRGB -> scRGB relative colorimetric")
|
||||||
<< QVector3D(0.2177376408240310, 0.2177376408240310, 0.2177376408240310)
|
<< ColorDescription(NamedColorimetry::BT709, TransferFunction(TransferFunction::gamma22), TransferFunction::defaultReferenceLuminanceFor(TransferFunction::gamma22), 0, std::nullopt, std::nullopt)
|
||||||
<< QVector3D(1, 1, 1);
|
<< ColorDescription(NamedColorimetry::BT709, TransferFunction(TransferFunction::linear, 0, 80), 80, 0, std::nullopt, std::nullopt)
|
||||||
|
<< QVector3D(0.0001, 0.0001, 0.0001)
|
||||||
|
<< QVector3D(0.2177376408240310, 0.2177376408240310, 0.2177376408240310)
|
||||||
|
<< QVector3D(1, 1, 1)
|
||||||
|
<< RenderingIntent::RelativeColorimetric;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestColorspaces::testColorPipeline()
|
void TestColorspaces::testColorPipeline()
|
||||||
|
@ -144,13 +161,14 @@ void TestColorspaces::testColorPipeline()
|
||||||
QFETCH(QVector3D, dstBlack);
|
QFETCH(QVector3D, dstBlack);
|
||||||
QFETCH(QVector3D, dstGray);
|
QFETCH(QVector3D, dstGray);
|
||||||
QFETCH(QVector3D, dstWhite);
|
QFETCH(QVector3D, dstWhite);
|
||||||
|
QFETCH(RenderingIntent, intent);
|
||||||
|
|
||||||
const auto pipeline = ColorPipeline::create(srcColor, dstColor);
|
const auto pipeline = ColorPipeline::create(srcColor, dstColor, intent);
|
||||||
QVERIFY(compareVectors(pipeline.evaluate(QVector3D(0, 0, 0)), dstBlack, s_resolution10bit));
|
QVERIFY(compareVectors(pipeline.evaluate(QVector3D(0, 0, 0)), dstBlack, s_resolution10bit));
|
||||||
QVERIFY(compareVectors(pipeline.evaluate(QVector3D(0.5, 0.5, 0.5)), dstGray, s_resolution10bit));
|
QVERIFY(compareVectors(pipeline.evaluate(QVector3D(0.5, 0.5, 0.5)), dstGray, s_resolution10bit));
|
||||||
QVERIFY(compareVectors(pipeline.evaluate(QVector3D(1, 1, 1)), dstWhite, s_resolution10bit));
|
QVERIFY(compareVectors(pipeline.evaluate(QVector3D(1, 1, 1)), dstWhite, s_resolution10bit));
|
||||||
|
|
||||||
const auto inversePipeline = ColorPipeline::create(dstColor, srcColor);
|
const auto inversePipeline = ColorPipeline::create(dstColor, srcColor, intent);
|
||||||
QVERIFY(compareVectors(inversePipeline.evaluate(dstBlack), QVector3D(0, 0, 0), s_resolution10bit));
|
QVERIFY(compareVectors(inversePipeline.evaluate(dstBlack), QVector3D(0, 0, 0), s_resolution10bit));
|
||||||
QVERIFY(compareVectors(inversePipeline.evaluate(dstGray), QVector3D(0.5, 0.5, 0.5), s_resolution10bit));
|
QVERIFY(compareVectors(inversePipeline.evaluate(dstGray), QVector3D(0.5, 0.5, 0.5), s_resolution10bit));
|
||||||
QVERIFY(compareVectors(inversePipeline.evaluate(dstWhite), QVector3D(1, 1, 1), s_resolution10bit));
|
QVERIFY(compareVectors(inversePipeline.evaluate(dstWhite), QVector3D(1, 1, 1), s_resolution10bit));
|
||||||
|
|
|
@ -86,7 +86,7 @@ ColorDescription EglGbmLayer::colorDescription() const
|
||||||
return m_surface.colorDescription();
|
return m_surface.colorDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, const std::shared_ptr<OutputFrame> &frame)
|
bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||||
{
|
{
|
||||||
static bool valid;
|
static bool valid;
|
||||||
static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid;
|
static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid;
|
||||||
|
@ -97,7 +97,7 @@ bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescriptio
|
||||||
// TODO make the icc profile output a color pipeline too?
|
// TODO make the icc profile output a color pipeline too?
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ColorPipeline pipeline = ColorPipeline::create(color, m_pipeline->output()->scanoutColorDescription());
|
ColorPipeline pipeline = ColorPipeline::create(color, m_pipeline->output()->scanoutColorDescription(), intent);
|
||||||
if (m_pipeline->output()->needsChannelFactorFallback()) {
|
if (m_pipeline->output()->needsChannelFactorFallback()) {
|
||||||
pipeline.addTransferFunction(m_pipeline->output()->scanoutColorDescription().transferFunction());
|
pipeline.addTransferFunction(m_pipeline->output()->scanoutColorDescription().transferFunction());
|
||||||
pipeline.addMultiplier(m_pipeline->output()->effectiveChannelFactors());
|
pipeline.addMultiplier(m_pipeline->output()->effectiveChannelFactors());
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
const ColorPipeline &colorPipeline() const override;
|
const ColorPipeline &colorPipeline() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, const std::shared_ptr<OutputFrame> &frame) override;
|
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame) override;
|
||||||
|
|
||||||
std::shared_ptr<DrmFramebuffer> m_scanoutBuffer;
|
std::shared_ptr<DrmFramebuffer> m_scanoutBuffer;
|
||||||
ColorPipeline m_colorPipeline;
|
ColorPipeline m_colorPipeline;
|
||||||
|
|
|
@ -193,7 +193,7 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion, OutputFrame
|
||||||
if (m_surface->iccShader) {
|
if (m_surface->iccShader) {
|
||||||
m_surface->iccShader->setUniforms(m_surface->iccProfile, m_surface->intermediaryColorDescription, m_surface->channelFactors);
|
m_surface->iccShader->setUniforms(m_surface->iccProfile, m_surface->intermediaryColorDescription, m_surface->channelFactors);
|
||||||
} else {
|
} else {
|
||||||
binder.shader()->setColorspaceUniforms(m_surface->intermediaryColorDescription, m_surface->targetColorDescription);
|
binder.shader()->setColorspaceUniforms(m_surface->intermediaryColorDescription, m_surface->targetColorDescription, RenderingIntent::RelativeColorimetric);
|
||||||
QMatrix4x4 ctm;
|
QMatrix4x4 ctm;
|
||||||
ctm(0, 0) = m_surface->channelFactors.x();
|
ctm(0, 0) = m_surface->channelFactors.x();
|
||||||
ctm(1, 1) = m_surface->channelFactors.y();
|
ctm(1, 1) = m_surface->channelFactors.y();
|
||||||
|
|
|
@ -491,7 +491,7 @@ void DrmOutput::tryKmsColorOffloading()
|
||||||
const QVector3D channelFactors = effectiveChannelFactors();
|
const QVector3D channelFactors = effectiveChannelFactors();
|
||||||
const double maxLuminance = colorDescription().maxHdrLuminance().value_or(colorDescription().referenceLuminance());
|
const double maxLuminance = colorDescription().maxHdrLuminance().value_or(colorDescription().referenceLuminance());
|
||||||
const ColorDescription optimal = colorDescription().transferFunction().type == TransferFunction::gamma22 ? colorDescription() : colorDescription().withTransferFunction(TransferFunction(TransferFunction::gamma22, 0, maxLuminance));
|
const ColorDescription optimal = colorDescription().transferFunction().type == TransferFunction::gamma22 ? colorDescription() : colorDescription().withTransferFunction(TransferFunction(TransferFunction::gamma22, 0, maxLuminance));
|
||||||
ColorPipeline colorPipeline = ColorPipeline::create(optimal, colorDescription());
|
ColorPipeline colorPipeline = ColorPipeline::create(optimal, colorDescription(), RenderingIntent::RelativeColorimetric);
|
||||||
colorPipeline.addTransferFunction(colorDescription().transferFunction());
|
colorPipeline.addTransferFunction(colorDescription().transferFunction());
|
||||||
colorPipeline.addMultiplier(channelFactors);
|
colorPipeline.addMultiplier(channelFactors);
|
||||||
colorPipeline.addInverseTransferFunction(colorDescription().transferFunction());
|
colorPipeline.addInverseTransferFunction(colorDescription().transferFunction());
|
||||||
|
@ -517,7 +517,7 @@ bool DrmOutput::needsChannelFactorFallback() const
|
||||||
|
|
||||||
QVector3D DrmOutput::effectiveChannelFactors() const
|
QVector3D DrmOutput::effectiveChannelFactors() const
|
||||||
{
|
{
|
||||||
QVector3D adaptedChannelFactors = Colorimetry::fromName(NamedColorimetry::BT709).toOther(m_state.colorDescription.containerColorimetry()) * m_channelFactors;
|
QVector3D adaptedChannelFactors = Colorimetry::fromName(NamedColorimetry::BT709).toOther(m_state.colorDescription.containerColorimetry(), RenderingIntent::RelativeColorimetric) * m_channelFactors;
|
||||||
// normalize red to be the original brightness value again
|
// normalize red to be the original brightness value again
|
||||||
adaptedChannelFactors *= m_channelFactors.x() / adaptedChannelFactors.x();
|
adaptedChannelFactors *= m_channelFactors.x() / adaptedChannelFactors.x();
|
||||||
if (m_state.highDynamicRange || !m_brightnessDevice) {
|
if (m_state.highDynamicRange || !m_brightnessDevice) {
|
||||||
|
|
|
@ -133,7 +133,7 @@ std::shared_ptr<GLTexture> VirtualEglGbmLayer::texture() const
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualEglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, const std::shared_ptr<OutputFrame> &frame)
|
bool VirtualEglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||||
{
|
{
|
||||||
static bool valid;
|
static bool valid;
|
||||||
static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid;
|
static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid;
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
const ColorDescription &colorDescription() const;
|
const ColorDescription &colorDescription() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, const std::shared_ptr<OutputFrame> &frame) override;
|
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame) override;
|
||||||
std::shared_ptr<EglSwapchain> createGbmSwapchain() const;
|
std::shared_ptr<EglSwapchain> createGbmSwapchain() const;
|
||||||
bool doesGbmSwapchainFit(EglSwapchain *swapchain) const;
|
bool doesGbmSwapchainFit(EglSwapchain *swapchain) const;
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ bool WaylandEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRe
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WaylandEglPrimaryLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, const std::shared_ptr<OutputFrame> &frame)
|
bool WaylandEglPrimaryLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!m_presentationBuffer);
|
Q_ASSERT(!m_presentationBuffer);
|
||||||
// TODO use viewporter to relax this check
|
// TODO use viewporter to relax this check
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
|
|
||||||
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
|
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
|
||||||
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override;
|
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override;
|
||||||
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, const std::shared_ptr<OutputFrame> &frame) override;
|
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame) override;
|
||||||
DrmDevice *scanoutDevice() const override;
|
DrmDevice *scanoutDevice() const override;
|
||||||
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
|
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
|
||||||
|
|
||||||
|
|
|
@ -287,7 +287,7 @@ static bool checkForBlackBackground(SurfaceItem *background)
|
||||||
}
|
}
|
||||||
const QRgb rgb = view.image()->pixel(0, 0);
|
const QRgb rgb = view.image()->pixel(0, 0);
|
||||||
const QVector3D encoded(qRed(rgb) / 255.0, qGreen(rgb) / 255.0, qBlue(rgb) / 255.0);
|
const QVector3D encoded(qRed(rgb) / 255.0, qGreen(rgb) / 255.0, qBlue(rgb) / 255.0);
|
||||||
const QVector3D nits = background->colorDescription().mapTo(encoded, ColorDescription(NamedColorimetry::BT709, TransferFunction(TransferFunction::linear), 100, 0, std::nullopt, std::nullopt));
|
const QVector3D nits = background->colorDescription().mapTo(encoded, ColorDescription(NamedColorimetry::BT709, TransferFunction(TransferFunction::linear), 100, 0, std::nullopt, std::nullopt), background->renderingIntent());
|
||||||
// below 0.1 nits, it shouldn't be noticeable that we replace it with black
|
// below 0.1 nits, it shouldn't be noticeable that we replace it with black
|
||||||
return nits.lengthSquared() <= (0.1 * 0.1);
|
return nits.lengthSquared() <= (0.1 * 0.1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
ColorPipeline ColorPipeline::create(const ColorDescription &from, const ColorDescription &to)
|
ColorPipeline ColorPipeline::create(const ColorDescription &from, const ColorDescription &to, RenderingIntent intent)
|
||||||
{
|
{
|
||||||
const auto range1 = ValueRange(from.minLuminance(), from.maxHdrLuminance().value_or(from.referenceLuminance()));
|
const auto range1 = ValueRange(from.minLuminance(), from.maxHdrLuminance().value_or(from.referenceLuminance()));
|
||||||
ColorPipeline ret(ValueRange{
|
ColorPipeline ret(ValueRange{
|
||||||
|
@ -23,7 +23,7 @@ ColorPipeline ColorPipeline::create(const ColorDescription &from, const ColorDes
|
||||||
|
|
||||||
// FIXME this assumes that the range stays the same with matrix multiplication
|
// FIXME this assumes that the range stays the same with matrix multiplication
|
||||||
// that's not necessarily true, and figuring out the actual range could be complicated..
|
// that's not necessarily true, and figuring out the actual range could be complicated..
|
||||||
ret.addMatrix(from.containerColorimetry().toOther(to.containerColorimetry()), ret.currentOutputRange());
|
ret.addMatrix(from.containerColorimetry().toOther(to.containerColorimetry(), intent), ret.currentOutputRange());
|
||||||
|
|
||||||
ret.addInverseTransferFunction(to.transferFunction());
|
ret.addInverseTransferFunction(to.transferFunction());
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -79,7 +79,7 @@ public:
|
||||||
explicit ColorPipeline();
|
explicit ColorPipeline();
|
||||||
explicit ColorPipeline(const ValueRange &inputRange);
|
explicit ColorPipeline(const ValueRange &inputRange);
|
||||||
|
|
||||||
static ColorPipeline create(const ColorDescription &from, const ColorDescription &to);
|
static ColorPipeline create(const ColorDescription &from, const ColorDescription &to, RenderingIntent intent);
|
||||||
|
|
||||||
ColorPipeline merged(const ColorPipeline &onTop) const;
|
ColorPipeline merged(const ColorPipeline &onTop) const;
|
||||||
|
|
||||||
|
|
|
@ -126,10 +126,16 @@ const QMatrix4x4 &Colorimetry::fromXYZ() const
|
||||||
return m_fromXYZ;
|
return m_fromXYZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMatrix4x4 Colorimetry::toOther(const Colorimetry &other) const
|
QMatrix4x4 Colorimetry::toOther(const Colorimetry &other, RenderingIntent intent) const
|
||||||
{
|
{
|
||||||
// rendering intent is relative colorimetric, so adapt to the different whitepoint
|
switch (intent) {
|
||||||
return other.fromXYZ() * chromaticAdaptationMatrix(this->white(), other.white()) * toXYZ();
|
case RenderingIntent::Perceptual:
|
||||||
|
case RenderingIntent::RelativeColorimetric:
|
||||||
|
return other.fromXYZ() * chromaticAdaptationMatrix(this->white(), other.white()) * toXYZ();
|
||||||
|
case RenderingIntent::AbsoluteColorimetric:
|
||||||
|
return other.fromXYZ() * toXYZ();
|
||||||
|
}
|
||||||
|
Q_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
Colorimetry Colorimetry::adaptedTo(QVector2D newWhitepoint) const
|
Colorimetry Colorimetry::adaptedTo(QVector2D newWhitepoint) const
|
||||||
|
@ -267,11 +273,11 @@ std::optional<double> ColorDescription::maxHdrLuminance() const
|
||||||
return m_maxHdrLuminance;
|
return m_maxHdrLuminance;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector3D ColorDescription::mapTo(QVector3D rgb, const ColorDescription &dst) const
|
QVector3D ColorDescription::mapTo(QVector3D rgb, const ColorDescription &dst, RenderingIntent intent) const
|
||||||
{
|
{
|
||||||
rgb = m_transferFunction.encodedToNits(rgb);
|
rgb = m_transferFunction.encodedToNits(rgb);
|
||||||
rgb *= dst.referenceLuminance() / m_referenceLuminance;
|
rgb *= dst.referenceLuminance() / m_referenceLuminance;
|
||||||
rgb = m_containerColorimetry.toOther(dst.containerColorimetry()) * rgb;
|
rgb = m_containerColorimetry.toOther(dst.containerColorimetry(), intent) * rgb;
|
||||||
return dst.transferFunction().nitsToEncoded(rgb);
|
return dst.transferFunction().nitsToEncoded(rgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,22 @@
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rendering intents describe how colors should be mapped between different color spaces
|
||||||
|
*/
|
||||||
|
enum class RenderingIntent {
|
||||||
|
/* "vendor specific", preserves the overall color appearance */
|
||||||
|
Perceptual,
|
||||||
|
/* "vendor specific", maps saturated colors to be saturated in the target color space too */
|
||||||
|
// TODO Saturation,
|
||||||
|
/* colorimetric mapping between color spaces, with whitepoint adaptation */
|
||||||
|
RelativeColorimetric,
|
||||||
|
/* colorimetric mapping between color spaces, without whitepoint adaptation */
|
||||||
|
AbsoluteColorimetric,
|
||||||
|
/* colorimetric mapping between color spaces, with whitepoint adaptation and black point compensation */
|
||||||
|
// TODO RelativeColorimetricWithBPC,
|
||||||
|
};
|
||||||
|
|
||||||
enum class NamedColorimetry {
|
enum class NamedColorimetry {
|
||||||
BT709,
|
BT709,
|
||||||
BT2020,
|
BT2020,
|
||||||
|
@ -56,9 +72,8 @@ public:
|
||||||
const QMatrix4x4 &fromXYZ() const;
|
const QMatrix4x4 &fromXYZ() const;
|
||||||
/**
|
/**
|
||||||
* @returns a matrix that transforms from linear RGB in this colorimetry to linear RGB in the other colorimetry
|
* @returns a matrix that transforms from linear RGB in this colorimetry to linear RGB in the other colorimetry
|
||||||
* the rendering intent is relative colorimetric
|
|
||||||
*/
|
*/
|
||||||
QMatrix4x4 toOther(const Colorimetry &colorimetry) const;
|
QMatrix4x4 toOther(const Colorimetry &colorimetry, RenderingIntent intent) const;
|
||||||
bool operator==(const Colorimetry &other) const;
|
bool operator==(const Colorimetry &other) const;
|
||||||
bool operator==(NamedColorimetry name) const;
|
bool operator==(NamedColorimetry name) const;
|
||||||
/**
|
/**
|
||||||
|
@ -164,7 +179,7 @@ public:
|
||||||
|
|
||||||
bool operator==(const ColorDescription &other) const = default;
|
bool operator==(const ColorDescription &other) const = default;
|
||||||
|
|
||||||
QVector3D mapTo(QVector3D rgb, const ColorDescription &other) const;
|
QVector3D mapTo(QVector3D rgb, const ColorDescription &other, RenderingIntent intent) const;
|
||||||
ColorDescription withTransferFunction(const TransferFunction &func) const;
|
ColorDescription withTransferFunction(const TransferFunction &func) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -62,7 +62,7 @@ bool OutputLayer::needsRepaint() const
|
||||||
return !m_repaints.isEmpty();
|
return !m_repaints.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OutputLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, const std::shared_ptr<OutputFrame> &frame)
|
bool OutputLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ bool OutputLayer::attemptScanout(SurfaceItem *surfaceItem, const std::shared_ptr
|
||||||
m_bufferTransform = surfaceItem->bufferTransform();
|
m_bufferTransform = surfaceItem->bufferTransform();
|
||||||
const auto desiredTransform = m_output ? m_output->transform() : OutputTransform::Kind::Normal;
|
const auto desiredTransform = m_output ? m_output->transform() : OutputTransform::Kind::Normal;
|
||||||
m_offloadTransform = m_bufferTransform.combine(desiredTransform.inverted());
|
m_offloadTransform = m_bufferTransform.combine(desiredTransform.inverted());
|
||||||
const bool ret = doAttemptScanout(buffer, surfaceItem->colorDescription(), frame);
|
const bool ret = doAttemptScanout(buffer, surfaceItem->colorDescription(), surfaceItem->renderingIntent(), frame);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
surfaceItem->resetDamage();
|
surfaceItem->resetDamage();
|
||||||
// ensure the pixmap is updated when direct scanout ends
|
// ensure the pixmap is updated when direct scanout ends
|
||||||
|
|
|
@ -95,7 +95,7 @@ public:
|
||||||
OutputTransform bufferTransform() const;
|
OutputTransform bufferTransform() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, const std::shared_ptr<OutputFrame> &frame);
|
virtual bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame);
|
||||||
virtual std::optional<OutputLayerBeginFrameInfo> doBeginFrame() = 0;
|
virtual std::optional<OutputLayerBeginFrameInfo> doBeginFrame() = 0;
|
||||||
virtual bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) = 0;
|
virtual bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) = 0;
|
||||||
|
|
||||||
|
|
|
@ -1501,7 +1501,7 @@ void EffectsHandler::renderOffscreenQuickView(const RenderTarget &renderTarget,
|
||||||
if (a != 1.0) {
|
if (a != 1.0) {
|
||||||
shader->setUniform(GLShader::Vec4Uniform::ModulationConstant, QVector4D(a, a, a, a));
|
shader->setUniform(GLShader::Vec4Uniform::ModulationConstant, QVector4D(a, a, a, a));
|
||||||
}
|
}
|
||||||
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription());
|
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
|
|
||||||
const bool alphaBlending = w->hasAlphaChannel() || (a != 1.0);
|
const bool alphaBlending = w->hasAlphaChannel() || (a != 1.0);
|
||||||
if (alphaBlending) {
|
if (alphaBlending) {
|
||||||
|
|
|
@ -189,7 +189,7 @@ void OffscreenData::paint(const RenderTarget &renderTarget, const RenderViewport
|
||||||
shader->setUniform(GLShader::Vec3Uniform::PrimaryBrightness, QVector3D(toXYZ(1, 0), toXYZ(1, 1), toXYZ(1, 2)));
|
shader->setUniform(GLShader::Vec3Uniform::PrimaryBrightness, QVector3D(toXYZ(1, 0), toXYZ(1, 1), toXYZ(1, 2)));
|
||||||
shader->setUniform(GLShader::IntUniform::TextureWidth, m_texture->width());
|
shader->setUniform(GLShader::IntUniform::TextureWidth, m_texture->width());
|
||||||
shader->setUniform(GLShader::IntUniform::TextureHeight, m_texture->height());
|
shader->setUniform(GLShader::IntUniform::TextureHeight, m_texture->height());
|
||||||
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription());
|
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
|
|
||||||
const bool clipping = region != infiniteRegion();
|
const bool clipping = region != infiniteRegion();
|
||||||
const QRegion clipRegion = clipping ? viewport.mapToRenderTarget(region) : infiniteRegion();
|
const QRegion clipRegion = clipping ? viewport.mapToRenderTarget(region) : infiniteRegion();
|
||||||
|
|
|
@ -469,10 +469,10 @@ QMatrix4x4 GLShader::getUniformMatrix4x4(const char *name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLShader::setColorspaceUniforms(const ColorDescription &src, const ColorDescription &dst)
|
bool GLShader::setColorspaceUniforms(const ColorDescription &src, const ColorDescription &dst, RenderingIntent intent)
|
||||||
{
|
{
|
||||||
const auto &srcColorimetry = src.containerColorimetry() == NamedColorimetry::BT709 ? dst.sdrColorimetry() : src.containerColorimetry();
|
const auto &srcColorimetry = intent == RenderingIntent::Perceptual && src.containerColorimetry() == NamedColorimetry::BT709 ? dst.sdrColorimetry() : src.containerColorimetry();
|
||||||
return setUniform(Mat4Uniform::ColorimetryTransformation, srcColorimetry.toOther(dst.containerColorimetry()))
|
return setUniform(Mat4Uniform::ColorimetryTransformation, srcColorimetry.toOther(dst.containerColorimetry(), intent))
|
||||||
&& setUniform(IntUniform::SourceNamedTransferFunction, src.transferFunction().type)
|
&& setUniform(IntUniform::SourceNamedTransferFunction, src.transferFunction().type)
|
||||||
&& setUniform(Vec2Uniform::SourceTransferFunctionParams, QVector2D(src.transferFunction().minLuminance, src.transferFunction().maxLuminance - src.transferFunction().minLuminance))
|
&& setUniform(Vec2Uniform::SourceTransferFunctionParams, QVector2D(src.transferFunction().minLuminance, src.transferFunction().maxLuminance - src.transferFunction().minLuminance))
|
||||||
&& setUniform(FloatUniform::SourceReferenceLuminance, src.referenceLuminance())
|
&& setUniform(FloatUniform::SourceReferenceLuminance, src.referenceLuminance())
|
||||||
|
|
|
@ -138,7 +138,7 @@ public:
|
||||||
bool setUniform(ColorUniform uniform, const QVector4D &value);
|
bool setUniform(ColorUniform uniform, const QVector4D &value);
|
||||||
bool setUniform(ColorUniform uniform, const QColor &value);
|
bool setUniform(ColorUniform uniform, const QColor &value);
|
||||||
|
|
||||||
bool setColorspaceUniforms(const ColorDescription &src, const ColorDescription &dst);
|
bool setColorspaceUniforms(const ColorDescription &src, const ColorDescription &dst, RenderingIntent intent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GLShader(unsigned int flags = NoFlags);
|
GLShader(unsigned int flags = NoFlags);
|
||||||
|
|
|
@ -67,7 +67,7 @@ void ColorPickerEffect::paintScreen(const RenderTarget &renderTarget, const Rend
|
||||||
const QPoint texturePosition = viewport.mapToRenderTarget(m_scheduledPosition).toPoint();
|
const QPoint texturePosition = viewport.mapToRenderTarget(m_scheduledPosition).toPoint();
|
||||||
|
|
||||||
glReadPixels(texturePosition.x(), renderTarget.size().height() - texturePosition.y() - PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE, GL_RGBA, GL_FLOAT, data.data());
|
glReadPixels(texturePosition.x(), renderTarget.size().height() - texturePosition.y() - PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE, GL_RGBA, GL_FLOAT, data.data());
|
||||||
QVector3D sRGB = 255 * renderTarget.colorDescription().mapTo(QVector3D(data[0], data[1], data[2]), ColorDescription::sRGB);
|
QVector3D sRGB = 255 * renderTarget.colorDescription().mapTo(QVector3D(data[0], data[1], data[2]), ColorDescription::sRGB, RenderingIntent::RelativeColorimetric);
|
||||||
QDBusConnection::sessionBus().send(m_replyMessage.createReply(QColor(sRGB.x(), sRGB.y(), sRGB.z())));
|
QDBusConnection::sessionBus().send(m_replyMessage.createReply(QColor(sRGB.x(), sRGB.y(), sRGB.z())));
|
||||||
setPicking(false);
|
setPicking(false);
|
||||||
m_scheduledPosition = QPoint(-1, -1);
|
m_scheduledPosition = QPoint(-1, -1);
|
||||||
|
|
|
@ -300,7 +300,7 @@ void MouseClickEffect::paintScreenSetupGl(const RenderTarget &renderTarget, cons
|
||||||
{
|
{
|
||||||
GLShader *shader = ShaderManager::instance()->pushShader(ShaderTrait::UniformColor | ShaderTrait::TransformColorspace);
|
GLShader *shader = ShaderManager::instance()->pushShader(ShaderTrait::UniformColor | ShaderTrait::TransformColorspace);
|
||||||
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
|
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
|
||||||
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription());
|
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
|
|
||||||
glLineWidth(m_lineWidth);
|
glLineWidth(m_lineWidth);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
|
|
@ -118,7 +118,7 @@ void MouseMarkEffect::paintScreen(const RenderTarget &renderTarget, const Render
|
||||||
const auto scale = viewport.scale();
|
const auto scale = viewport.scale();
|
||||||
ShaderBinder binder(ShaderTrait::UniformColor | ShaderTrait::TransformColorspace);
|
ShaderBinder binder(ShaderTrait::UniformColor | ShaderTrait::TransformColorspace);
|
||||||
binder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, viewport.projectionMatrix());
|
binder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, viewport.projectionMatrix());
|
||||||
binder.shader()->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription());
|
binder.shader()->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
binder.shader()->setUniform(GLShader::ColorUniform::Color, color);
|
binder.shader()->setUniform(GLShader::ColorUniform::Color, color);
|
||||||
QList<QVector2D> verts;
|
QList<QVector2D> verts;
|
||||||
for (const Mark &mark : std::as_const(marks)) {
|
for (const Mark &mark : std::as_const(marks)) {
|
||||||
|
|
|
@ -72,7 +72,7 @@ void OutputScreenCastSource::render(GLFramebuffer *target)
|
||||||
projectionMatrix.scale(1, -1);
|
projectionMatrix.scale(1, -1);
|
||||||
projectionMatrix.ortho(QRect(QPoint(), textureSize()));
|
projectionMatrix.ortho(QRect(QPoint(), textureSize()));
|
||||||
shaderBinder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
|
shaderBinder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
|
||||||
shaderBinder.shader()->setColorspaceUniforms(colorDescription, ColorDescription::sRGB);
|
shaderBinder.shader()->setColorspaceUniforms(colorDescription, ColorDescription::sRGB, RenderingIntent::Perceptual);
|
||||||
|
|
||||||
GLFramebuffer::pushFramebuffer(target);
|
GLFramebuffer::pushFramebuffer(target);
|
||||||
outputTexture->render(textureSize());
|
outputTexture->render(textureSize());
|
||||||
|
|
|
@ -107,7 +107,7 @@ void RegionScreenCastSource::blit(Output *output)
|
||||||
projectionMatrix.translate(outputGeometry.left(), outputGeometry.top());
|
projectionMatrix.translate(outputGeometry.left(), outputGeometry.top());
|
||||||
|
|
||||||
shaderBinder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
|
shaderBinder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
|
||||||
shaderBinder.shader()->setColorspaceUniforms(colorDescription, ColorDescription::sRGB);
|
shaderBinder.shader()->setColorspaceUniforms(colorDescription, ColorDescription::sRGB, RenderingIntent::Perceptual);
|
||||||
|
|
||||||
outputTexture->render(outputGeometry.size());
|
outputTexture->render(outputGeometry.size());
|
||||||
GLFramebuffer::popFramebuffer();
|
GLFramebuffer::popFramebuffer();
|
||||||
|
|
|
@ -385,7 +385,7 @@ QImage ScreenShotEffect::blitScreenshot(const RenderTarget &renderTarget, const
|
||||||
if (renderTarget.texture()) {
|
if (renderTarget.texture()) {
|
||||||
GLFramebuffer::pushFramebuffer(&target);
|
GLFramebuffer::pushFramebuffer(&target);
|
||||||
ShaderBinder binder(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace);
|
ShaderBinder binder(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace);
|
||||||
binder.shader()->setColorspaceUniforms(renderTarget.colorDescription(), ColorDescription::sRGB);
|
binder.shader()->setColorspaceUniforms(renderTarget.colorDescription(), ColorDescription::sRGB, RenderingIntent::Perceptual);
|
||||||
QMatrix4x4 projectionMatrix;
|
QMatrix4x4 projectionMatrix;
|
||||||
projectionMatrix.scale(1, -1);
|
projectionMatrix.scale(1, -1);
|
||||||
projectionMatrix *= renderTarget.transform().toMatrix();
|
projectionMatrix *= renderTarget.transform().toMatrix();
|
||||||
|
|
|
@ -72,7 +72,7 @@ void ShowPaintEffect::paintGL(const RenderTarget &renderTarget, const QMatrix4x4
|
||||||
vbo->reset();
|
vbo->reset();
|
||||||
ShaderBinder binder(ShaderTrait::UniformColor | ShaderTrait::TransformColorspace);
|
ShaderBinder binder(ShaderTrait::UniformColor | ShaderTrait::TransformColorspace);
|
||||||
binder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projection);
|
binder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projection);
|
||||||
binder.shader()->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription());
|
binder.shader()->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
QColor color = s_colors[m_colorIndex];
|
QColor color = s_colors[m_colorIndex];
|
||||||
|
|
|
@ -113,7 +113,7 @@ void SnapHelperEffect::paintScreen(const RenderTarget &renderTarget, const Rende
|
||||||
vbo->reset();
|
vbo->reset();
|
||||||
ShaderBinder binder(ShaderTrait::UniformColor | ShaderTrait::TransformColorspace);
|
ShaderBinder binder(ShaderTrait::UniformColor | ShaderTrait::TransformColorspace);
|
||||||
binder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, viewport.projectionMatrix());
|
binder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, viewport.projectionMatrix());
|
||||||
binder.shader()->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription());
|
binder.shader()->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
|
|
@ -239,7 +239,7 @@ void StartupFeedbackEffect::paintScreen(const RenderTarget &renderTarget, const
|
||||||
QMatrix4x4 mvp = viewport.projectionMatrix();
|
QMatrix4x4 mvp = viewport.projectionMatrix();
|
||||||
mvp.translate(pixelGeometry.x(), pixelGeometry.y());
|
mvp.translate(pixelGeometry.x(), pixelGeometry.y());
|
||||||
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mvp);
|
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mvp);
|
||||||
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription());
|
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
texture->render(pixelGeometry.size());
|
texture->render(pixelGeometry.size());
|
||||||
ShaderManager::instance()->popShader();
|
ShaderManager::instance()->popShader();
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
|
|
@ -232,7 +232,7 @@ void TouchPointsEffect::paintScreenSetupGl(const RenderTarget &renderTarget, con
|
||||||
{
|
{
|
||||||
GLShader *shader = ShaderManager::instance()->pushShader(ShaderTrait::UniformColor);
|
GLShader *shader = ShaderManager::instance()->pushShader(ShaderTrait::UniformColor);
|
||||||
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
|
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
|
||||||
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription());
|
shader->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
|
|
||||||
glLineWidth(m_lineWidth);
|
glLineWidth(m_lineWidth);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
|
|
@ -399,7 +399,7 @@ void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewp
|
||||||
matrix.translate(offscreen.viewport.x() * scale, offscreen.viewport.y() * scale);
|
matrix.translate(offscreen.viewport.x() * scale, offscreen.viewport.y() * scale);
|
||||||
|
|
||||||
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, viewport.projectionMatrix() * matrix);
|
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, viewport.projectionMatrix() * matrix);
|
||||||
shader->setColorspaceUniforms(offscreen.color, renderTarget.colorDescription());
|
shader->setColorspaceUniforms(offscreen.color, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
|
|
||||||
offscreen.texture->render(offscreen.viewport.size() * scale);
|
offscreen.texture->render(offscreen.viewport.size() * scale);
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,7 @@ void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewp
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
auto s = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace);
|
auto s = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace);
|
||||||
s->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription());
|
s->setColorspaceUniforms(ColorDescription::sRGB, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||||
QMatrix4x4 mvp = viewport.projectionMatrix();
|
QMatrix4x4 mvp = viewport.projectionMatrix();
|
||||||
mvp.translate(p.x() * scale, p.y() * scale);
|
mvp.translate(p.x() * scale, p.y() * scale);
|
||||||
s->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mvp);
|
s->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mvp);
|
||||||
|
|
|
@ -491,11 +491,21 @@ const ColorDescription &Item::colorDescription() const
|
||||||
return m_colorDescription;
|
return m_colorDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RenderingIntent Item::renderingIntent() const
|
||||||
|
{
|
||||||
|
return m_renderingIntent;
|
||||||
|
}
|
||||||
|
|
||||||
void Item::setColorDescription(const ColorDescription &description)
|
void Item::setColorDescription(const ColorDescription &description)
|
||||||
{
|
{
|
||||||
m_colorDescription = description;
|
m_colorDescription = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item::setRenderingIntent(RenderingIntent intent)
|
||||||
|
{
|
||||||
|
m_renderingIntent = intent;
|
||||||
|
}
|
||||||
|
|
||||||
PresentationModeHint Item::presentationHint() const
|
PresentationModeHint Item::presentationHint() const
|
||||||
{
|
{
|
||||||
return m_presentationHint;
|
return m_presentationHint;
|
||||||
|
|
|
@ -113,6 +113,7 @@ public:
|
||||||
WindowQuadList quads() const;
|
WindowQuadList quads() const;
|
||||||
virtual void preprocess();
|
virtual void preprocess();
|
||||||
const ColorDescription &colorDescription() const;
|
const ColorDescription &colorDescription() const;
|
||||||
|
RenderingIntent renderingIntent() const;
|
||||||
PresentationModeHint presentationHint() const;
|
PresentationModeHint presentationHint() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
@ -136,6 +137,7 @@ protected:
|
||||||
virtual WindowQuadList buildQuads() const;
|
virtual WindowQuadList buildQuads() const;
|
||||||
void discardQuads();
|
void discardQuads();
|
||||||
void setColorDescription(const ColorDescription &description);
|
void setColorDescription(const ColorDescription &description);
|
||||||
|
void setRenderingIntent(RenderingIntent intent);
|
||||||
void setPresentationHint(PresentationModeHint hint);
|
void setPresentationHint(PresentationModeHint hint);
|
||||||
void setScene(Scene *scene);
|
void setScene(Scene *scene);
|
||||||
|
|
||||||
|
@ -169,6 +171,7 @@ private:
|
||||||
mutable std::optional<WindowQuadList> m_quads;
|
mutable std::optional<WindowQuadList> m_quads;
|
||||||
mutable std::optional<QList<Item *>> m_sortedChildItems;
|
mutable std::optional<QList<Item *>> m_sortedChildItems;
|
||||||
ColorDescription m_colorDescription = ColorDescription::sRGB;
|
ColorDescription m_colorDescription = ColorDescription::sRGB;
|
||||||
|
RenderingIntent m_renderingIntent = RenderingIntent::Perceptual;
|
||||||
PresentationModeHint m_presentationHint = PresentationModeHint::VSync;
|
PresentationModeHint m_presentationHint = PresentationModeHint::VSync;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context)
|
||||||
.hasAlpha = true,
|
.hasAlpha = true,
|
||||||
.coordinateType = UnnormalizedCoordinates,
|
.coordinateType = UnnormalizedCoordinates,
|
||||||
.colorDescription = item->colorDescription(),
|
.colorDescription = item->colorDescription(),
|
||||||
|
.renderingIntent = item->renderingIntent(),
|
||||||
.bufferReleasePoint = nullptr,
|
.bufferReleasePoint = nullptr,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -179,6 +180,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context)
|
||||||
.hasAlpha = true,
|
.hasAlpha = true,
|
||||||
.coordinateType = UnnormalizedCoordinates,
|
.coordinateType = UnnormalizedCoordinates,
|
||||||
.colorDescription = item->colorDescription(),
|
.colorDescription = item->colorDescription(),
|
||||||
|
.renderingIntent = item->renderingIntent(),
|
||||||
.bufferReleasePoint = nullptr,
|
.bufferReleasePoint = nullptr,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -195,6 +197,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context)
|
||||||
.hasAlpha = pixmap->hasAlphaChannel(),
|
.hasAlpha = pixmap->hasAlphaChannel(),
|
||||||
.coordinateType = NormalizedCoordinates,
|
.coordinateType = NormalizedCoordinates,
|
||||||
.colorDescription = item->colorDescription(),
|
.colorDescription = item->colorDescription(),
|
||||||
|
.renderingIntent = item->renderingIntent(),
|
||||||
.bufferReleasePoint = surfaceItem->bufferReleasePoint(),
|
.bufferReleasePoint = surfaceItem->bufferReleasePoint(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -209,6 +212,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context)
|
||||||
.hasAlpha = imageItem->image().hasAlphaChannel(),
|
.hasAlpha = imageItem->image().hasAlphaChannel(),
|
||||||
.coordinateType = NormalizedCoordinates,
|
.coordinateType = NormalizedCoordinates,
|
||||||
.colorDescription = item->colorDescription(),
|
.colorDescription = item->colorDescription(),
|
||||||
|
.renderingIntent = item->renderingIntent(),
|
||||||
.bufferReleasePoint = nullptr,
|
.bufferReleasePoint = nullptr,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -369,7 +373,7 @@ void ItemRendererOpenGL::renderItem(const RenderTarget &renderTarget, const Rend
|
||||||
shader->setUniform(GLShader::Vec4Uniform::ModulationConstant, modulate(renderNode.opacity, data.brightness()));
|
shader->setUniform(GLShader::Vec4Uniform::ModulationConstant, modulate(renderNode.opacity, data.brightness()));
|
||||||
}
|
}
|
||||||
if (traits & ShaderTrait::TransformColorspace) {
|
if (traits & ShaderTrait::TransformColorspace) {
|
||||||
shader->setColorspaceUniforms(renderNode.colorDescription, renderTarget.colorDescription());
|
shader->setColorspaceUniforms(renderNode.colorDescription, renderTarget.colorDescription(), renderNode.renderingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::holds_alternative<GLTexture *>(renderNode.texture)) {
|
if (std::holds_alternative<GLTexture *>(renderNode.texture)) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ public:
|
||||||
bool hasAlpha = false;
|
bool hasAlpha = false;
|
||||||
TextureCoordinateType coordinateType = UnnormalizedCoordinates;
|
TextureCoordinateType coordinateType = UnnormalizedCoordinates;
|
||||||
ColorDescription colorDescription;
|
ColorDescription colorDescription;
|
||||||
|
RenderingIntent renderingIntent;
|
||||||
std::shared_ptr<SyncReleasePoint> bufferReleasePoint;
|
std::shared_ptr<SyncReleasePoint> bufferReleasePoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -201,6 +201,7 @@ void SurfaceItemWayland::freeze()
|
||||||
void SurfaceItemWayland::handleColorDescriptionChanged()
|
void SurfaceItemWayland::handleColorDescriptionChanged()
|
||||||
{
|
{
|
||||||
setColorDescription(m_surface->colorDescription());
|
setColorDescription(m_surface->colorDescription());
|
||||||
|
setRenderingIntent(m_surface->renderingIntent());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceItemWayland::handlePresentationModeHintChanged()
|
void SurfaceItemWayland::handlePresentationModeHintChanged()
|
||||||
|
|
|
@ -1107,6 +1107,11 @@ const ColorDescription &SurfaceInterface::colorDescription() const
|
||||||
return d->current->colorDescription;
|
return d->current->colorDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RenderingIntent SurfaceInterface::renderingIntent() const
|
||||||
|
{
|
||||||
|
return d->current->renderingIntent;
|
||||||
|
}
|
||||||
|
|
||||||
void SurfaceInterface::setPreferredColorDescription(const ColorDescription &descr)
|
void SurfaceInterface::setPreferredColorDescription(const ColorDescription &descr)
|
||||||
{
|
{
|
||||||
if (d->preferredColorDescription == descr) {
|
if (d->preferredColorDescription == descr) {
|
||||||
|
|
|
@ -340,6 +340,7 @@ public:
|
||||||
void setLastTransaction(Transaction *transaction);
|
void setLastTransaction(Transaction *transaction);
|
||||||
|
|
||||||
const ColorDescription &colorDescription() const;
|
const ColorDescription &colorDescription() const;
|
||||||
|
RenderingIntent renderingIntent() const;
|
||||||
|
|
||||||
void setPreferredColorDescription(const ColorDescription &descr);
|
void setPreferredColorDescription(const ColorDescription &descr);
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ struct SurfaceState
|
||||||
ContentType contentType = ContentType::None;
|
ContentType contentType = ContentType::None;
|
||||||
PresentationModeHint presentationHint = PresentationModeHint::VSync;
|
PresentationModeHint presentationHint = PresentationModeHint::VSync;
|
||||||
ColorDescription colorDescription = ColorDescription::sRGB;
|
ColorDescription colorDescription = ColorDescription::sRGB;
|
||||||
|
RenderingIntent renderingIntent = RenderingIntent::Perceptual;
|
||||||
std::unique_ptr<PresentationTimeFeedback> presentationFeedback;
|
std::unique_ptr<PresentationTimeFeedback> presentationFeedback;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,7 +39,8 @@ void XXColorManagerV4::xx_color_manager_v4_bind_resource(Resource *resource)
|
||||||
|
|
||||||
send_supported_intent(resource->handle, render_intent::render_intent_perceptual);
|
send_supported_intent(resource->handle, render_intent::render_intent_perceptual);
|
||||||
send_supported_intent(resource->handle, render_intent::render_intent_relative);
|
send_supported_intent(resource->handle, render_intent::render_intent_relative);
|
||||||
// TODO implement the other rendering intents
|
send_supported_intent(resource->handle, render_intent::render_intent_absolute);
|
||||||
|
// TODO implement saturation and relative bpc intents
|
||||||
}
|
}
|
||||||
|
|
||||||
void XXColorManagerV4::xx_color_manager_v4_destroy(Resource *resource)
|
void XXColorManagerV4::xx_color_manager_v4_destroy(Resource *resource)
|
||||||
|
@ -143,15 +144,36 @@ void XXColorSurfaceV4::xx_color_management_surface_v4_destroy(Resource *resource
|
||||||
wl_resource_destroy(resource->handle);
|
wl_resource_destroy(resource->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::optional<RenderingIntent> waylandToKwinIntent(uint32_t intent)
|
||||||
|
{
|
||||||
|
switch (intent) {
|
||||||
|
case QtWaylandServer::xx_color_manager_v4::render_intent::render_intent_perceptual:
|
||||||
|
return RenderingIntent::Perceptual;
|
||||||
|
case QtWaylandServer::xx_color_manager_v4::render_intent::render_intent_relative:
|
||||||
|
return RenderingIntent::RelativeColorimetric;
|
||||||
|
case QtWaylandServer::xx_color_manager_v4::render_intent::render_intent_absolute:
|
||||||
|
return RenderingIntent::AbsoluteColorimetric;
|
||||||
|
case QtWaylandServer::xx_color_manager_v4::render_intent::render_intent_saturation:
|
||||||
|
case QtWaylandServer::xx_color_manager_v4::render_intent::render_intent_relative_bpc:
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
void XXColorSurfaceV4::xx_color_management_surface_v4_set_image_description(Resource *resource, struct ::wl_resource *image_description, uint32_t render_intent)
|
void XXColorSurfaceV4::xx_color_management_surface_v4_set_image_description(Resource *resource, struct ::wl_resource *image_description, uint32_t render_intent)
|
||||||
{
|
{
|
||||||
if (!m_surface) {
|
if (!m_surface) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const std::optional<RenderingIntent> intent = waylandToKwinIntent(render_intent);
|
||||||
|
if (!intent) {
|
||||||
|
wl_resource_post_error(resource->handle, XX_COLOR_MANAGER_V4_ERROR_UNSUPPORTED_FEATURE, "rendering intent is not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto priv = SurfaceInterfacePrivate::get(m_surface);
|
const auto priv = SurfaceInterfacePrivate::get(m_surface);
|
||||||
priv->pending->colorDescription = XXImageDescriptionV4::get(image_description)->description();
|
priv->pending->colorDescription = XXImageDescriptionV4::get(image_description)->description();
|
||||||
|
priv->pending->renderingIntent = *intent;
|
||||||
priv->pending->colorDescriptionIsSet = true;
|
priv->pending->colorDescriptionIsSet = true;
|
||||||
// TODO render_intent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XXColorSurfaceV4::xx_color_management_surface_v4_unset_image_description(Resource *resource)
|
void XXColorSurfaceV4::xx_color_management_surface_v4_unset_image_description(Resource *resource)
|
||||||
|
|
Loading…
Reference in a new issue