diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2022-09-02 10:07:50 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2022-09-14 10:23:22 +0200 |
commit | 5fb20a61c9895c911f95824e68180fa448894180 (patch) | |
tree | c4e0d89a60c9af13f12b416f319c6c2ecafe71e6 /src/gui/opengl | |
parent | 3dbe047ec3974c580d0d2a28b52d940c6c5964de (diff) |
Defer creating the special shaders in the texture blitter
Won't apply as-is to Qt 6, needs a dedicated patch there. The urgency is
different there as well, from 6.4 on the blitter is not used at all in
the backingstore compositor, so the fact that preparing some of the
special shaders fail with some Intel drivers does not matter and
won't break applications using QOpenGLWidget or QQuickWidget.
Instead of introducing platform specific ifdefs (e.g. only supporting
texture rectangles on macOS, which is where it really is used), defer
the compilation of the more exotic shader variants.
Deferring the compilation of the potentially problematic
shaders to a point where they are actually needed has the benefit
of not affecting applications that never need those shaders to
begin with, i.e. even if the shader would fail to compile it won't
be a problem as the shader is never needed in the first place. In
addition, this provides a performance improvement to create() because
it now only compiles the commonly used shader, not the other two.
This way, even if the sampler2DRect-based shader failed
to compile, that would not be a problem for an application using
a QOpenGLWidget (and so using the blitter internally), because
that particular shader is not needed at all for rendering.
What exactly fails with certain older (but not that old) Intel
drivers, and what "syntax error syntax error" really means remain
a mystery, and likely not something we will solve.
Fixes: QTBUG-101396
Change-Id: Ic923d51007af503f2749eaae36297ca6647cfa09
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/gui/opengl')
-rw-r--r-- | src/gui/opengl/qopengltextureblitter.cpp | 76 |
1 files changed, 58 insertions, 18 deletions
diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp index f2816712b7..7ed56fe571 100644 --- a/src/gui/opengl/qopengltextureblitter.cpp +++ b/src/gui/opengl/qopengltextureblitter.cpp @@ -236,7 +236,8 @@ public: TEXTURE_RECTANGLE }; - QOpenGLTextureBlitterPrivate() : + QOpenGLTextureBlitterPrivate(QOpenGLTextureBlitter *q_ptr) : + q(q_ptr), swizzle(false), opacity(1.0f), vao(new QOpenGLVertexArrayObject), @@ -244,16 +245,18 @@ 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); bool supportsRectangleTarget() const; + QOpenGLTextureBlitter *q; QOpenGLBuffer vertexBuffer; QOpenGLBuffer textureBuffer; struct Program { @@ -300,9 +303,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); @@ -325,6 +332,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 @@ -349,7 +358,8 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture, const QMatrix3x3 &sourceTransform) { TextureBinder binder(currentTarget, texture); - prepareProgram(targetTransform); + if (!prepareProgram(targetTransform)) + return; Program *program = &programs[targetToProgramIndex(currentTarget)]; @@ -365,7 +375,8 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture, QOpenGLTextureBlitter::Origin origin) { TextureBinder binder(currentTarget, texture); - prepareProgram(targetTransform); + if (!prepareProgram(targetTransform)) + return; Program *program = &programs[targetToProgramIndex(currentTarget)]; @@ -398,6 +409,7 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs p->glProgram->link(); if (!p->glProgram->isLinked()) { qWarning() << "Could not link shader program:\n" << p->glProgram->log(); + p->glProgram.reset(); return false; } @@ -418,6 +430,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 && supportsRectangleTarget()) { + if (!buildProgram(idx, vertex_shader150, fragment_shader150_rectangle)) + return false; + } + } else { + if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE && 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; +} + /*! Constructs a new QOpenGLTextureBlitter instance. @@ -428,7 +469,7 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs create(). */ QOpenGLTextureBlitter::QOpenGLTextureBlitter() - : d_ptr(new QOpenGLTextureBlitterPrivate) + : d_ptr(new QOpenGLTextureBlitterPrivate(this)) { } @@ -468,21 +509,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 (d->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 (d->supportsRectangleTarget()) - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE, vertex_shader, fragment_shader_rectangle)) - return false; } // Create and bind the VAO, if supported. @@ -591,7 +625,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(); @@ -613,7 +651,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(); } |