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 ®i 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