Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qopengltextureblitter.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtOpenGL/QOpenGLShaderProgram>
7#include <QtOpenGL/QOpenGLVertexArrayObject>
8#include <QtOpenGL/QOpenGLBuffer>
9#include <QtGui/QOpenGLContext>
10#include <QtGui/QOpenGLFunctions>
11#include <QtGui/QOpenGLExtraFunctions>
12
13#ifndef GL_TEXTURE_EXTERNAL_OES
14#define GL_TEXTURE_EXTERNAL_OES 0x8D65
15#endif
16#ifndef GL_TEXTURE_RECTANGLE
17#define GL_TEXTURE_RECTANGLE 0x84F5
18#endif
19#ifndef GL_TEXTURE_WIDTH
20#define GL_TEXTURE_WIDTH 0x1000
21#endif
22#ifndef GL_TEXTURE_HEIGHT
23#define GL_TEXTURE_HEIGHT 0x1001
24#endif
25
27
71static const char vertex_shader150[] =
72 "#version 150 core\n"
73 "in vec3 vertexCoord;"
74 "in vec2 textureCoord;"
75 "out vec2 uv;"
76 "uniform mat4 vertexTransform;"
77 "uniform mat3 textureTransform;"
78 "void main() {"
79 " uv = (textureTransform * vec3(textureCoord,1.0)).xy;"
80 " gl_Position = vertexTransform * vec4(vertexCoord,1.0);"
81 "}";
82
83static const char fragment_shader150[] =
84 "#version 150 core\n"
85 "in vec2 uv;"
86 "out vec4 fragcolor;"
87 "uniform sampler2D textureSampler;"
88 "uniform bool swizzle;"
89 "uniform float opacity;"
90 "void main() {"
91 " vec4 tmpFragColor = texture(textureSampler, uv);"
92 " tmpFragColor.a *= opacity;"
93 " fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
94 "}";
95
96static const char vertex_shader[] =
97 "attribute highp vec3 vertexCoord;"
98 "attribute highp vec2 textureCoord;"
99 "varying highp vec2 uv;"
100 "uniform highp mat4 vertexTransform;"
101 "uniform highp mat3 textureTransform;"
102 "void main() {"
103 " uv = (textureTransform * vec3(textureCoord,1.0)).xy;"
104 " gl_Position = vertexTransform * vec4(vertexCoord,1.0);"
105 "}";
106
107static const char fragment_shader[] =
108 "varying highp vec2 uv;"
109 "uniform sampler2D textureSampler;"
110 "uniform bool swizzle;"
111 "uniform highp float opacity;"
112 "void main() {"
113 " highp vec4 tmpFragColor = texture2D(textureSampler,uv);"
114 " tmpFragColor.a *= opacity;"
115 " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
116 "}";
117
118static const char fragment_shader_external_oes[] =
119 "#extension GL_OES_EGL_image_external : require\n"
120 "varying highp vec2 uv;"
121 "uniform samplerExternalOES textureSampler;\n"
122 "uniform bool swizzle;"
123 "uniform highp float opacity;"
124 "void main() {"
125 " highp vec4 tmpFragColor = texture2D(textureSampler, uv);"
126 " tmpFragColor.a *= opacity;"
127 " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
128 "}";
129
130static const char fragment_shader_rectangle[] =
131 "varying highp vec2 uv;"
132 "uniform sampler2DRect textureSampler;"
133 "uniform bool swizzle;"
134 "uniform highp float opacity;"
135 "void main() {"
136 " highp vec4 tmpFragColor = texture2DRect(textureSampler,uv);"
137 " tmpFragColor.a *= opacity;"
138 " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
139 "}";
140
141static const char fragment_shader150_rectangle[] =
142 "#version 150 core\n"
143 "in vec2 uv;"
144 "out vec4 fragcolor;"
145 "uniform sampler2DRect textureSampler;"
146 "uniform bool swizzle;"
147 "uniform float opacity;"
148 "void main() {"
149 " vec4 tmpFragColor = texture(textureSampler, uv);"
150 " tmpFragColor.a *= opacity;"
151 " fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
152 "}";
153
154static const GLfloat vertex_buffer_data[] = {
155 -1,-1, 0,
156 -1, 1, 0,
157 1,-1, 0,
158 -1, 1, 0,
159 1,-1, 0,
160 1, 1, 0
161};
162
163static const GLfloat texture_buffer_data[] = {
164 0, 0,
165 0, 1,
166 1, 0,
167 0, 1,
168 1, 0,
169 1, 1
170};
171
173{
174public:
175 explicit QBlitterTextureBinder(GLenum target, GLuint textureId) : m_target(target)
176 {
177 QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, textureId);
178 }
180 {
181 QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, 0);
182 }
183
184private:
185 GLenum m_target;
186};
187
189{
190public:
196
202
210
211 bool buildProgram(ProgramIndex idx, const char *vs, const char *fs);
212 bool ensureProgram(ProgramIndex idx);
213
216
218
219 bool prepareProgram(const QMatrix4x4 &vertexTransform);
220
248 float opacity;
249 QScopedPointer<QOpenGLVertexArrayObject> vao;
251};
252
267
269{
271 if (!ensureProgram(programIndex))
272 return false;
273
274 Program *program = &programs[programIndex];
275
277 program->glProgram->setAttributeBuffer(program->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0);
278 program->glProgram->enableAttributeArray(program->vertexCoordAttribPos);
280
281 program->glProgram->setUniformValue(program->vertexTransformUniformPos, vertexTransform);
282
284 program->glProgram->setAttributeBuffer(program->textureCoordAttribPos, GL_FLOAT, 0, 2, 0);
285 program->glProgram->enableAttributeArray(program->textureCoordAttribPos);
287
288 if (swizzle != program->swizzle) {
289 program->glProgram->setUniformValue(program->swizzleUniformPos, swizzle);
290 program->swizzle = swizzle;
291 }
292
293 if (opacity != program->opacity) {
294 program->glProgram->setUniformValue(program->opacityUniformPos, opacity);
295 program->opacity = opacity;
296 }
297
298 return true;
299}
300
302{
304 // Non-normalized coordinates
305 QMatrix4x4 textureTransform(sourceTransform);
306 if (auto *glFunctions = QOpenGLContext::currentContext()->extraFunctions()) {
307 int width, height;
308 glFunctions->glGetTexLevelParameteriv(currentTarget, 0, GL_TEXTURE_WIDTH, &width);
309 glFunctions->glGetTexLevelParameteriv(currentTarget, 0, GL_TEXTURE_HEIGHT, &height);
310 textureTransform.scale(width, height);
311 }
312 return textureTransform.toGenericMatrix<3, 3>();
313 }
314
315 return sourceTransform; // Normalized coordinates
316}
317
321{
324 return;
325
327
328 const QMatrix3x3 textureTransform = toTextureCoordinates(sourceTransform);
329 program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
330 program->textureMatrixUniformState = User;
331
332 QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6);
333}
334
338{
341 return;
342
344
346 if (program->textureMatrixUniformState != IdentityFlipped) {
348 sourceTransform(1,1) = -1;
349 sourceTransform(1,2) = 1;
350 const QMatrix3x3 textureTransform = toTextureCoordinates(sourceTransform);
351 program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
352 program->textureMatrixUniformState = IdentityFlipped;
353 }
354 } else if (program->textureMatrixUniformState != Identity) {
355 const QMatrix3x3 textureTransform = toTextureCoordinates(QMatrix3x3());
356 program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
357 program->textureMatrixUniformState = Identity;
358 }
359
360 QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6);
361}
362
363bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs, const char *fs)
364{
365 Program *p = &programs[idx];
366
368
369 p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vs);
370 p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fs);
371 p->glProgram->link();
372 if (!p->glProgram->isLinked()) {
373 qWarning() << "Could not link shader program:\n" << p->glProgram->log();
374 return false;
375 }
376
377 p->glProgram->bind();
378
379 p->vertexCoordAttribPos = p->glProgram->attributeLocation("vertexCoord");
380 p->vertexTransformUniformPos = p->glProgram->uniformLocation("vertexTransform");
381 p->textureCoordAttribPos = p->glProgram->attributeLocation("textureCoord");
382 p->textureTransformUniformPos = p->glProgram->uniformLocation("textureTransform");
383 p->swizzleUniformPos = p->glProgram->uniformLocation("swizzle");
384 p->opacityUniformPos = p->glProgram->uniformLocation("opacity");
385
386 p->glProgram->setUniformValue(p->swizzleUniformPos, false);
387
388 // minmize state left set after a create()
389 p->glProgram->release();
390
391 return true;
392}
393
395{
396 if (programs[idx].glProgram)
397 return true;
398
400 if (!currentContext)
401 return false;
402
403 QSurfaceFormat format = currentContext->format();
404 if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) {
405 if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE && q->supportsRectangleTarget()) {
407 return false;
408 }
409 } else {
410 if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE && q->supportsRectangleTarget()) {
412 return false;
413 }
414 if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES && q->supportsExternalOESTarget()) {
416 return false;
417 }
418 }
419
420 return !programs[idx].glProgram.isNull();
421}
422
436
450
462{
464 if (!currentContext)
465 return false;
466
468
469 if (d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram)
470 return true;
471
472 QSurfaceFormat format = currentContext->format();
473 // Build the most common, 2D texture shader variant.
474 // The other special ones are deferred and compiled only when first needed.
475 if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) {
477 return false;
478 } else {
480 return false;
481 }
482
483 // Create and bind the VAO, if supported.
484 QOpenGLVertexArrayObject::Binder vaoBinder(d->vao.data());
485
486 d->vertexBuffer.create();
487 d->vertexBuffer.bind();
488 d->vertexBuffer.allocate(vertex_buffer_data, sizeof(vertex_buffer_data));
489 d->vertexBuffer.release();
490
491 d->textureBuffer.create();
492 d->textureBuffer.bind();
493 d->textureBuffer.allocate(texture_buffer_data, sizeof(texture_buffer_data));
494 d->textureBuffer.release();
495
496 return true;
497}
498
505{
506 Q_D(const QOpenGLTextureBlitter);
507 return !d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.isNull();
508}
509
520{
521 if (!isCreated())
522 return;
524 d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.reset();
525 d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES].glProgram.reset();
526 d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE].glProgram.reset();
527 d->vertexBuffer.destroy();
528 d->textureBuffer.destroy();
529 d->vao.reset();
530}
531
539{
541 return ctx && ctx->isOpenGLES() && ctx->hasExtension("GL_OES_EGL_image_external");
542}
543
551{
553 if (!ctx || ctx->isOpenGLES())
554 return false;
555
556 if (ctx->hasExtension("GL_ARB_texture_rectangle"))
557 return true;
558
559 if (ctx->hasExtension("GL_EXT_texture_rectangle"))
560 return true;
561
562 QSurfaceFormat f = ctx->format();
563 const auto version = qMakePair(f.majorVersion(), f.minorVersion());
564 if (version >= qMakePair(3, 1))
565 return true;
566
567 return false;
568}
569
582{
584
585 if (d->vao->isCreated())
586 d->vao->bind();
587
588 d->currentTarget = target;
590 if (!d->ensureProgram(programIndex))
591 return;
592
593 QOpenGLTextureBlitterPrivate::Program *p = &d->programs[programIndex];
594 p->glProgram->bind();
595
596 d->vertexBuffer.bind();
597 p->glProgram->setAttributeBuffer(p->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0);
598 p->glProgram->enableAttributeArray(p->vertexCoordAttribPos);
599 d->vertexBuffer.release();
600
601 d->textureBuffer.bind();
602 p->glProgram->setAttributeBuffer(p->textureCoordAttribPos, GL_FLOAT, 0, 2, 0);
603 p->glProgram->enableAttributeArray(p->textureCoordAttribPos);
604 d->textureBuffer.release();
605}
606
613{
615 QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(d->currentTarget)];
616 if (p->glProgram)
617 p->glProgram->release();
618 if (d->vao->isCreated())
619 d->vao->release();
620}
621
639
648{
650 d->opacity = opacity;
651}
652
683 Origin sourceOrigin)
684{
686 d->blit(texture, targetTransform, sourceOrigin);
687}
688
709
723 const QRect &viewport)
724{
725 qreal x_scale = target.width() / viewport.width();
726 qreal y_scale = target.height() / viewport.height();
727
728 const QPointF relative_to_viewport = target.topLeft() - viewport.topLeft();
729 qreal x_translate = x_scale - 1 + ((relative_to_viewport.x() / viewport.width()) * 2);
730 qreal y_translate = -y_scale + 1 - ((relative_to_viewport.y() / viewport.height()) * 2);
731
733 matrix(0,3) = x_translate;
734 matrix(1,3) = y_translate;
735
736 matrix(0,0) = x_scale;
737 matrix(1,1) = y_scale;
738
739 return matrix;
740}
741
754 const QSize &textureSize,
755 Origin origin)
756{
757 qreal x_scale = subTexture.width() / textureSize.width();
758 qreal y_scale = subTexture.height() / textureSize.height();
759
760 const QPointF topLeft = subTexture.topLeft();
761 qreal x_translate = topLeft.x() / textureSize.width();
762 qreal y_translate = topLeft.y() / textureSize.height();
763
764 if (origin == OriginTopLeft) {
765 y_scale = -y_scale;
766 y_translate = 1 - y_translate;
767 }
768
770 matrix(0,2) = x_translate;
771 matrix(1,2) = y_translate;
772
773 matrix(0,0) = x_scale;
774 matrix(1,1) = y_scale;
775
776 return matrix;
777}
778
QBlitterTextureBinder(GLenum target, GLuint textureId)
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
The QOpenGLBuffer class provides functions for creating and managing OpenGL buffer objects.
bool bind()
Binds the buffer associated with this object to the current OpenGL context.
void release()
Releases the buffer associated with this object from the current OpenGL context.
\inmodule QtGui
QSurfaceFormat format() const
Returns the format of the underlying platform context, if create() has been called.
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
The QOpenGLShaderProgram class allows OpenGL shader programs to be linked and used.
void release()
Releases the active shader program from the current QOpenGLContext.
bool bind()
Binds this shader program to the active QOpenGLContext and makes it the current shader program.
QMatrix3x3 toTextureCoordinates(const QMatrix3x3 &sourceTransform) const
QScopedPointer< QOpenGLVertexArrayObject > vao
QOpenGLTextureBlitterPrivate(QOpenGLTextureBlitter *q_ptr)
bool buildProgram(ProgramIndex idx, const char *vs, const char *fs)
void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform)
bool prepareProgram(const QMatrix4x4 &vertexTransform)
The QOpenGLTextureBlitter class provides a convenient way to draw textured quads via OpenGL.
bool create()
Initializes the graphics resources used by the blitter.
void destroy()
Frees all graphics resources held by the blitter.
Origin
\value OriginBottomLeft Indicates that the data in the texture follows the OpenGL convention of coord...
QOpenGLTextureBlitter()
Constructs a new QOpenGLTextureBlitter instance.
void setOpacity(float opacity)
Changes the opacity to opacity.
void blit(GLuint texture, const QMatrix4x4 &targetTransform, Origin sourceOrigin)
Performs the blit with the source texture texture.
~QOpenGLTextureBlitter()
Destructs the instance.
void setRedBlueSwizzle(bool swizzle)
Sets whether swizzling is enabled for the red and blue color channels to swizzle.
static QMatrix3x3 sourceTransform(const QRectF &subTexture, const QSize &textureSize, Origin origin)
Calculates a 3x3 matrix suitable as the input to blit().
void release()
Unbinds the graphics resources used by the blitter.
static QMatrix4x4 targetTransform(const QRectF &target, const QRect &viewport)
Calculates a target transform suitable for blit().
void bind(GLenum target=GL_TEXTURE_2D)
Binds the graphics resources used by the blitter.
The QOpenGLVertexArrayObject::Binder class is a convenience class to help with the binding and releas...
The QOpenGLVertexArrayObject class wraps an OpenGL Vertex Array Object.
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
EGLContext ctx
#define this
Definition dialogs.cpp:9
Combined button and popup list for selecting options.
static QMatrix4x4 targetTransform(const QRectF &target, const QRect &viewport, bool invertY)
static QMatrix3x3 sourceTransform(const QRectF &subTexture, const QSize &textureSize, SourceTransformOrigin origin)
QGenericMatrix< 3, 3, float > QMatrix3x3
#define qWarning
Definition qlogging.h:166
typedef GLfloat(GL_APIENTRYP PFNGLGETPATHLENGTHNVPROC)(GLuint path
GLint GLsizei GLsizei height
GLfloat GLfloat f
GLint GLsizei width
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLenum target
GLenum GLuint texture
GLuint program
GLint GLsizei GLsizei GLenum format
GLuint GLenum swizzle
const GLuint * programs
GLuint GLenum matrix
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
#define GL_TEXTURE_WIDTH
static const char fragment_shader_external_oes[]
#define GL_TEXTURE_HEIGHT
static const char vertex_shader[]
static const GLfloat vertex_buffer_data[]
#define GL_TEXTURE_RECTANGLE
static const char fragment_shader150[]
static const char fragment_shader_rectangle[]
static const char vertex_shader150[]
static const char fragment_shader[]
#define GL_TEXTURE_EXTERNAL_OES
static const char fragment_shader150_rectangle[]
static QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GLenum target)
static const GLfloat texture_buffer_data[]
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
#define GLuint
#define GL_FLOAT
double qreal
Definition qtypes.h:187
view viewport() -> scroll(dx, dy, deviceRect)
QScopedPointer< QOpenGLShaderProgram > glProgram