From 72dd23cf53e910a0e34e71c9a7bf94f92c91fd7d Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 2 Sep 2022 14:11:18 +0200 Subject: [PATCH] Defer creating the special shaders in the texture blitter Port of the 5.15 change. It is not strictly required for Qt 6 since the immediate problem of failing to compile some of the shaders with some drivers will pop up much more rarely in practice, because neither Multimedia nor the backing store compositor for QOpenGLWidget/QQuickWidget use QOpenGLTextureBlitter in 6.4 and newer. To maintain the internal behavior between 5 and 6, the patch is nonetheless ported to Qt 6. It also has a performance benefit for the users of the blitter, because now the special shader variants (for rectangle or external textures) are only created when needed. Task-number: QTBUG-101396 Change-Id: I1cf4bec0c74045f4b6f94765563254026bf0b7d8 Reviewed-by: Qt CI Bot Reviewed-by: Andy Nichols --- src/opengl/qopengltextureblitter.cpp | 75 +++++++++++++++++++++------- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/src/opengl/qopengltextureblitter.cpp b/src/opengl/qopengltextureblitter.cpp index 664aa5e11b9..2b43afc3b6b 100644 --- a/src/opengl/qopengltextureblitter.cpp +++ b/src/opengl/qopengltextureblitter.cpp @@ -200,7 +200,8 @@ public: TEXTURE_RECTANGLE }; - QOpenGLTextureBlitterPrivate() : + QOpenGLTextureBlitterPrivate(QOpenGLTextureBlitter *q_ptr) : + q(q_ptr), swizzle(false), opacity(1.0f), vao(new QOpenGLVertexArrayObject), @@ -208,14 +209,16 @@ public: { } bool buildProgram(ProgramIndex idx, const char *vs, const char *fs); + bool ensureProgram(ProgramIndex idx); void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform); void blit(GLuint texture, const QMatrix4x4 &targetTransform, QOpenGLTextureBlitter::Origin origin); QMatrix3x3 toTextureCoordinates(const QMatrix3x3 &sourceTransform) const; - void prepareProgram(const QMatrix4x4 &vertexTransform); + bool prepareProgram(const QMatrix4x4 &vertexTransform); + QOpenGLTextureBlitter *q; QOpenGLBuffer vertexBuffer; QOpenGLBuffer textureBuffer; struct Program { @@ -262,9 +265,13 @@ static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GL } } -void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform) +bool QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform) { - Program *program = &programs[targetToProgramIndex(currentTarget)]; + ProgramIndex programIndex = targetToProgramIndex(currentTarget); + if (!ensureProgram(programIndex)) + return false; + + Program *program = &programs[programIndex]; vertexBuffer.bind(); program->glProgram->setAttributeBuffer(program->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); @@ -287,6 +294,8 @@ void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransf program->glProgram->setUniformValue(program->opacityUniformPos, opacity); program->opacity = opacity; } + + return true; } QMatrix3x3 QOpenGLTextureBlitterPrivate::toTextureCoordinates(const QMatrix3x3 &sourceTransform) const @@ -311,7 +320,8 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture, const QMatrix3x3 &sourceTransform) { TextureBinder binder(currentTarget, texture); - prepareProgram(targetTransform); + if (!prepareProgram(targetTransform)) + return; Program *program = &programs[targetToProgramIndex(currentTarget)]; @@ -327,7 +337,8 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture, QOpenGLTextureBlitter::Origin origin) { TextureBinder binder(currentTarget, texture); - prepareProgram(targetTransform); + if (!prepareProgram(targetTransform)) + return; Program *program = &programs[targetToProgramIndex(currentTarget)]; @@ -380,6 +391,35 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs return true; } +bool QOpenGLTextureBlitterPrivate::ensureProgram(ProgramIndex idx) +{ + if (programs[idx].glProgram) + return true; + + QOpenGLContext *currentContext = QOpenGLContext::currentContext(); + if (!currentContext) + return false; + + QSurfaceFormat format = currentContext->format(); + if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) { + if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE && q->supportsRectangleTarget()) { + if (!buildProgram(idx, vertex_shader150, fragment_shader150_rectangle)) + return false; + } + } else { + if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE && q->supportsRectangleTarget()) { + if (!buildProgram(idx, vertex_shader, fragment_shader_rectangle)) + return false; + } + if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES && q->supportsExternalOESTarget()) { + if (!buildProgram(idx, vertex_shader, fragment_shader_external_oes)) + return false; + } + } + + return !programs[idx].glProgram.isNull(); +} + /*! Constructs a new QOpenGLTextureBlitter instance. @@ -390,7 +430,7 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs create(). */ QOpenGLTextureBlitter::QOpenGLTextureBlitter() - : d_ptr(new QOpenGLTextureBlitterPrivate) + : d_ptr(new QOpenGLTextureBlitterPrivate(this)) { } @@ -430,21 +470,14 @@ bool QOpenGLTextureBlitter::create() return true; QSurfaceFormat format = currentContext->format(); + // Build the most common, 2D texture shader variant. + // The other special ones are deferred and compiled only when first needed. if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) { if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader150, fragment_shader150)) return false; - if (supportsRectangleTarget()) - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE, vertex_shader150, fragment_shader150_rectangle)) - return false; } else { if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader, fragment_shader)) return false; - if (supportsExternalOESTarget()) - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES, vertex_shader, fragment_shader_external_oes)) - return false; - if (supportsRectangleTarget()) - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE, vertex_shader, fragment_shader_rectangle)) - return false; } // Create and bind the VAO, if supported. @@ -553,7 +586,11 @@ void QOpenGLTextureBlitter::bind(GLenum target) d->vao->bind(); d->currentTarget = target; - QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(target)]; + QOpenGLTextureBlitterPrivate::ProgramIndex programIndex = targetToProgramIndex(target); + if (!d->ensureProgram(programIndex)) + return; + + QOpenGLTextureBlitterPrivate::Program *p = &d->programs[programIndex]; p->glProgram->bind(); d->vertexBuffer.bind(); @@ -575,7 +612,9 @@ void QOpenGLTextureBlitter::bind(GLenum target) void QOpenGLTextureBlitter::release() { Q_D(QOpenGLTextureBlitter); - d->programs[targetToProgramIndex(d->currentTarget)].glProgram->release(); + QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(d->currentTarget)]; + if (p->glProgram) + p->glProgram->release(); if (d->vao->isCreated()) d->vao->release(); }