Warning, /graphics/krita/3rdparty/ext_qt/0005-Implement-color-conversion-for-the-backing-store-tex.patch is written in an unsupported language. File is not indexed.

0001 From 79d037731c8a195718bff3ea2d76a40f059c0735 Mon Sep 17 00:00:00 2001
0002 From: Dmitry Kazakov <dimula73@gmail.com>
0003 Date: Thu, 22 Nov 2018 15:47:48 +0300
0004 Subject: [PATCH 15/47] Implement color conversion for the backing store
0005  texture
0006 
0007 If the window surface is not in sRGB mode, then the backing store
0008 surface should be converted into the destinations color space.
0009 
0010 This patch adds the most popular color space transitions into
0011 QOpenGLTextureBlitter.
0012 
0013 The patch also implements QOpenGLWidget::setTextureColorSpace(),
0014 which notifies the compositor about the color space of non-native
0015 openGL widgets, so that the data could be converted correctly.
0016 
0017 TODO: should we implement the same for QOpenGLWindow::
0018       setTextureColorSpace()?
0019 
0020 Note:
0021 The channels should be swizzled into RGBA *before* applying the
0022 color space conversion matrix. Otherwise the colors will be skewed,
0023 because the conversion function for R and B channels is not the same.
0024 
0025 Change-Id: Icbf599952c93cc04de417d0c3790a65282741655
0026 ---
0027  src/gui/opengl/qopengltextureblitter.cpp      | 222 ++++++++++++++++--
0028  src/gui/opengl/qopengltextureblitter.h        |  12 +-
0029  src/gui/painting/qplatformbackingstore.cpp    |  16 +-
0030  src/gui/painting/qplatformbackingstore.h      |   4 +-
0031  .../qopenglcompositorbackingstore.cpp         |   2 +-
0032  src/widgets/kernel/qopenglwidget.cpp          |  45 +++-
0033  src/widgets/kernel/qopenglwidget.h            |   3 +
0034  src/widgets/kernel/qwidget_p.h                |   1 +
0035  src/widgets/kernel/qwidgetbackingstore.cpp    |   2 +-
0036  9 files changed, 281 insertions(+), 26 deletions(-)
0037 
0038 diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp
0039 index b709f2f639..8b9142a0ef 100644
0040 --- a/src/gui/opengl/qopengltextureblitter.cpp
0041 +++ b/src/gui/opengl/qopengltextureblitter.cpp
0042 @@ -131,14 +131,85 @@ static const char vertex_shader[] =
0043      "}";
0044  
0045  static const char fragment_shader[] =
0046 -    "varying highp vec2 uv;"
0047 -    "uniform sampler2D textureSampler;"
0048 -    "uniform bool swizzle;"
0049 -    "uniform highp float opacity;"
0050 +    "varying highp vec2 uv;\n"
0051 +    "uniform sampler2D textureSampler;\n"
0052 +    "uniform bool swizzle;\n"
0053 +    "uniform highp float opacity;\n"
0054 +    "#if defined SCRGB_TO_SRGB\n"
0055 +    "highp vec4 linearToSRGB(highp vec4 value)\n"
0056 +    "{\n"
0057 +    "   bvec4 cutoff = lessThan(value, vec4(0.0031308));\n"
0058 +    "   const highp vec2 a1 = vec2(0.055, 0.0);\n"
0059 +    "   const highp vec2 c2 = vec2(1.055, 1.0);\n"
0060 +    "   const highp vec2 m3 = vec2(2.4, 1.0);\n"
0061 +    "   const highp vec2 c4 = vec2(12.92, 1.0);\n"
0062 +    "   highp vec4 higher = c2.xxxy * pow(value, 1.0 / m3.xxxy) - a1.xxxy;\n"
0063 +    "   highp vec4 lower = value * c4.xxxy;\n"
0064 +    "   return mix(higher, lower, vec4(cutoff));\n"
0065 +    "}\n"
0066 +    "#endif\n"
0067 +    "#if defined SRGB_TO_SCRGB || defined SRGB_TO_BT2020PQ || defined SCRGB_TO_BT2020PQ\n"
0068 +    "highp vec4 sRgbToLinear(highp vec4 sRGB)\n"
0069 +    "{\n"
0070 +    "   bvec4 cutoff = lessThan(sRGB, vec4(0.04045));\n"
0071 +    "   const highp vec2 a1 = vec2(0.055, 0.0);\n"
0072 +    "   const highp vec2 c2 = vec2(1.055, 1.0);\n"
0073 +    "   const highp vec2 m3 = vec2(2.4, 1.0);\n"
0074 +    "   const highp vec2 c4 = vec2(12.92, 1.0);\n"
0075 +    "   highp vec4 higher = pow((sRGB + a1.xxxy) / c2.xxxy, m3.xxxy);\n"
0076 +    "   highp vec4 lower = sRGB / c4.xxxy;\n"
0077 +    "   return mix(higher, lower, vec4(cutoff));\n"
0078 +    "}\n"
0079 +    "#endif\n"
0080 +    "#if defined SRGB_TO_BT2020PQ || defined SCRGB_TO_BT2020PQ\n"
0081 +    "highp vec4 applySmpte2084Curve(highp vec4 L)\n"
0082 +    "{"
0083 +    "   const highp vec2 m1 = vec2(2610.0 / 4096.0 / 4.0, 1.0);\n"
0084 +    "   const highp vec2 m2 = vec2(2523.0 / 4096.0 * 128.0, 1.0);\n"
0085 +    "   const highp vec2 a1 = vec2(3424.0 / 4096.0, 0.0);\n"
0086 +    "   const highp vec2 c2 = vec2(2413.0 / 4096.0 * 32.0, 1.0);\n"
0087 +    "   const highp vec2 c3 = vec2(2392.0 / 4096.0 * 32.0, 1.0);\n"
0088 +    "   const highp vec2 a4 = vec2(1.0, 0.0);\n"
0089 +    "   highp vec4 Lp = pow(L, m1.xxxy);\n"
0090 +    "   highp vec4 res = pow((a1.xxxy + c2.xxxy * Lp) / (a4.xxxy + c3.xxxy * Lp), m2.xxxy);\n"
0091 +    "   return res;"
0092 +    "}\n"
0093 +    "#endif\n"
0094 +    "#if defined SRGB_TO_BT2020PQ || defined SCRGB_TO_BT2020PQ\n"
0095 +    "highp vec4 scRgbToBt2020pq(highp vec4 value)\n"
0096 +    "{\n"
0097 +    "   const highp mat4 convMat = "
0098 +    "      mat4(0.627402, 0.069095, 0.016394, 0.0,"
0099 +    "           0.329292, 0.919544, 0.088028, 0.0,"
0100 +    "           0.043306, 0.011360, 0.895578, 0.0,"
0101 +    "           0.0,      0.0,      0.0,      1.0);"
0102 +    ""
0103 +    "   value = convMat * value;\n"
0104 +    "   return applySmpte2084Curve(0.008 * value);"
0105 +    "}\n"
0106 +    "#endif\n"
0107 +    "#if defined SRGB_TO_BT2020PQ\n"
0108 +    "highp vec4 sRgbToBt2020pq(highp vec4 value)\n"
0109 +    "{\n"
0110 +    "   value = sRgbToLinear(value);"
0111 +    "   return scRgbToBt2020pq(value);"
0112 +    "}\n"
0113 +    "#endif\n"
0114 +    "\n"
0115      "void main() {"
0116      "   highp vec4 tmpFragColor = texture2D(textureSampler,uv);"
0117 -    "   tmpFragColor.a *= opacity;"
0118 -    "   gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
0119 +    "   tmpFragColor.a *= opacity;\n"
0120 +    "   tmpFragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;\n"
0121 +    "#if defined SRGB_TO_SCRGB\n"
0122 +    "   tmpFragColor = sRgbToLinear(tmpFragColor);\n"
0123 +    "#elif defined SRGB_TO_BT2020PQ\n"
0124 +    "   tmpFragColor = sRgbToBt2020pq(tmpFragColor);\n"
0125 +    "#elif defined SCRGB_TO_BT2020PQ\n"
0126 +    "   tmpFragColor = scRgbToBt2020pq(tmpFragColor);\n"
0127 +    "#elif defined SCRGB_TO_SRGB\n"
0128 +    "   tmpFragColor = linearToSRGB(tmpFragColor);\n"
0129 +    "#endif\n"
0130 +    "   gl_FragColor = tmpFragColor;"
0131      "}";
0132  
0133  static const char fragment_shader_external_oes[] =
0134 @@ -187,6 +258,23 @@ private:
0135      GLenum m_target;
0136  };
0137  
0138 +class ColorSpaceConversion : public QPair<QSurfaceFormat::ColorSpace, QSurfaceFormat::ColorSpace>
0139 +{
0140 +public:
0141 +    ColorSpaceConversion() { };
0142 +    ColorSpaceConversion(QSurfaceFormat::ColorSpace srcColorSpace,
0143 +                         QSurfaceFormat::ColorSpace dstColorSpace)
0144 +        : QPair(srcColorSpace, dstColorSpace)
0145 +    { }
0146 +
0147 +    QSurfaceFormat::ColorSpace source() const {
0148 +        return first;
0149 +    }
0150 +    QSurfaceFormat::ColorSpace destination() const {
0151 +        return second;
0152 +    }
0153 +};
0154 +
0155  class QOpenGLTextureBlitterPrivate
0156  {
0157  public:
0158 @@ -197,16 +285,29 @@ public:
0159      };
0160  
0161      enum ProgramIndex {
0162 -        TEXTURE_2D,
0163 -        TEXTURE_EXTERNAL_OES
0164 +        TEXTURE_2D = 0,
0165 +        TEXTURE_2D_SRGB_TO_SCRGB,
0166 +        TEXTURE_2D_SCRGB_TO_SRGB,
0167 +        TEXTURE_2D_SRGB_TO_BT2020PQ,
0168 +        TEXTURE_2D_SCRGB_TO_BT2020PQ,
0169 +        TEXTURE_EXTERNAL_OES,
0170 +
0171 +        PROGRAM_COUNT
0172      };
0173  
0174      QOpenGLTextureBlitterPrivate() :
0175          swizzle(false),
0176          opacity(1.0f),
0177          vao(new QOpenGLVertexArrayObject),
0178 -        currentTarget(TEXTURE_2D)
0179 -    { }
0180 +        currentTarget(GL_NONE),
0181 +        colorSpaceConversion(0)
0182 +    {
0183 +        supportedColorSpaceConversions << ColorSpaceConversion(QSurfaceFormat::DefaultColorSpace, QSurfaceFormat::DefaultColorSpace);
0184 +        supportedColorSpaceConversions << ColorSpaceConversion(QSurfaceFormat::sRGBColorSpace, QSurfaceFormat::scRGBColorSpace);
0185 +        supportedColorSpaceConversions << ColorSpaceConversion(QSurfaceFormat::scRGBColorSpace, QSurfaceFormat::sRGBColorSpace);
0186 +        supportedColorSpaceConversions << ColorSpaceConversion(QSurfaceFormat::sRGBColorSpace, QSurfaceFormat::bt2020PQColorSpace);
0187 +        supportedColorSpaceConversions << ColorSpaceConversion(QSurfaceFormat::scRGBColorSpace, QSurfaceFormat::bt2020PQColorSpace);
0188 +    }
0189  
0190      bool buildProgram(ProgramIndex idx, const char *vs, const char *fs);
0191  
0192 @@ -214,6 +315,7 @@ public:
0193      void blit(GLuint texture, const QMatrix4x4 &vertexTransform, QOpenGLTextureBlitter::Origin origin);
0194  
0195      void prepareProgram(const QMatrix4x4 &vertexTransform);
0196 +    int calcColorSpaceConversionIndex(QSurfaceFormat::ColorSpace srcColorSpace, QSurfaceFormat::ColorSpace dstColorSpace);
0197  
0198      QOpenGLBuffer vertexBuffer;
0199      QOpenGLBuffer textureBuffer;
0200 @@ -239,18 +341,48 @@ public:
0201          bool swizzle;
0202          float opacity;
0203          TextureMatrixUniform textureMatrixUniformState;
0204 -    } programs[2];
0205 +    } programs[PROGRAM_COUNT];
0206      bool swizzle;
0207      float opacity;
0208      QScopedPointer<QOpenGLVertexArrayObject> vao;
0209      GLenum currentTarget;
0210 +
0211 +    int colorSpaceConversion;
0212 +    QVector<ColorSpaceConversion> supportedColorSpaceConversions;
0213  };
0214  
0215 -static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GLenum target)
0216 +int QOpenGLTextureBlitterPrivate::calcColorSpaceConversionIndex(QSurfaceFormat::ColorSpace srcColorSpace, QSurfaceFormat::ColorSpace dstColorSpace)
0217 +{
0218 +    // TODO: auto-detect destination color space of the surface
0219 +    //       in case of default color space
0220 +
0221 +    // disable color management if at least one of the color
0222 +    // spaces is declared as default
0223 +    if (srcColorSpace == QSurfaceFormat::DefaultColorSpace ||
0224 +        dstColorSpace == QSurfaceFormat::DefaultColorSpace) {
0225 +
0226 +        return 0;
0227 +    }
0228 +
0229 +    // disable color management if source and destination color
0230 +    // spaces are the same
0231 +    if (srcColorSpace == dstColorSpace) {
0232 +        return 0;
0233 +    }
0234 +
0235 +    ColorSpaceConversion conversion(srcColorSpace, dstColorSpace);
0236 +    return supportedColorSpaceConversions.indexOf(conversion);
0237 +}
0238 +
0239 +static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GLenum target, int colorSpaceConversion)
0240  {
0241      switch (target) {
0242 -    case GL_TEXTURE_2D:
0243 -        return QOpenGLTextureBlitterPrivate::TEXTURE_2D;
0244 +    case GL_TEXTURE_2D: {
0245 +        QOpenGLTextureBlitterPrivate::ProgramIndex index =
0246 +            QOpenGLTextureBlitterPrivate::ProgramIndex(
0247 +                int(QOpenGLTextureBlitterPrivate::TEXTURE_2D) + colorSpaceConversion);
0248 +        return index;
0249 +    }
0250      case GL_TEXTURE_EXTERNAL_OES:
0251          return QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES;
0252      default:
0253 @@ -261,7 +393,7 @@ static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GL
0254  
0255  void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform)
0256  {
0257 -    Program *program = &programs[targetToProgramIndex(currentTarget)];
0258 +    Program *program = &programs[targetToProgramIndex(currentTarget, colorSpaceConversion)];
0259  
0260      vertexBuffer.bind();
0261      program->glProgram->setAttributeBuffer(program->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0);
0262 @@ -293,7 +425,7 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture,
0263      TextureBinder binder(currentTarget, texture);
0264      prepareProgram(vertexTransform);
0265  
0266 -    Program *program = &programs[targetToProgramIndex(currentTarget)];
0267 +    Program *program = &programs[targetToProgramIndex(currentTarget, colorSpaceConversion)];
0268      program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
0269      program->textureMatrixUniformState = User;
0270  
0271 @@ -307,7 +439,7 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture,
0272      TextureBinder binder(currentTarget, texture);
0273      prepareProgram(vertexTransform);
0274  
0275 -    Program *program = &programs[targetToProgramIndex(currentTarget)];
0276 +    Program *program = &programs[targetToProgramIndex(currentTarget, colorSpaceConversion)];
0277      if (origin == QOpenGLTextureBlitter::OriginTopLeft) {
0278          if (program->textureMatrixUniformState != IdentityFlipped) {
0279              QMatrix3x3 flipped;
0280 @@ -411,6 +543,28 @@ bool QOpenGLTextureBlitter::create()
0281      } else {
0282          if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader, fragment_shader))
0283              return false;
0284 +
0285 +        // TODO: create non-default transformations on-demand
0286 +        {
0287 +            const QString shader = QString("#define SRGB_TO_SCRGB\n %1").arg(fragment_shader);
0288 +            if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D_SRGB_TO_SCRGB, vertex_shader, shader.toLatin1().constData()))
0289 +                return false;
0290 +        }
0291 +        {
0292 +            const QString shader = QString("#define SCRGB_TO_SRGB\n %1").arg(fragment_shader);
0293 +            if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D_SCRGB_TO_SRGB, vertex_shader, shader.toLatin1().constData()))
0294 +                return false;
0295 +        }
0296 +        {
0297 +            const QString shader = QString("#define SRGB_TO_BT2020PQ\n %1").arg(fragment_shader);
0298 +            if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D_SRGB_TO_BT2020PQ, vertex_shader, shader.toLatin1().constData()))
0299 +                return false;
0300 +        }
0301 +        {
0302 +            const QString shader = QString("#define SCRGB_TO_BT2020PQ\n %1").arg(fragment_shader);
0303 +            if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D_SCRGB_TO_BT2020PQ, vertex_shader, shader.toLatin1().constData()))
0304 +                return false;
0305 +        }
0306          if (supportsExternalOESTarget())
0307              if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES, vertex_shader, fragment_shader_external_oes))
0308                  return false;
0309 @@ -458,6 +612,8 @@ void QOpenGLTextureBlitter::destroy()
0310          return;
0311      Q_D(QOpenGLTextureBlitter);
0312      d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.reset();
0313 +    d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D_SRGB_TO_SCRGB].glProgram.reset();
0314 +    d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D_SRGB_TO_BT2020PQ].glProgram.reset();
0315      d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES].glProgram.reset();
0316      d->vertexBuffer.destroy();
0317      d->textureBuffer.destroy();
0318 @@ -487,15 +643,26 @@ bool QOpenGLTextureBlitter::supportsExternalOESTarget() const
0319  
0320      \sa release(), blit()
0321   */
0322 -void QOpenGLTextureBlitter::bind(GLenum target)
0323 +void QOpenGLTextureBlitter::bind(GLenum target,
0324 +                                 QSurfaceFormat::ColorSpace srcColorSpace,
0325 +                                 QSurfaceFormat::ColorSpace dstColorSpace)
0326  {
0327      Q_D(QOpenGLTextureBlitter);
0328  
0329      if (d->vao->isCreated())
0330          d->vao->bind();
0331  
0332 +    const int index = d->calcColorSpaceConversionIndex(srcColorSpace, dstColorSpace);
0333 +
0334 +    if (index >= 0) {
0335 +        d->colorSpaceConversion = index;
0336 +    } else {
0337 +        qWarning() << "QOpenGLTextureBlitter::bind(): color space conversion is not supported" << srcColorSpace << dstColorSpace;
0338 +        d->colorSpaceConversion = 0; // noop conversion
0339 +    }
0340 +
0341      d->currentTarget = target;
0342 -    QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(target)];
0343 +    QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(target, d->colorSpaceConversion)];
0344      p->glProgram->bind();
0345  
0346      d->vertexBuffer.bind();
0347 @@ -509,6 +676,21 @@ void QOpenGLTextureBlitter::bind(GLenum target)
0348      d->textureBuffer.release();
0349  }
0350  
0351 +void QOpenGLTextureBlitter::rebind(GLenum target, QSurfaceFormat::ColorSpace srcColorSpace, QSurfaceFormat::ColorSpace dstColorSpace)
0352 +{
0353 +    Q_D(QOpenGLTextureBlitter);
0354 +
0355 +    if (d->vao->isCreated() &&
0356 +        d->currentTarget == target &&
0357 +        d->colorSpaceConversion == d->calcColorSpaceConversionIndex(srcColorSpace, dstColorSpace)) {
0358 +
0359 +        // the blitter is already configured in the correct state, so just skip it
0360 +        return;
0361 +    }
0362 +
0363 +    bind(target, srcColorSpace, dstColorSpace);
0364 +}
0365 +
0366  /*!
0367      Unbinds the graphics resources used by the blitter.
0368  
0369 @@ -517,7 +699,7 @@ void QOpenGLTextureBlitter::bind(GLenum target)
0370  void QOpenGLTextureBlitter::release()
0371  {
0372      Q_D(QOpenGLTextureBlitter);
0373 -    d->programs[targetToProgramIndex(d->currentTarget)].glProgram->release();
0374 +    d->programs[targetToProgramIndex(d->currentTarget, d->colorSpaceConversion)].glProgram->release();
0375      if (d->vao->isCreated())
0376          d->vao->release();
0377  }
0378 diff --git a/src/gui/opengl/qopengltextureblitter.h b/src/gui/opengl/qopengltextureblitter.h
0379 index 2f7c6b1a0a..3c87e4e2b5 100644
0380 --- a/src/gui/opengl/qopengltextureblitter.h
0381 +++ b/src/gui/opengl/qopengltextureblitter.h
0382 @@ -48,6 +48,9 @@
0383  #include <QtGui/QMatrix3x3>
0384  #include <QtGui/QMatrix4x4>
0385  
0386 +// TODO: less includes!!!
0387 +#include <QSurfaceFormat>
0388 +
0389  QT_BEGIN_NAMESPACE
0390  
0391  class QOpenGLTextureBlitterPrivate;
0392 @@ -69,7 +72,14 @@ public:
0393  
0394      bool supportsExternalOESTarget() const;
0395  
0396 -    void bind(GLenum target = GL_TEXTURE_2D);
0397 +    void bind(GLenum target = GL_TEXTURE_2D,
0398 +              QSurfaceFormat::ColorSpace srcColorSpace = QSurfaceFormat::DefaultColorSpace,
0399 +              QSurfaceFormat::ColorSpace dstColorSpace = QSurfaceFormat::DefaultColorSpace);
0400 +
0401 +    void rebind(GLenum target = GL_TEXTURE_2D,
0402 +                QSurfaceFormat::ColorSpace srcColorSpace = QSurfaceFormat::DefaultColorSpace,
0403 +                QSurfaceFormat::ColorSpace dstColorSpace = QSurfaceFormat::DefaultColorSpace);
0404 +
0405      void release();
0406  
0407      void setRedBlueSwizzle(bool swizzle);
0408 diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
0409 index c71d82546a..8dd96a66bd 100644
0410 --- a/src/gui/painting/qplatformbackingstore.cpp
0411 +++ b/src/gui/painting/qplatformbackingstore.cpp
0412 @@ -132,6 +132,7 @@ struct QBackingstoreTextureInfo
0413      QRect rect;
0414      QRect clipRect;
0415      QPlatformTextureList::Flags flags;
0416 +    QSurfaceFormat::ColorSpace colorSpace;
0417  };
0418  
0419  Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_MOVABLE_TYPE);
0420 @@ -181,6 +182,12 @@ QPlatformTextureList::Flags QPlatformTextureList::flags(int index) const
0421      return d->textures.at(index).flags;
0422  }
0423  
0424 +QSurfaceFormat::ColorSpace QPlatformTextureList::colorSpace(int index) const
0425 +{
0426 +    Q_D(const QPlatformTextureList);
0427 +    return d->textures.at(index).colorSpace;
0428 +}
0429 +
0430  QRect QPlatformTextureList::geometry(int index) const
0431  {
0432      Q_D(const QPlatformTextureList);
0433 @@ -209,7 +216,7 @@ bool QPlatformTextureList::isLocked() const
0434  }
0435  
0436  void QPlatformTextureList::appendTexture(void *source, GLuint textureId, const QRect &geometry,
0437 -                                         const QRect &clipRect, Flags flags)
0438 +                                         const QRect &clipRect, Flags flags, QSurfaceFormat::ColorSpace colorSpace)
0439  {
0440      Q_D(QPlatformTextureList);
0441      QBackingstoreTextureInfo bi;
0442 @@ -218,6 +225,7 @@ void QPlatformTextureList::appendTexture(void *source, GLuint textureId, const Q
0443      bi.rect = geometry;
0444      bi.clipRect = clipRect;
0445      bi.flags = flags;
0446 +    bi.colorSpace = colorSpace;
0447      d->textures.append(bi);
0448  }
0449  
0450 @@ -300,6 +308,7 @@ static void blitTextureForWidget(const QPlatformTextureList *textures, int idx,
0451      if (srgb && canUseSrgb)
0452          funcs->glEnable(GL_FRAMEBUFFER_SRGB);
0453  
0454 +    blitter->rebind(GL_TEXTURE_2D, textures->colorSpace(idx), window->format().colorSpace());
0455      blitter->blit(textures->textureId(idx), target, source);
0456  
0457      if (srgb && canUseSrgb)
0458 @@ -433,6 +442,11 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
0459          funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
0460  
0461      if (textureId) {
0462 +        // GUI texture is always in sRGB color space
0463 +        d_ptr->blitter->rebind(GL_TEXTURE_2D,
0464 +                               QSurfaceFormat::sRGBColorSpace,
0465 +                               window->format().colorSpace());
0466 +
0467          if (d_ptr->needsSwizzle)
0468              d_ptr->blitter->setRedBlueSwizzle(true);
0469          // The backingstore is for the entire tlw.
0470 diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
0471 index de5ba964dc..f8887bd4cd 100644
0472 --- a/src/gui/painting/qplatformbackingstore.h
0473 +++ b/src/gui/painting/qplatformbackingstore.h
0474 @@ -95,11 +95,13 @@ public:
0475      QRect clipRect(int index) const;
0476      void *source(int index);
0477      Flags flags(int index) const;
0478 +    QSurfaceFormat::ColorSpace colorSpace(int index) const;
0479      void lock(bool on);
0480      bool isLocked() const;
0481  
0482      void appendTexture(void *source, GLuint textureId, const QRect &geometry,
0483 -                       const QRect &clipRect = QRect(), Flags flags = 0);
0484 +                       const QRect &clipRect = QRect(), Flags flags = 0,
0485 +                       QSurfaceFormat::ColorSpace colorSpace = QSurfaceFormat::DefaultColorSpace);
0486      void clear();
0487  
0488   Q_SIGNALS:
0489 diff --git a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp
0490 index 40400e2a19..5d44e62455 100644
0491 --- a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp
0492 +++ b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp
0493 @@ -230,7 +230,7 @@ void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegi
0494      m_textures->clear();
0495      for (int i = 0; i < textures->count(); ++i)
0496          m_textures->appendTexture(textures->source(i), textures->textureId(i), textures->geometry(i),
0497 -                                  textures->clipRect(i), textures->flags(i));
0498 +                                  textures->clipRect(i), textures->flags(i), textures->colorSpace(i));
0499  
0500      updateTexture();
0501      m_textures->appendTexture(nullptr, m_bsTexture, window->geometry());
0502 diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp
0503 index e58994b04c..36eae9f9db 100644
0504 --- a/src/widgets/kernel/qopenglwidget.cpp
0505 +++ b/src/widgets/kernel/qopenglwidget.cpp
0506 @@ -568,7 +568,8 @@ public:
0507            updateBehavior(QOpenGLWidget::NoPartialUpdate),
0508            requestedSamples(0),
0509            inPaintGL(false),
0510 -          textureFormat(0)
0511 +          textureFormat(0),
0512 +          textureColorSpace(QSurfaceFormat::DefaultColorSpace)
0513      {
0514          requestedFormat = QSurfaceFormat::defaultFormat();
0515      }
0516 @@ -578,6 +579,7 @@ public:
0517  
0518      GLuint textureId() const override;
0519      QPlatformTextureList::Flags textureListFlags() override;
0520 +    QSurfaceFormat::ColorSpace colorSpace() const override;
0521  
0522      void initialize();
0523      void invokeUserPaint();
0524 @@ -609,6 +611,7 @@ public:
0525      int requestedSamples;
0526      bool inPaintGL;
0527      GLenum textureFormat;
0528 +    QSurfaceFormat::ColorSpace textureColorSpace;
0529  };
0530  
0531  void QOpenGLWidgetPaintDevicePrivate::beginPaint()
0532 @@ -695,6 +698,11 @@ QPlatformTextureList::Flags QOpenGLWidgetPrivate::textureListFlags()
0533      return flags;
0534  }
0535  
0536 +QSurfaceFormat::ColorSpace QOpenGLWidgetPrivate::colorSpace() const
0537 +{
0538 +    return textureColorSpace;
0539 +}
0540 +
0541  void QOpenGLWidgetPrivate::reset()
0542  {
0543      Q_Q(QOpenGLWidget);
0544 @@ -1117,6 +1125,41 @@ void QOpenGLWidget::setTextureFormat(GLenum texFormat)
0545      d->textureFormat = texFormat;
0546  }
0547  
0548 +/*!
0549 +    \return the declared color space of the internal texture of the widget.
0550 +
0551 +    The texture's color space will be used when composing the widget
0552 +    into the root window surface.
0553 +
0554 +    \note when the color space is set to QSurfaceFormat::DefaultColorSpace,
0555 +    color conversion is effectively disabled.
0556 +
0557 +    \since 5.99
0558 + */
0559 +QSurfaceFormat::ColorSpace QOpenGLWidget::textureColorSpace() const
0560 +{
0561 +    Q_D(const QOpenGLWidget);
0562 +    return d->textureColorSpace;
0563 +}
0564 +
0565 +/*!
0566 +    Sets a custom color space for the internal texture of the widget
0567 +
0568 +    The color space of the texture will be compared against the color
0569 +    space of the root surface and conversion will be performed if needed.
0570 +
0571 +    \note setting the color space to QSurfaceFormat::DefaultColorSpace will
0572 +    effectively disable color conversion when composing this texture on
0573 +    screen.
0574 +
0575 +    \since 5.99
0576 + */
0577 +void QOpenGLWidget::setTextureColorSpace(QSurfaceFormat::ColorSpace colorSpace)
0578 +{
0579 +    Q_D(QOpenGLWidget);
0580 +    d->textureColorSpace = colorSpace;
0581 +}
0582 +
0583  /*!
0584      \return the active internal texture format if the widget has already
0585      initialized, the requested format if one was set but the widget has not yet
0586 diff --git a/src/widgets/kernel/qopenglwidget.h b/src/widgets/kernel/qopenglwidget.h
0587 index 9eb4a9ba5a..eff2d9796d 100644
0588 --- a/src/widgets/kernel/qopenglwidget.h
0589 +++ b/src/widgets/kernel/qopenglwidget.h
0590 @@ -75,6 +75,9 @@ public:
0591      GLenum textureFormat() const;
0592      void setTextureFormat(GLenum texFormat);
0593  
0594 +    QSurfaceFormat::ColorSpace textureColorSpace() const;
0595 +    void setTextureColorSpace(QSurfaceFormat::ColorSpace colorSpace);
0596 +
0597      bool isValid() const;
0598  
0599      void makeCurrent();
0600 diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h
0601 index 142d5ef9bb..e541cb70e4 100644
0602 --- a/src/widgets/kernel/qwidget_p.h
0603 +++ b/src/widgets/kernel/qwidget_p.h
0604 @@ -657,6 +657,7 @@ public:
0605              ? QPlatformTextureList::StacksOnTop
0606              : QPlatformTextureList::Flags(0);
0607      }
0608 +    virtual QSurfaceFormat::ColorSpace colorSpace() const { return QSurfaceFormat::DefaultColorSpace; }
0609      virtual QImage grabFramebuffer() { return QImage(); }
0610      virtual void beginBackingStorePainting() { }
0611      virtual void endBackingStorePainting() { }
0612 diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp
0613 index 38ea5966ae..d5b613a4e5 100644
0614 --- a/src/widgets/kernel/qwidgetbackingstore.cpp
0615 +++ b/src/widgets/kernel/qwidgetbackingstore.cpp
0616 @@ -1011,7 +1011,7 @@ static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatfo
0617      if (wd->renderToTexture) {
0618          QPlatformTextureList::Flags flags = wd->textureListFlags();
0619          const QRect rect(widget->mapTo(tlw, QPoint()), widget->size());
0620 -        widgetTextures->appendTexture(widget, wd->textureId(), rect, wd->clipRect(), flags);
0621 +        widgetTextures->appendTexture(widget, wd->textureId(), rect, wd->clipRect(), flags, wd->colorSpace());
0622      }
0623  
0624      for (int i = 0; i < wd->children.size(); ++i) {
0625 -- 
0626 2.20.1.windows.1
0627