summaryrefslogtreecommitdiffstats
path: root/src/gui/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/opengl')
-rw-r--r--src/gui/opengl/opengl.pri2
-rw-r--r--src/gui/opengl/qopengl.h2
-rw-r--r--src/gui/opengl/qopenglbuffer.cpp24
-rw-r--r--src/gui/opengl/qopengldebug.cpp67
-rw-r--r--src/gui/opengl/qopenglengineshadermanager.cpp75
-rw-r--r--src/gui/opengl/qopenglengineshadermanager_p.h4
-rw-r--r--src/gui/opengl/qopenglengineshadersource_p.h173
-rw-r--r--src/gui/opengl/qopenglextensions_p.h3
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp86
-rw-r--r--src/gui/opengl/qopenglfunctions.cpp106
-rw-r--r--src/gui/opengl/qopenglfunctions.h3
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp102
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache.cpp27
-rw-r--r--src/gui/opengl/qopenglshaderprogram.cpp88
-rw-r--r--src/gui/opengl/qopengltexturecache.cpp199
-rw-r--r--src/gui/opengl/qopengltexturecache_p.h24
-rw-r--r--src/gui/opengl/qopengltextureglyphcache.cpp10
-rw-r--r--src/gui/opengl/qopengltextureuploader.cpp328
-rw-r--r--src/gui/opengl/qopengltextureuploader_p.h84
19 files changed, 839 insertions, 568 deletions
diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri
index 4c778b184e..24758afdeb 100644
--- a/src/gui/opengl/opengl.pri
+++ b/src/gui/opengl/opengl.pri
@@ -32,6 +32,7 @@ qtConfig(opengl) {
opengl/qopengltexture.h \
opengl/qopengltexture_p.h \
opengl/qopengltexturehelper_p.h \
+ opengl/qopengltextureuploader_p.h \
opengl/qopenglpixeltransferoptions.h \
opengl/qopenglextrafunctions.h \
opengl/qopenglprogrambinarycache_p.h
@@ -56,6 +57,7 @@ qtConfig(opengl) {
opengl/qopengltextureblitter.cpp \
opengl/qopengltexture.cpp \
opengl/qopengltexturehelper.cpp \
+ opengl/qopengltextureuploader.cpp \
opengl/qopenglpixeltransferoptions.cpp \
opengl/qopenglprogrambinarycache.cpp
diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h
index b4657fa118..3a2393ea58 100644
--- a/src/gui/opengl/qopengl.h
+++ b/src/gui/opengl/qopengl.h
@@ -239,7 +239,7 @@ typedef unsigned long long int uint64_t;
typedef long int int32_t;
typedef long long int int64_t;
typedef unsigned long long int uint64_t;
-#elif defined(_WIN32) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1600))
+#elif defined(_WIN32) && (defined(__GNUC__) || defined(_MSC_VER))
#include <stdint.h>
#elif defined(_WIN32)
typedef __int32 int32_t;
diff --git a/src/gui/opengl/qopenglbuffer.cpp b/src/gui/opengl/qopenglbuffer.cpp
index 69c2baa8d9..537097c09f 100644
--- a/src/gui/opengl/qopenglbuffer.cpp
+++ b/src/gui/opengl/qopenglbuffer.cpp
@@ -43,6 +43,10 @@
#include "qopenglbuffer.h"
#include <private/qopenglextensions_p.h>
+#ifndef GL_CONTEXT_LOST
+#define GL_CONTEXT_LOST 0x0507
+#endif
+
QT_BEGIN_NAMESPACE
/*!
@@ -59,12 +63,7 @@ QT_BEGIN_NAMESPACE
QOpenGLBuffer objects can be copied around as a reference to the
underlying OpenGL buffer object:
- \code
- QOpenGLBuffer buffer1(QOpenGLBuffer::IndexBuffer);
- buffer1.create();
-
- QOpenGLBuffer buffer2 = buffer1;
- \endcode
+ \snippet code/src_gui_opengl_qopenglbuffer.cpp 0
QOpenGLBuffer performs a shallow copy when objects are copied in this
manner, but does not implement copy-on-write semantics. The original
@@ -346,7 +345,14 @@ bool QOpenGLBuffer::read(int offset, void *data, int count)
Q_D(QOpenGLBuffer);
if (!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id())
return false;
- while (d->funcs->glGetError() != GL_NO_ERROR) ; // Clear error state.
+
+ while (true) { // Clear error state.
+ GLenum error = d->funcs->glGetError();
+ if (error == GL_NO_ERROR)
+ break;
+ if (error == GL_CONTEXT_LOST)
+ return false;
+ };
d->funcs->glGetBufferSubData(d->type, offset, count, data);
return d->funcs->glGetError() == GL_NO_ERROR;
#else
@@ -473,9 +479,7 @@ void QOpenGLBuffer::release()
been bound to the context but wants to make sure that it
is released.
- \code
- QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
- \endcode
+ \snippet code/src_gui_opengl_qopenglbuffer.cpp 1
*/
void QOpenGLBuffer::release(QOpenGLBuffer::Type type)
{
diff --git a/src/gui/opengl/qopengldebug.cpp b/src/gui/opengl/qopengldebug.cpp
index f6c3af37dd..2e628a2bd5 100644
--- a/src/gui/opengl/qopengldebug.cpp
+++ b/src/gui/opengl/qopengldebug.cpp
@@ -89,16 +89,11 @@ QT_BEGIN_NAMESPACE
call. Moreover, OpenGL errors stack up, therefore glGetError should always
be used in a loop like this:
- \code
+ \snippet code/src_gui_opengl_qopengldebug.cpp 0
- GLenum error = GL_NO_ERROR;
- do {
- error = glGetError();
- if (error != GL_NO_ERROR)
- // handle the error
- } while (error != GL_NO_ERROR);
-
- \endcode
+ If you try to clear the error stack, make sure not just keep going until
+ GL_NO_ERROR is returned but also break on GL_CONTEXT_LOST as that error
+ value will keep repeating.
There are also many other information we are interested in (as application
developers), for instance performance issues, or warnings about using
@@ -121,20 +116,7 @@ QT_BEGIN_NAMESPACE
to create a debug context from Qt, you must set the QSurfaceFormat::DebugContext
format option on the QSurfaceFormat used to create the QOpenGLContext object:
- \code
-
- QSurfaceFormat format;
- // asks for a OpenGL 3.2 debug context using the Core profile
- format.setMajorVersion(3);
- format.setMinorVersion(2);
- format.setProfile(QSurfaceFormat::CoreProfile);
- format.setOption(QSurfaceFormat::DebugContext);
-
- QOpenGLContext *context = new QOpenGLContext;
- context->setFormat(format);
- context->create();
-
- \endcode
+ \snippet code/src_gui_opengl_qopengldebug.cpp 1
Note that requesting a 3.2 OpenGL Core Profile is just for the example's
purposes; this class is not tied to any specific OpenGL or OpenGL ES
@@ -148,24 +130,13 @@ QT_BEGIN_NAMESPACE
object), and like the other OpenGL functions in Qt you \e{must} initialize
it before usage by calling initialize() whilst there is a current OpenGL context:
- \code
-
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
-
- logger->initialize(); // initializes in the current context, i.e. ctx
-
- \endcode
+ \snippet code/src_gui_opengl_qopengldebug.cpp 2
Note that the \c{GL_KHR_debug} extension \e{must} be available in the context
in order to access the messages logged by OpenGL. You can check the
presence of this extension by calling:
- \code
-
- ctx->hasExtension(QByteArrayLiteral("GL_KHR_debug"))
-
- \endcode
+ \snippet code/src_gui_opengl_qopengldebug.cpp 3
where \c{ctx} is a valid QOpenGLContext. If the extension is not available,
initialize() will return false.
@@ -175,13 +146,7 @@ QT_BEGIN_NAMESPACE
OpenGL implementations keep an internal log of debug messages. Messages
stored in this log can be retrieved by using the loggedMessages() function:
- \code
-
- const QList<QOpenGLDebugMessage> messages = logger->loggedMessages();
- for (const QOpenGLDebugMessage &message : messages)
- qDebug() << message;
-
- \endcode
+ \snippet code/src_gui_opengl_qopengldebug.cpp 4
The internal log has a limited size; when it fills up, older messages will
get discarded to make room for the new incoming messages. When you call
@@ -199,12 +164,7 @@ QT_BEGIN_NAMESPACE
you need to connect a suitable slot to the messageLogged() signal, and
start logging by calling startLogging():
- \code
-
- connect(logger, &QOpenGLDebugLogger::messageLogged, receiver, &LogHandler::handleLoggedMessage);
- logger->startLogging();
-
- \endcode
+ \snippet code/src_gui_opengl_qopengldebug.cpp 5
Similarly, logging can be disabled at any time by calling the stopLogging()
function.
@@ -255,14 +215,7 @@ QT_BEGIN_NAMESPACE
\l{QOpenGLDebugMessage::}{createThirdPartyMessage()}, and then inserting it
into the log by calling logMessage():
- \code
-
- QOpenGLDebugMessage message =
- QOpenGLDebugMessage::createApplicationMessage(QStringLiteral("Custom message"));
-
- logger->logMessage(message);
-
- \endcode
+ \snippet code/src_gui_opengl_qopengldebug.cpp 6
Note that OpenGL implementations have a vendor-specific limit to the length
of the messages that can be inserted in the debug log. You can retrieve
diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp
index 2f7afa4a66..1e5a10c99c 100644
--- a/src/gui/opengl/qopenglengineshadermanager.cpp
+++ b/src/gui/opengl/qopenglengineshadermanager.cpp
@@ -153,12 +153,8 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader_core;
code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader_core;
- code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO_core;
- code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM_core;
code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO_core;
code[MainFragmentShader_M] = qopenglslMainFragmentShader_M_core;
- code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO_core;
- code[MainFragmentShader_C] = qopenglslMainFragmentShader_C_core;
code[MainFragmentShader_O] = qopenglslMainFragmentShader_O_core;
code[MainFragmentShader] = qopenglslMainFragmentShader_core;
code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays_core;
@@ -171,7 +167,7 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader_core; // Calls "customShader", which must be appended
code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader_core;
- code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop_core;
+ code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_core;
code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader_core;
code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader_core;
code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader_core;
@@ -203,12 +199,8 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader;
code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader;
- code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO;
- code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM;
code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO;
code[MainFragmentShader_M] = qopenglslMainFragmentShader_M;
- code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO;
- code[MainFragmentShader_C] = qopenglslMainFragmentShader_C;
code[MainFragmentShader_O] = qopenglslMainFragmentShader_O;
code[MainFragmentShader] = qopenglslMainFragmentShader;
code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays;
@@ -220,10 +212,7 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader;
code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader;
- if (context->isOpenGLES())
- code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_ES;
- else
- code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop;
+ code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader;
code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader;
code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader;
code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader;
@@ -238,21 +227,20 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[RgbMaskWithGammaFragmentShader] = ""; //###
}
- // These shaders are not implemented yet and therefore are the same
- // for all profiles. Implementations should make a version for both
- // profiles and put the appropriate lines in the if-statement above.
+ // The composition shaders are just layout qualifiers and the same
+ // for all profiles that support them.
code[NoCompositionModeFragmentShader] = "";
- code[MultiplyCompositionModeFragmentShader] = ""; //###
- code[ScreenCompositionModeFragmentShader] = ""; //###
- code[OverlayCompositionModeFragmentShader] = ""; //###
- code[DarkenCompositionModeFragmentShader] = ""; //###
- code[LightenCompositionModeFragmentShader] = ""; //###
- code[ColorDodgeCompositionModeFragmentShader] = ""; //###
- code[ColorBurnCompositionModeFragmentShader] = ""; //###
- code[HardLightCompositionModeFragmentShader] = ""; //###
- code[SoftLightCompositionModeFragmentShader] = ""; //###
- code[DifferenceCompositionModeFragmentShader] = ""; //###
- code[ExclusionCompositionModeFragmentShader] = ""; //###
+ code[MultiplyCompositionModeFragmentShader] = qopenglslMultiplyCompositionModeFragmentShader;
+ code[ScreenCompositionModeFragmentShader] = qopenglslScreenCompositionModeFragmentShader;
+ code[OverlayCompositionModeFragmentShader] = qopenglslOverlayCompositionModeFragmentShader;
+ code[DarkenCompositionModeFragmentShader] = qopenglslDarkenCompositionModeFragmentShader;
+ code[LightenCompositionModeFragmentShader] = qopenglslLightenCompositionModeFragmentShader;
+ code[ColorDodgeCompositionModeFragmentShader] = qopenglslColorDodgeCompositionModeFragmentShader;
+ code[ColorBurnCompositionModeFragmentShader] = qopenglslColorBurnCompositionModeFragmentShader;
+ code[HardLightCompositionModeFragmentShader] = qopenglslHardLightCompositionModeFragmentShader;
+ code[SoftLightCompositionModeFragmentShader] = qopenglslSoftLightCompositionModeFragmentShader;
+ code[DifferenceCompositionModeFragmentShader] = qopenglslDifferenceCompositionModeFragmentShader;
+ code[ExclusionCompositionModeFragmentShader] = qopenglslExclusionCompositionModeFragmentShader;
#if defined(QT_DEBUG)
// Check that all the elements have been filled:
@@ -268,9 +256,13 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
QByteArray fragSource;
// Compile up the simple shader:
+#ifdef Q_OS_WASM
+ vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]);
+ vertexSource.append(qShaderSnippets[MainVertexShader]);
+#else
vertexSource.append(qShaderSnippets[MainVertexShader]);
vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]);
-
+#endif
fragSource.append(qShaderSnippets[MainFragmentShader]);
fragSource.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
@@ -396,9 +388,13 @@ QOpenGLEngineShaderProg *QOpenGLEngineSharedShaders::findProgramInCache(const QO
fragSource.append(qShaderSnippets[prog.maskFragShader]);
QByteArray vertexSource;
+#ifdef Q_OS_WASM
+ vertexSource.append(qShaderSnippets[prog.positionVertexShader]);
+ vertexSource.append(qShaderSnippets[prog.mainVertexShader]);
+#else
vertexSource.append(qShaderSnippets[prog.mainVertexShader]);
vertexSource.append(qShaderSnippets[prog.positionVertexShader]);
-
+#endif
QScopedPointer<QOpenGLShaderProgram> shaderProgram(new QOpenGLShaderProgram);
CachedShader shaderCache(fragSource, vertexSource);
@@ -612,8 +608,11 @@ void QOpenGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mo
if (compositionMode == mode)
return;
+ bool wasAdvanced = compositionMode > QPainter::CompositionMode_Plus;
+ bool isAdvanced = mode > QPainter::CompositionMode_Plus;
+
compositionMode = mode;
- shaderProgNeedsChanging = true; //###
+ shaderProgNeedsChanging = shaderProgNeedsChanging || wasAdvanced || isAdvanced;
}
void QOpenGLEngineShaderManager::setCustomStage(QOpenGLCustomShaderStage* stage)
@@ -783,21 +782,13 @@ bool QOpenGLEngineShaderManager::useCorrectShaderProg()
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_ImageArrays;
} else {
bool useGlobalOpacity = (opacityMode == UniformOpacity);
- if (hasCompose && hasMask && useGlobalOpacity)
- requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CMO;
- if (hasCompose && hasMask && !useGlobalOpacity)
- requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CM;
- if (!hasCompose && hasMask && useGlobalOpacity)
+ if (hasMask && useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_MO;
- if (!hasCompose && hasMask && !useGlobalOpacity)
+ if (hasMask && !useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_M;
- if (hasCompose && !hasMask && useGlobalOpacity)
- requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CO;
- if (hasCompose && !hasMask && !useGlobalOpacity)
- requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_C;
- if (!hasCompose && !hasMask && useGlobalOpacity)
+ if (!hasMask && useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_O;
- if (!hasCompose && !hasMask && !useGlobalOpacity)
+ if (!hasMask && !useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader;
}
diff --git a/src/gui/opengl/qopenglengineshadermanager_p.h b/src/gui/opengl/qopenglengineshadermanager_p.h
index 377501457d..d43788d777 100644
--- a/src/gui/opengl/qopenglengineshadermanager_p.h
+++ b/src/gui/opengl/qopenglengineshadermanager_p.h
@@ -281,12 +281,8 @@ public:
AffinePositionWithTextureBrushVertexShader,
// MainFragmentShader_CMO must be first in the list:
- MainFragmentShader_CMO,
- MainFragmentShader_CM,
MainFragmentShader_MO,
MainFragmentShader_M,
- MainFragmentShader_CO,
- MainFragmentShader_C,
MainFragmentShader_O,
MainFragmentShader,
MainFragmentShader_ImageArrays,
diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h
index a165643839..3ac599b6c2 100644
--- a/src/gui/opengl/qopenglengineshadersource_p.h
+++ b/src/gui/opengl/qopenglengineshadersource_p.h
@@ -303,17 +303,7 @@ static const char* const qopenglslPositionWithTextureBrushVertexShader = "\n\
static const char* const qopenglslAffinePositionWithTextureBrushVertexShader
= qopenglslPositionWithTextureBrushVertexShader;
-// OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead,
-// we emulate GL_REPEAT by only taking the fractional part of the texture coords.
-// TODO: Special case POT textures which don't need this emulation
-static const char* const qopenglslTextureBrushSrcFragmentShader_ES = "\n\
- varying highp vec2 brushTextureCoords; \n\
- uniform sampler2D brushTexture; \n\
- lowp vec4 srcPixel() { \n\
- return texture2D(brushTexture, fract(brushTextureCoords)); \n\
- }\n";
-
-static const char* const qopenglslTextureBrushSrcFragmentShader_desktop = "\n\
+static const char* const qopenglslTextureBrushSrcFragmentShader = "\n\
varying highp vec2 brushTextureCoords; \n\
uniform sampler2D brushTexture; \n\
lowp vec4 srcPixel() \n\
@@ -403,25 +393,6 @@ static const char* const qopenglslMainFragmentShader_ImageArrays = "\n\
gl_FragColor = srcPixel() * opacity; \n\
}\n";
-static const char* const qopenglslMainFragmentShader_CMO = "\n\
- uniform lowp float globalOpacity; \n\
- lowp vec4 srcPixel(); \n\
- lowp vec4 applyMask(lowp vec4); \n\
- lowp vec4 compose(lowp vec4); \n\
- void main() \n\
- { \n\
- gl_FragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_CM = "\n\
- lowp vec4 srcPixel(); \n\
- lowp vec4 applyMask(lowp vec4); \n\
- lowp vec4 compose(lowp vec4); \n\
- void main() \n\
- { \n\
- gl_FragColor = applyMask(compose(srcPixel())); \n\
- }\n";
-
static const char* const qopenglslMainFragmentShader_MO = "\n\
uniform lowp float globalOpacity; \n\
lowp vec4 srcPixel(); \n\
@@ -439,23 +410,6 @@ static const char* const qopenglslMainFragmentShader_M = "\n\
gl_FragColor = applyMask(srcPixel()); \n\
}\n";
-static const char* const qopenglslMainFragmentShader_CO = "\n\
- uniform lowp float globalOpacity; \n\
- lowp vec4 srcPixel(); \n\
- lowp vec4 compose(lowp vec4); \n\
- void main() \n\
- { \n\
- gl_FragColor = compose(srcPixel()*globalOpacity); \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_C = "\n\
- lowp vec4 srcPixel(); \n\
- lowp vec4 compose(lowp vec4); \n\
- void main() \n\
- { \n\
- gl_FragColor = compose(srcPixel()); \n\
- }\n";
-
static const char* const qopenglslMainFragmentShader_O = "\n\
uniform lowp float globalOpacity; \n\
lowp vec4 srcPixel(); \n\
@@ -513,22 +467,65 @@ static const char* const qopenglslRgbMaskFragmentShaderPass2 = "\n\
return src * mask; \n\
}\n";
+static const char* const qopenglslMultiplyCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_multiply) out;\n\
+ #endif\n";
+
+static const char* const qopenglslScreenCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_screen) out;\n\
+ #endif\n";
+
+static const char* const qopenglslOverlayCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_overlay) out;\n\
+ #endif\n";
+
+static const char* const qopenglslDarkenCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_darken) out;\n\
+ #endif\n";
+
+static const char* const qopenglslLightenCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_lighten) out;\n\
+ #endif\n";
+
+static const char* const qopenglslColorDodgeCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_colordodge) out;\n\
+ #endif\n";
+
+static const char* const qopenglslColorBurnCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_colorburn) out;\n\
+ #endif\n";
+
+static const char* const qopenglslHardLightCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_hardlight) out;\n\
+ #endif\n";
+
+static const char* const qopenglslSoftLightCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_softlight) out;\n\
+ #endif\n";
+
+static const char* const qopenglslDifferenceCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_difference) out;\n\
+ #endif\n";
+
+static const char* const qopenglslExclusionCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_exclusion) out;\n\
+ #endif\n";
+
/*
Left to implement:
RgbMaskFragmentShader,
RgbMaskWithGammaFragmentShader,
-
- MultiplyCompositionModeFragmentShader,
- ScreenCompositionModeFragmentShader,
- OverlayCompositionModeFragmentShader,
- DarkenCompositionModeFragmentShader,
- LightenCompositionModeFragmentShader,
- ColorDodgeCompositionModeFragmentShader,
- ColorBurnCompositionModeFragmentShader,
- HardLightCompositionModeFragmentShader,
- SoftLightCompositionModeFragmentShader,
- DifferenceCompositionModeFragmentShader,
- ExclusionCompositionModeFragmentShader,
*/
/*
@@ -788,7 +785,7 @@ static const char* const qopenglslPositionWithTextureBrushVertexShader_core = "\
static const char* const qopenglslAffinePositionWithTextureBrushVertexShader_core
= qopenglslPositionWithTextureBrushVertexShader_core;
-static const char* const qopenglslTextureBrushSrcFragmentShader_desktop_core = "\n\
+static const char* const qopenglslTextureBrushSrcFragmentShader_core = "\n\
in vec2 brushTextureCoords; \n\
uniform sampler2D brushTexture; \n\
vec4 srcPixel() \n\
@@ -880,29 +877,6 @@ static const char* const qopenglslMainFragmentShader_ImageArrays_core =
fragColor = srcPixel() * opacity; \n\
}\n";
-static const char* const qopenglslMainFragmentShader_CMO_core =
- "#version 150 core\n\
- out vec4 fragColor; \n\
- uniform float globalOpacity; \n\
- vec4 srcPixel(); \n\
- vec4 applyMask(vec4); \n\
- vec4 compose(vec4); \n\
- void main() \n\
- { \n\
- fragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_CM_core =
- "#version 150 core\n\
- out vec4 fragColor; \n\
- vec4 srcPixel(); \n\
- vec4 applyMask(vec4); \n\
- vec4 compose(vec4); \n\
- void main() \n\
- { \n\
- fragColor = applyMask(compose(srcPixel())); \n\
- }\n";
-
static const char* const qopenglslMainFragmentShader_MO_core =
"#version 150 core\n\
out vec4 fragColor; \n\
@@ -924,27 +898,6 @@ static const char* const qopenglslMainFragmentShader_M_core =
fragColor = applyMask(srcPixel()); \n\
}\n";
-static const char* const qopenglslMainFragmentShader_CO_core =
- "#version 150 core\n\
- out vec4 fragColor; \n\
- uniform float globalOpacity; \n\
- vec4 srcPixel(); \n\
- vec4 compose(vec4); \n\
- void main() \n\
- { \n\
- fragColor = compose(srcPixel()*globalOpacity); \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_C_core =
- "#version 150 core\n\
- out vec4 fragColor; \n\
- vec4 srcPixel(); \n\
- vec4 compose(vec4); \n\
- void main() \n\
- { \n\
- fragColor = compose(srcPixel()); \n\
- }\n";
-
static const char* const qopenglslMainFragmentShader_O_core =
"#version 150 core\n\
out vec4 fragColor; \n\
@@ -1010,18 +963,6 @@ static const char* const qopenglslRgbMaskFragmentShaderPass2_core = "\n\
Left to implement:
RgbMaskFragmentShader_core,
RgbMaskWithGammaFragmentShader_core,
-
- MultiplyCompositionModeFragmentShader_core,
- ScreenCompositionModeFragmentShader_core,
- OverlayCompositionModeFragmentShader_core,
- DarkenCompositionModeFragmentShader_core,
- LightenCompositionModeFragmentShader_core,
- ColorDodgeCompositionModeFragmentShader_core,
- ColorBurnCompositionModeFragmentShader_core,
- HardLightCompositionModeFragmentShader_core,
- SoftLightCompositionModeFragmentShader_core,
- DifferenceCompositionModeFragmentShader_core,
- ExclusionCompositionModeFragmentShader_core,
*/
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglextensions_p.h b/src/gui/opengl/qopenglextensions_p.h
index a5f1a2cc88..af8ee8201d 100644
--- a/src/gui/opengl/qopenglextensions_p.h
+++ b/src/gui/opengl/qopenglextensions_p.h
@@ -90,7 +90,8 @@ public:
MapBufferRange = 0x00100000,
Sized8Formats = 0x00200000,
DiscardFramebuffer = 0x00400000,
- Sized16Formats = 0x00800000
+ Sized16Formats = 0x00800000,
+ TextureSwizzle = 0x01000000,
};
Q_DECLARE_FLAGS(OpenGLExtensions, OpenGLExtension)
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index 83bc568ba7..cae3d516c4 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -110,6 +110,10 @@ QT_BEGIN_NAMESPACE
#define GL_RGB10 0x8052
#endif
+#ifndef GL_RGB16
+#define GL_RGB16 0x8054
+#endif
+
#ifndef GL_RGBA8
#define GL_RGBA8 0x8058
#endif
@@ -118,6 +122,10 @@ QT_BEGIN_NAMESPACE
#define GL_RGB10_A2 0x8059
#endif
+#ifndef GL_RGBA16
+#define GL_RGBA16 0x805B
+#endif
+
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
@@ -134,6 +142,15 @@ QT_BEGIN_NAMESPACE
#define GL_CONTEXT_LOST 0x0507
#endif
+#ifndef GL_DEPTH_STENCIL_ATTACHMENT
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#endif
+
+#ifndef GL_DEPTH_STENCIL
+#define GL_DEPTH_STENCIL 0x84F9
+#endif
+
+
/*!
\class QOpenGLFramebufferObjectFormat
@@ -530,6 +547,8 @@ void QOpenGLFramebufferObjectPrivate::initTexture(int idx)
GLuint pixelType = GL_UNSIGNED_BYTE;
if (color.internalFormat == GL_RGB10_A2 || color.internalFormat == GL_RGB10)
pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ else if (color.internalFormat == GL_RGB16 || color.internalFormat == GL_RGBA16)
+ pixelType = GL_UNSIGNED_SHORT;
funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0,
GL_RGBA, pixelType, NULL);
@@ -567,11 +586,16 @@ void QOpenGLFramebufferObjectPrivate::initColorBuffer(int idx, GLint *samples)
GLenum storageFormat = color.internalFormat;
// ES requires a sized format. The older desktop extension does not. Correct the format on ES.
- if (ctx->isOpenGLES() && color.internalFormat == GL_RGBA) {
- if (funcs.hasOpenGLExtension(QOpenGLExtensions::Sized8Formats))
- storageFormat = GL_RGBA8;
- else
- storageFormat = GL_RGBA4;
+ if (ctx->isOpenGLES()) {
+ if (color.internalFormat == GL_RGBA) {
+ if (funcs.hasOpenGLExtension(QOpenGLExtensions::Sized8Formats))
+ storageFormat = GL_RGBA8;
+ else
+ storageFormat = GL_RGBA4;
+ } else if (color.internalFormat == GL_RGB10) {
+ // GL_RGB10 is not allowed in ES for glRenderbufferStorage.
+ storageFormat = GL_RGB10_A2;
+ }
}
funcs.glGenRenderbuffers(1, &color_buffer);
@@ -603,7 +627,11 @@ void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext
// free existing attachments
if (depth_buffer_guard) {
+#ifdef Q_OS_WASM
+ funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+#else
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+#endif
depth_buffer_guard->free();
}
if (stencil_buffer_guard) {
@@ -621,7 +649,35 @@ void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext
// In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a
// separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer
// might not be supported while separate buffers are, according to QTBUG-12861.
+#ifdef Q_OS_WASM
+ // WebGL doesn't allow separately attach buffers to
+ // STENCIL_ATTACHMENT and DEPTH_ATTACHMENT
+ // QTBUG-69913
+ if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil) {
+ funcs.glGenRenderbuffers(1, &depth_buffer);
+ funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
+ Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
+ GLenum storageFormat = GL_DEPTH_STENCIL;
+
+ if (samples != 0 ) {
+ funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
+ storageFormat, dsSize.width(), dsSize.height());
+ } else {
+ funcs.glRenderbufferStorage(GL_RENDERBUFFER, storageFormat,
+ dsSize.width(), dsSize.height());
+ }
+
+ funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, depth_buffer);
+
+ valid = checkFramebufferStatus(ctx);
+ if (!valid) {
+ funcs.glDeleteRenderbuffers(1, &depth_buffer);
+ depth_buffer = 0;
+ }
+ }
+#else
if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
&& funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil))
{
@@ -713,11 +769,16 @@ void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext
stencil_buffer = 0;
}
}
+#endif //Q_OS_WASM
// The FBO might have become valid after removing the depth or stencil buffer.
valid = checkFramebufferStatus(ctx);
+#ifdef Q_OS_WASM
+ if (depth_buffer) {
+#else
if (depth_buffer && stencil_buffer) {
+#endif
fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil;
} else if (depth_buffer) {
fbo_attachment = QOpenGLFramebufferObject::Depth;
@@ -1307,6 +1368,14 @@ static inline QImage qt_gl_read_framebuffer_rgb10a2(const QSize &size, bool incl
return img;
}
+static inline QImage qt_gl_read_framebuffer_rgba16(const QSize &size, bool include_alpha, QOpenGLContext *context)
+{
+ // We assume OpenGL 1.2+ or ES 3.0+ here.
+ QImage img(size, include_alpha ? QImage::Format_RGBA64_Premultiplied : QImage::Format_RGBX64);
+ context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_SHORT, img.bits());
+ return img;
+}
+
static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format, bool include_alpha, bool flip)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
@@ -1324,6 +1393,10 @@ static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format,
return qt_gl_read_framebuffer_rgb10a2(size, false, ctx).mirrored(false, flip);
case GL_RGB10_A2:
return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).mirrored(false, flip);
+ case GL_RGB16:
+ return qt_gl_read_framebuffer_rgba16(size, false, ctx).mirrored(false, flip);
+ case GL_RGBA16:
+ return qt_gl_read_framebuffer_rgba16(size, include_alpha, ctx).mirrored(false, flip);
case GL_RGBA:
case GL_RGBA8:
default:
@@ -1352,7 +1425,8 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
is used only when internalTextureFormat() is set to \c GL_RGB. Since Qt 5.2
the function will fall back to premultiplied RGBA8888 or RGBx8888 when
reading to (A)RGB32 is not supported, and this includes OpenGL ES. Since Qt
- 5.4 an A2BGR30 image is returned if the internal format is RGB10_A2.
+ 5.4 an A2BGR30 image is returned if the internal format is RGB10_A2, and since
+ Qt 5.12 a RGBA64 image is return if the internal format is RGBA16.
If the rendering in the framebuffer was not done with premultiplied alpha in mind,
create a wrapper QImage with a non-premultiplied format. This is necessary before
diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp
index 977565516f..b4ff21f3fd 100644
--- a/src/gui/opengl/qopenglfunctions.cpp
+++ b/src/gui/opengl/qopenglfunctions.cpp
@@ -45,6 +45,7 @@
#include <QtGui/private/qopengl_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
#ifdef Q_OS_INTEGRITY
#include <EGL/egl.h>
@@ -89,65 +90,18 @@ void CLASS::init(QOpenGLContext *context) \
that need it. The recommended way to use QOpenGLFunctions is by
direct inheritance:
- \code
- class MyGLWindow : public QWindow, protected QOpenGLFunctions
- {
- Q_OBJECT
- public:
- MyGLWindow(QScreen *screen = 0);
-
- protected:
- void initializeGL();
- void paintGL();
-
- QOpenGLContext *m_context;
- };
-
- MyGLWindow(QScreen *screen)
- : QWindow(screen), QOpenGLWidget(parent)
- {
- setSurfaceType(OpenGLSurface);
- create();
-
- // Create an OpenGL context
- m_context = new QOpenGLContext;
- m_context->create();
-
- // Setup scene and render it
- initializeGL();
- paintGL();
- }
-
- void MyGLWindow::initializeGL()
- {
- m_context->makeCurrent(this);
- initializeOpenGLFunctions();
- }
- \endcode
+ \snippet code/src_gui_opengl_qopenglfunctions.cpp 0
The \c{paintGL()} function can then use any of the OpenGL ES 2.0
functions without explicit resolution, such as glActiveTexture()
in the following example:
- \code
- void MyGLWindow::paintGL()
- {
- m_context->makeCurrent(this);
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, textureId);
- ...
- m_context->swapBuffers(this);
- m_context->doneCurrent();
- }
- \endcode
+ \snippet code/src_gui_opengl_qopenglfunctions.cpp 1
QOpenGLFunctions can also be used directly for ad-hoc invocation
of OpenGL ES 2.0 functions on all platforms:
- \code
- QOpenGLFunctions glFuncs(QOpenGLContext::currentContext());
- glFuncs.glActiveTexture(GL_TEXTURE1);
- \endcode
+ \snippet code/src_gui_opengl_qopenglfunctions.cpp 2
An alternative approach is to query the context's associated
QOpenGLFunctions instance. This is somewhat faster than the previous
@@ -156,10 +110,7 @@ void CLASS::init(QOpenGLContext *context) \
resolving happens only once for a given context, regardless of the number of
QOpenGLFunctions instances initialized for it.
- \code
- QOpenGLFunctions *glFuncs = QOpenGLContext::currentContext()->functions();
- glFuncs->glActiveTexture(GL_TEXTURE1);
- \endcode
+ \snippet code/src_gui_opengl_qopenglfunctions.cpp 3
QOpenGLFunctions provides wrappers for all OpenGL ES 2.0
functions, including the common subset of OpenGL 1.x and ES
@@ -174,10 +125,7 @@ void CLASS::init(QOpenGLContext *context) \
feature. For example, the following checks if non power of two
textures are available:
- \code
- QOpenGLFunctions funcs(QOpenGLContext::currentContext());
- bool npot = funcs.hasOpenGLFeature(QOpenGLFunctions::NPOTTextures);
- \endcode
+ \snippet code/src_gui_opengl_qopenglfunctions.cpp 4
\sa QOpenGLContext, QSurfaceFormat
*/
@@ -294,9 +242,19 @@ QOpenGLExtensions::QOpenGLExtensions(QOpenGLContext *context)
static int qt_gl_resolve_features()
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QOpenGLExtensionMatcher extensions;
+ int features = 0;
+ if ((extensions.match("GL_KHR_blend_equation_advanced")
+ || extensions.match("GL_NV_blend_equation_advanced")) &&
+ (extensions.match("GL_KHR_blend_equation_advanced_coherent")
+ || extensions.match("GL_NV_blend_equation_advanced_coherent"))) {
+ // We need both the advanced equations and the coherency for us
+ // to be able to easily use the new blend equations
+ features |= QOpenGLFunctions::BlendEquationAdvanced;
+ }
if (ctx->isOpenGLES()) {
// OpenGL ES
- int features = QOpenGLFunctions::Multitexture |
+ features |= QOpenGLFunctions::Multitexture |
QOpenGLFunctions::Shaders |
QOpenGLFunctions::Buffers |
QOpenGLFunctions::Framebuffers |
@@ -308,7 +266,6 @@ static int qt_gl_resolve_features()
QOpenGLFunctions::CompressedTextures |
QOpenGLFunctions::Multisample |
QOpenGLFunctions::StencilSeparate;
- QOpenGLExtensionMatcher extensions;
if (extensions.match("GL_IMG_texture_npot"))
features |= QOpenGLFunctions::NPOTTextures;
if (extensions.match("GL_OES_texture_npot"))
@@ -320,14 +277,18 @@ static int qt_gl_resolve_features()
if (!(renderer && strstr(renderer, "Mesa")))
features |= QOpenGLFunctions::TextureRGFormats;
}
- if (ctx->format().majorVersion() >= 3)
+ if (ctx->format().majorVersion() >= 3) {
features |= QOpenGLFunctions::MultipleRenderTargets;
+ if (ctx->format().minorVersion() >= 2 && extensions.match("GL_KHR_blend_equation_advanced_coherent")) {
+ // GL_KHR_blend_equation_advanced is included in OpenGL ES/3.2
+ features |= QOpenGLFunctions::BlendEquationAdvanced;
+ }
+ }
return features;
} else {
// OpenGL
- int features = QOpenGLFunctions::TextureRGFormats;
+ features |= QOpenGLFunctions::TextureRGFormats;
QSurfaceFormat format = QOpenGLContext::currentContext()->format();
- QOpenGLExtensionMatcher extensions;
if (format.majorVersion() >= 3)
features |= QOpenGLFunctions::Framebuffers | QOpenGLFunctions::MultipleRenderTargets;
@@ -411,6 +372,8 @@ static int qt_gl_resolve_extensions()
extensions |= QOpenGLExtensions::NVFloatBuffer;
if (extensionMatcher.match("GL_ARB_pixel_buffer_object"))
extensions |= QOpenGLExtensions::PixelBufferObject;
+ if (extensionMatcher.match("GL_ARB_texture_swizzle") || extensionMatcher.match("GL_EXT_texture_swizzle"))
+ extensions |= QOpenGLExtensions::TextureSwizzle;
if (ctx->isOpenGLES()) {
if (format.majorVersion() >= 2)
@@ -423,7 +386,8 @@ static int qt_gl_resolve_extensions()
| QOpenGLExtensions::MapBufferRange
| QOpenGLExtensions::FramebufferBlit
| QOpenGLExtensions::FramebufferMultisample
- | QOpenGLExtensions::Sized8Formats;
+ | QOpenGLExtensions::Sized8Formats
+ | QOpenGLExtensions::TextureSwizzle;
} else {
// Recognize features by extension name.
if (extensionMatcher.match("GL_OES_packed_depth_stencil"))
@@ -449,6 +413,17 @@ static int qt_gl_resolve_extensions()
// We don't match GL_APPLE_texture_format_BGRA8888 here because it has different semantics.
if (extensionMatcher.match("GL_IMG_texture_format_BGRA8888") || extensionMatcher.match("GL_EXT_texture_format_BGRA8888"))
extensions |= QOpenGLExtensions::BGRATextureFormat;
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+ QString *deviceName =
+ static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName"));
+ static bool wrongfullyReportsBgra8888Support = deviceName != 0
+ && (deviceName->compare(QLatin1String("samsung SM-T211"), Qt::CaseInsensitive) == 0
+ || deviceName->compare(QLatin1String("samsung SM-T210"), Qt::CaseInsensitive) == 0
+ || deviceName->compare(QLatin1String("samsung SM-T215"), Qt::CaseInsensitive) == 0);
+ if (wrongfullyReportsBgra8888Support)
+ extensions &= ~QOpenGLExtensions::BGRATextureFormat;
+#endif
+
if (extensionMatcher.match("GL_EXT_discard_framebuffer"))
extensions |= QOpenGLExtensions::DiscardFramebuffer;
if (extensionMatcher.match("GL_EXT_texture_norm16"))
@@ -482,6 +457,9 @@ static int qt_gl_resolve_extensions()
if (format.version() >= qMakePair(3, 2) || extensionMatcher.match("GL_ARB_geometry_shader4"))
extensions |= QOpenGLExtensions::GeometryShaders;
+ if (format.version() >= qMakePair(3, 3))
+ extensions |= QOpenGLExtensions::TextureSwizzle;
+
if (extensionMatcher.match("GL_ARB_map_buffer_range"))
extensions |= QOpenGLExtensions::MapBufferRange;
diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h
index 1a43f13d9b..00287b0665 100644
--- a/src/gui/opengl/qopenglfunctions.h
+++ b/src/gui/opengl/qopenglfunctions.h
@@ -277,7 +277,8 @@ public:
NPOTTextureRepeat = 0x2000,
FixedFunctionPipeline = 0x4000,
TextureRGFormats = 0x8000,
- MultipleRenderTargets = 0x10000
+ MultipleRenderTargets = 0x10000,
+ BlendEquationAdvanced = 0x20000,
};
Q_DECLARE_FLAGS(OpenGLFeatures, OpenGLFeature)
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index 6a89089f18..001cb839fa 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -87,8 +87,27 @@
#include <QDebug>
-QT_BEGIN_NAMESPACE
+#ifndef GL_KHR_blend_equation_advanced
+#define GL_KHR_blend_equation_advanced 1
+#define GL_MULTIPLY_KHR 0x9294
+#define GL_SCREEN_KHR 0x9295
+#define GL_OVERLAY_KHR 0x9296
+#define GL_DARKEN_KHR 0x9297
+#define GL_LIGHTEN_KHR 0x9298
+#define GL_COLORDODGE_KHR 0x9299
+#define GL_COLORBURN_KHR 0x929A
+#define GL_HARDLIGHT_KHR 0x929B
+#define GL_SOFTLIGHT_KHR 0x929C
+#define GL_DIFFERENCE_KHR 0x929E
+#define GL_EXCLUSION_KHR 0x92A0
+#endif /* GL_KHR_blend_equation_advanced */
+
+#ifndef GL_KHR_blend_equation_advanced_coherent
+#define GL_KHR_blend_equation_advanced_coherent 1
+#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285
+#endif /* GL_KHR_blend_equation_advanced_coherent */
+QT_BEGIN_NAMESPACE
Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert);
@@ -244,7 +263,7 @@ GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QGradient &gradient)
struct ImageWithBindOptions
{
const QImage &image;
- QOpenGLTextureCache::BindOptions options;
+ QOpenGLTextureUploader::BindOptions options;
};
template<>
@@ -253,6 +272,12 @@ GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const ImageWithBindOptions &ima
return QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, imageWithOptions.image, imageWithOptions.options);
}
+inline static bool isPowerOfTwo(int x)
+{
+ // Assumption: x >= 1
+ return x == (x & -x);
+}
+
void QOpenGL2PaintEngineExPrivate::updateBrushTexture()
{
Q_Q(QOpenGL2PaintEngineEx);
@@ -285,16 +310,18 @@ void QOpenGL2PaintEngineExPrivate::updateBrushTexture()
currentBrushImage = currentBrush.textureImage();
int max_texture_size = ctx->d_func()->maxTextureSize();
- if (currentBrushImage.width() > max_texture_size || currentBrushImage.height() > max_texture_size)
- currentBrushImage = currentBrushImage.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
+ QSize newSize = currentBrushImage.size();
+ newSize = newSize.boundedTo(QSize(max_texture_size, max_texture_size));
+ if (!QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat)) {
+ if (!isPowerOfTwo(newSize.width()) || !isPowerOfTwo(newSize.height())) {
+ newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1));
+ newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1));
+ }
+ }
+ if (currentBrushImage.size() != newSize)
+ currentBrushImage = currentBrushImage.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
GLuint wrapMode = GL_REPEAT;
- if (QOpenGLContext::currentContext()->isOpenGLES()) {
- // OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead,
- // we emulate GL_REPEAT by only taking the fractional part of the texture coords
- // in the qopenglslTextureBrushSrcFragmentShader program.
- wrapMode = GL_CLAMP_TO_EDGE;
- }
updateTexture(QT_BRUSH_TEXTURE_UNIT, currentBrushImage, wrapMode, filterMode, ForceUpdate);
}
@@ -498,6 +525,21 @@ void QOpenGL2PaintEngineExPrivate::updateCompositionMode()
// NOTE: The entire paint engine works on pre-multiplied data - which is why some of these
// composition modes look odd.
// qDebug() << "QOpenGL2PaintEngineExPrivate::updateCompositionMode() - Setting GL composition mode for " << q->state()->composition_mode;
+ if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::BlendEquationAdvanced)) {
+ if (q->state()->composition_mode <= QPainter::CompositionMode_Plus) {
+ funcs.glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
+ funcs.glBlendEquation(GL_FUNC_ADD);
+ } else {
+ funcs.glEnable(GL_BLEND_ADVANCED_COHERENT_KHR);
+ }
+ shaderManager->setCompositionMode(q->state()->composition_mode);
+ } else {
+ if (q->state()->composition_mode > QPainter::CompositionMode_Plus) {
+ qWarning("Unsupported composition mode");
+ compositionModeDirty = false;
+ return;
+ }
+ }
switch(q->state()->composition_mode) {
case QPainter::CompositionMode_SourceOver:
funcs.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
@@ -538,6 +580,39 @@ void QOpenGL2PaintEngineExPrivate::updateCompositionMode()
case QPainter::CompositionMode_Plus:
funcs.glBlendFunc(GL_ONE, GL_ONE);
break;
+ case QPainter::CompositionMode_Multiply:
+ funcs.glBlendEquation(GL_MULTIPLY_KHR);
+ break;
+ case QPainter::CompositionMode_Screen:
+ funcs.glBlendEquation(GL_SCREEN_KHR);
+ break;
+ case QPainter::CompositionMode_Overlay:
+ funcs.glBlendEquation(GL_OVERLAY_KHR);
+ break;
+ case QPainter::CompositionMode_Darken:
+ funcs.glBlendEquation(GL_DARKEN_KHR);
+ break;
+ case QPainter::CompositionMode_Lighten:
+ funcs.glBlendEquation(GL_LIGHTEN_KHR);
+ break;
+ case QPainter::CompositionMode_ColorDodge:
+ funcs.glBlendEquation(GL_COLORDODGE_KHR);
+ break;
+ case QPainter::CompositionMode_ColorBurn:
+ funcs.glBlendEquation(GL_COLORBURN_KHR);
+ break;
+ case QPainter::CompositionMode_HardLight:
+ funcs.glBlendEquation(GL_HARDLIGHT_KHR);
+ break;
+ case QPainter::CompositionMode_SoftLight:
+ funcs.glBlendEquation(GL_SOFTLIGHT_KHR);
+ break;
+ case QPainter::CompositionMode_Difference:
+ funcs.glBlendEquation(GL_DIFFERENCE_KHR);
+ break;
+ case QPainter::CompositionMode_Exclusion:
+ funcs.glBlendEquation(GL_EXCLUSION_KHR);
+ break;
default:
qWarning("Unsupported composition mode");
break;
@@ -1487,25 +1562,26 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c
ensureActive();
d->transferMode(ImageDrawingMode);
- QOpenGLTextureCache::BindOptions bindOption = QOpenGLTextureCache::PremultipliedAlphaBindOption;
+ QOpenGLTextureUploader::BindOptions bindOption = QOpenGLTextureUploader::PremultipliedAlphaBindOption;
// Use specialized bind for formats we have specialized shaders for.
switch (image.format()) {
case QImage::Format_RGBA8888:
case QImage::Format_ARGB32:
+ case QImage::Format_RGBA64:
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::NonPremultipliedImageSrc);
bindOption = 0;
break;
case QImage::Format_Alpha8:
if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) {
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::AlphaImageSrc);
- bindOption = QOpenGLTextureCache::UseRedFor8BitBindOption;
+ bindOption = QOpenGLTextureUploader::UseRedFor8BitBindOption;
} else
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
break;
case QImage::Format_Grayscale8:
if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) {
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::GrayscaleImageSrc);
- bindOption = QOpenGLTextureCache::UseRedFor8BitBindOption;
+ bindOption = QOpenGLTextureUploader::UseRedFor8BitBindOption;
} else
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
break;
diff --git a/src/gui/opengl/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp
index d16173df83..c96021a969 100644
--- a/src/gui/opengl/qopenglprogrambinarycache.cpp
+++ b/src/gui/opengl/qopenglprogrambinarycache.cpp
@@ -54,14 +54,19 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
+#ifndef GL_CONTEXT_LOST
+#define GL_CONTEXT_LOST 0x0507
+#endif
+
#ifndef GL_PROGRAM_BINARY_LENGTH
#define GL_PROGRAM_BINARY_LENGTH 0x8741
#endif
const quint32 BINSHADER_MAGIC = 0x5174;
-const quint32 BINSHADER_VERSION = 0x2;
+const quint32 BINSHADER_VERSION = 0x3;
const quint32 BINSHADER_QTVERSION = QT_VERSION;
+namespace {
struct GLEnvInfo
{
GLEnvInfo();
@@ -70,6 +75,7 @@ struct GLEnvInfo
QByteArray glrenderer;
QByteArray glversion;
};
+}
GLEnvInfo::GLEnvInfo()
{
@@ -114,7 +120,7 @@ QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) con
return m_cacheDir + QString::fromUtf8(cacheKey);
}
-#define BASE_HEADER_SIZE (int(3 * sizeof(quint32)))
+#define BASE_HEADER_SIZE (int(4 * sizeof(quint32)))
#define FULL_HEADER_SIZE(stringsSize) (BASE_HEADER_SIZE + 12 + stringsSize + 8)
#define PADDING_SIZE(fullHeaderSize) (((fullHeaderSize + 3) & ~3) - fullHeaderSize)
@@ -153,13 +159,21 @@ bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const
qCDebug(DBG_SHADER_CACHE, "Qt version does not match");
return false;
}
+ if (readUInt(&p) != sizeof(quintptr)) {
+ qCDebug(DBG_SHADER_CACHE, "Architecture does not match");
+ return false;
+ }
return true;
}
bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat, const void *p, uint blobSize)
{
QOpenGLExtraFunctions *funcs = QOpenGLContext::currentContext()->extraFunctions();
- while (funcs->glGetError() != GL_NO_ERROR) { }
+ while (true) {
+ GLenum error = funcs->glGetError();
+ if (error == GL_NO_ERROR || error == GL_CONTEXT_LOST)
+ break;
+ }
funcs->glProgramBinary(programId, blobFormat, p, blobSize);
GLenum err = funcs->glGetError();
@@ -335,7 +349,11 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
QOpenGLExtraFunctions *funcs = QOpenGLContext::currentContext()->extraFunctions();
GLint blobSize = 0;
- while (funcs->glGetError() != GL_NO_ERROR) { }
+ while (true) {
+ GLenum error = funcs->glGetError();
+ if (error == GL_NO_ERROR || error == GL_CONTEXT_LOST)
+ break;
+ }
funcs->glGetProgramiv(programId, GL_PROGRAM_BINARY_LENGTH, &blobSize);
const int headerSize = FULL_HEADER_SIZE(info.glvendor.size() + info.glrenderer.size() + info.glversion.size());
@@ -357,6 +375,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
writeUInt(&p, BINSHADER_MAGIC);
writeUInt(&p, BINSHADER_VERSION);
writeUInt(&p, BINSHADER_QTVERSION);
+ writeUInt(&p, sizeof(quintptr));
writeStr(&p, info.glvendor);
writeStr(&p, info.glrenderer);
diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp
index 2ae9c6d327..c39177080d 100644
--- a/src/gui/opengl/qopenglshaderprogram.cpp
+++ b/src/gui/opengl/qopenglshaderprogram.cpp
@@ -39,7 +39,7 @@
#include "qopenglshaderprogram.h"
#include "qopenglprogrambinarycache_p.h"
-#include "qopenglfunctions.h"
+#include "qopenglextrafunctions.h"
#include "private/qopenglcontext_p.h"
#include <QtCore/private/qobject_p.h>
#include <QtCore/qdebug.h>
@@ -170,13 +170,13 @@ QT_BEGIN_NAMESPACE
\value Vertex Vertex shader written in the OpenGL Shading Language (GLSL).
\value Fragment Fragment shader written in the OpenGL Shading Language (GLSL).
\value Geometry Geometry shaders written in the OpenGL Shading Language (GLSL)
- based on the OpenGL core feature (requires OpenGL >= 3.2).
+ (requires OpenGL >= 3.2 or OpenGL ES >= 3.2).
\value TessellationControl Tessellation control shaders written in the OpenGL
- shading language (GLSL), based on the core feature (requires OpenGL >= 4.0).
+ shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2).
\value TessellationEvaluation Tessellation evaluation shaders written in the OpenGL
- shading language (GLSL), based on the core feature (requires OpenGL >= 4.0).
- \value Compute Compute shaders written in the OpenGL shading language (GLSL),
- based on the core feature (requires OpenGL >= 4.3).
+ shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2).
+ \value Compute Compute shaders written in the OpenGL shading language (GLSL)
+ (requires OpenGL >= 4.3 or OpenGL ES >= 3.1).
*/
Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
@@ -223,26 +223,18 @@ static inline bool isFormatGLES(const QSurfaceFormat &f)
static inline bool supportsGeometry(const QSurfaceFormat &f)
{
-#ifndef QT_OPENGL_ES_2
- if (!isFormatGLES(f))
- return (f.version() >= qMakePair<int, int>(3, 2));
- else
- return false;
-#else
- Q_UNUSED(f);
- return false;
-#endif
+ return f.version() >= qMakePair(3, 2);
}
static inline bool supportsCompute(const QSurfaceFormat &f)
{
#ifndef QT_OPENGL_ES_2
if (!isFormatGLES(f))
- return (f.version() >= qMakePair<int, int>(4, 3));
+ return f.version() >= qMakePair(4, 3);
else
- return (f.version() >= qMakePair<int, int>(3, 1));
+ return f.version() >= qMakePair(3, 1);
#else
- return (f.version() >= qMakePair<int, int>(3, 1));
+ return f.version() >= qMakePair(3, 1);
#endif
}
@@ -250,12 +242,11 @@ static inline bool supportsTessellation(const QSurfaceFormat &f)
{
#ifndef QT_OPENGL_ES_2
if (!isFormatGLES(f))
- return (f.version() >= qMakePair<int, int>(4, 0));
+ return f.version() >= qMakePair(4, 0);
else
- return false;
+ return f.version() >= qMakePair(3, 2);
#else
- Q_UNUSED(f);
- return false;
+ return f.version() >= qMakePair(3, 2);
#endif
}
@@ -267,7 +258,7 @@ public:
: shaderGuard(0)
, shaderType(type)
, compiled(false)
- , glfuncs(new QOpenGLFunctions(ctx))
+ , glfuncs(new QOpenGLExtraFunctions(ctx))
, supportsGeometryShaders(false)
, supportsTessellationShaders(false)
, supportsComputeShaders(false)
@@ -286,7 +277,7 @@ public:
bool compiled;
QString log;
- QOpenGLFunctions *glfuncs;
+ QOpenGLExtraFunctions *glfuncs;
// Support for geometry shaders
bool supportsGeometryShaders;
@@ -496,6 +487,13 @@ static const char redefineHighp[] =
"#endif\n";
#endif
+// Boiler-plate header to have the layout attributes available we need later
+static const char blendEquationAdvancedHeader[] =
+ "#ifdef GL_KHR_blend_equation_advanced\n"
+ "#extension GL_ARB_fragment_coord_conventions : enable\n"
+ "#extension GL_KHR_blend_equation_advanced : enable\n"
+ "#endif\n";
+
struct QVersionDirectivePosition
{
Q_DECL_CONSTEXPR QVersionDirectivePosition(int position = 0, int line = -1)
@@ -636,6 +634,10 @@ bool QOpenGLShader::compileSourceCode(const char *source)
}
}
}
+ if (d->shaderType == Fragment) {
+ sourceChunks.append(blendEquationAdvancedHeader);
+ sourceChunkLengths.append(GLint(sizeof(blendEquationAdvancedHeader) - 1));
+ }
// The precision qualifiers are useful on OpenGL/ES systems,
// but usually not present on desktop systems.
@@ -791,7 +793,7 @@ public:
, linked(false)
, inited(false)
, removingShaders(false)
- , glfuncs(new QOpenGLFunctions)
+ , glfuncs(new QOpenGLExtraFunctions)
#ifndef QT_OPENGL_ES_2
, tessellationFuncs(0)
#endif
@@ -809,10 +811,9 @@ public:
QList<QOpenGLShader *> shaders;
QList<QOpenGLShader *> anonShaders;
- QOpenGLFunctions *glfuncs;
-
+ QOpenGLExtraFunctions *glfuncs;
#ifndef QT_OPENGL_ES_2
- // Tessellation shader support
+ // for tessellation features not in GLES 3.2
QOpenGLFunctions_4_0_Core *tessellationFuncs;
#endif
@@ -902,10 +903,7 @@ bool QOpenGLShaderProgram::init()
d->glfuncs->initializeOpenGLFunctions();
#ifndef QT_OPENGL_ES_2
- // Resolve OpenGL 4 functions for tessellation shader support
- QSurfaceFormat format = context->format();
- if (!context->isOpenGLES()
- && format.version() >= qMakePair<int, int>(4, 0)) {
+ if (!context->isOpenGLES() && context->format().version() >= qMakePair(4, 0)) {
d->tessellationFuncs = context->versionFunctions<QOpenGLFunctions_4_0_Core>();
d->tessellationFuncs->initializeOpenGLFunctions();
}
@@ -3497,13 +3495,8 @@ int QOpenGLShaderProgram::maxGeometryOutputVertices() const
*/
void QOpenGLShaderProgram::setPatchVertexCount(int count)
{
-#ifndef QT_OPENGL_ES_2
Q_D(QOpenGLShaderProgram);
- if (d->tessellationFuncs)
- d->tessellationFuncs->glPatchParameteri(GL_PATCH_VERTICES, count);
-#else
- Q_UNUSED(count);
-#endif
+ d->glfuncs->glPatchParameteri(GL_PATCH_VERTICES, count);
}
/*!
@@ -3516,15 +3509,10 @@ void QOpenGLShaderProgram::setPatchVertexCount(int count)
*/
int QOpenGLShaderProgram::patchVertexCount() const
{
-#ifndef QT_OPENGL_ES_2
int patchVertices = 0;
Q_D(const QOpenGLShaderProgram);
- if (d->tessellationFuncs)
- d->tessellationFuncs->glGetIntegerv(GL_PATCH_VERTICES, &patchVertices);
+ d->glfuncs->glGetIntegerv(GL_PATCH_VERTICES, &patchVertices);
return patchVertices;
-#else
- return 0;
-#endif
}
/*!
@@ -3542,6 +3530,9 @@ int QOpenGLShaderProgram::patchVertexCount() const
function when needed, as QOpenGLShaderProgram will not apply this for
you. This is purely a convenience function.
+ \note This function is only available with OpenGL >= 4.0 and is not supported
+ with OpenGL ES 3.2.
+
\sa defaultOuterTessellationLevels(), setDefaultInnerTessellationLevels()
*/
void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float> &levels)
@@ -3579,6 +3570,9 @@ void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float
\note This returns the global OpenGL state value. It is not specific to
this QOpenGLShaderProgram instance.
+ \note This function is only supported with OpenGL >= 4.0 and will not
+ return valid results with OpenGL ES 3.2.
+
\sa setDefaultOuterTessellationLevels(), defaultInnerTessellationLevels()
*/
QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const
@@ -3609,6 +3603,9 @@ QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const
function when needed, as QOpenGLShaderProgram will not apply this for
you. This is purely a convenience function.
+ \note This function is only available with OpenGL >= 4.0 and is not supported
+ with OpenGL ES 3.2.
+
\sa defaultInnerTessellationLevels(), setDefaultOuterTessellationLevels()
*/
void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float> &levels)
@@ -3646,6 +3643,9 @@ void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float
\note This returns the global OpenGL state value. It is not specific to
this QOpenGLShaderProgram instance.
+ \note This function is only supported with OpenGL >= 4.0 and will not
+ return valid results with OpenGL ES 3.2.
+
\sa setDefaultInnerTessellationLevels(), defaultOuterTessellationLevels()
*/
QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const
diff --git a/src/gui/opengl/qopengltexturecache.cpp b/src/gui/opengl/qopengltexturecache.cpp
index 27aa8db33a..8de0b25fee 100644
--- a/src/gui/opengl/qopengltexturecache.cpp
+++ b/src/gui/opengl/qopengltexturecache.cpp
@@ -38,39 +38,14 @@
****************************************************************************/
#include "qopengltexturecache_p.h"
+#include "qopengltextureuploader_p.h"
#include <qmath.h>
#include <qopenglfunctions.h>
-#include <private/qopenglcontext_p.h>
-#include <private/qopenglextensions_p.h>
#include <private/qimagepixmapcleanuphooks_p.h>
#include <qpa/qplatformpixmap.h>
QT_BEGIN_NAMESPACE
-#ifndef GL_RED
-#define GL_RED 0x1903
-#endif
-
-#ifndef GL_RGB10_A2
-#define GL_RGB10_A2 0x8059
-#endif
-
-#ifndef GL_BGR
-#define GL_BGR 0x80E0
-#endif
-
-#ifndef GL_BGRA
-#define GL_BGRA 0x80E1
-#endif
-
-#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
-#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
-#endif
-
-#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
-#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
-#endif
-
class QOpenGLTextureCacheWrapper
{
public:
@@ -130,7 +105,7 @@ QOpenGLTextureCache::~QOpenGLTextureCache()
{
}
-GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QPixmap &pixmap, BindOptions options)
+GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QPixmap &pixmap, QOpenGLTextureUploader::BindOptions options)
{
if (pixmap.isNull())
return 0;
@@ -153,7 +128,7 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QPixmap &
return id;
}
-GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &image, BindOptions options)
+GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &image, QOpenGLTextureUploader::BindOptions options)
{
if (image.isNull())
return 0;
@@ -170,16 +145,8 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &i
}
QImage img = image;
- if (!context->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures)) {
- // Scale the pixmap if needed. GL textures needs to have the
- // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL
- // 2.0 or use the GL_TEXTURE_RECTANGLE texture target
- int tx_w = qNextPowerOfTwo(image.width() - 1);
- int tx_h = qNextPowerOfTwo(image.height() - 1);
- if (tx_w != image.width() || tx_h != image.height()) {
- img = img.scaled(tx_w, tx_h);
- }
- }
+ if (!context->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures))
+ options |= QOpenGLTextureUploader::PowerOfTwoBindOption;
GLuint id = bindTexture(context, key, img, options);
if (id > 0)
@@ -188,164 +155,16 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &i
return id;
}
-GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, BindOptions options)
+GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, QOpenGLTextureUploader::BindOptions options)
{
GLuint id;
QOpenGLFunctions *funcs = context->functions();
funcs->glGenTextures(1, &id);
funcs->glBindTexture(GL_TEXTURE_2D, id);
- QImage tx;
- GLenum externalFormat;
- GLenum internalFormat;
- GLuint pixelType;
- QImage::Format targetFormat = QImage::Format_Invalid;
- const bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2);
-
- switch (image.format()) {
- case QImage::Format_RGB32:
- case QImage::Format_ARGB32:
- case QImage::Format_ARGB32_Premultiplied:
- if (isOpenGL12orBetter) {
- externalFormat = GL_BGRA;
- internalFormat = GL_RGBA;
- pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;
- } else {
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- // Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian.
- break;
-#endif
- if (static_cast<QOpenGLExtensions*>(context->functions())->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat)) {
- // GL_EXT_bgra or GL_EXT_texture_format_BGRA8888 extensions.
- if (context->isOpenGLES()) {
- // The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external.
- externalFormat = internalFormat = GL_BGRA;
- } else {
- // OpenGL BGRA/BGR format is not allowed as an internal format
- externalFormat = GL_BGRA;
- internalFormat = GL_RGBA;
- }
- pixelType = GL_UNSIGNED_BYTE;
- } else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
- // Is only allowed as an external format like OpenGL.
- externalFormat = GL_BGRA;
- internalFormat = GL_RGBA;
- pixelType = GL_UNSIGNED_BYTE;
- } else {
- // No support for direct ARGB32 upload.
- break;
- }
- }
- targetFormat = image.format();
- break;
- case QImage::Format_BGR30:
- case QImage::Format_A2BGR30_Premultiplied:
- if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3)) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- externalFormat = GL_RGBA;
- internalFormat = GL_RGB10_A2;
- targetFormat = image.format();
- }
- break;
- case QImage::Format_RGB30:
- case QImage::Format_A2RGB30_Premultiplied:
- if (isOpenGL12orBetter) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- externalFormat = GL_BGRA;
- internalFormat = GL_RGB10_A2;
- targetFormat = image.format();
- } else if (context->isOpenGLES() && context->format().majorVersion() >= 3) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- externalFormat = GL_RGBA;
- internalFormat = GL_RGB10_A2;
- targetFormat = QImage::Format_A2BGR30_Premultiplied;
- }
- break;
- case QImage::Format_RGB444:
- case QImage::Format_RGB555:
- case QImage::Format_RGB16:
- if (isOpenGL12orBetter || context->isOpenGLES()) {
- externalFormat = internalFormat = GL_RGB;
- pixelType = GL_UNSIGNED_SHORT_5_6_5;
- targetFormat = QImage::Format_RGB16;
- }
- break;
- case QImage::Format_RGB666:
- case QImage::Format_RGB888:
- externalFormat = internalFormat = GL_RGB;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = QImage::Format_RGB888;
- break;
- case QImage::Format_RGBX8888:
- case QImage::Format_RGBA8888:
- case QImage::Format_RGBA8888_Premultiplied:
- externalFormat = internalFormat = GL_RGBA;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- break;
- case QImage::Format_Indexed8:
- if (options & UseRedFor8BitBindOption) {
- externalFormat = internalFormat = GL_RED;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- }
- break;
- case QImage::Format_Alpha8:
- if (options & UseRedFor8BitBindOption) {
- externalFormat = internalFormat = GL_RED;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
- externalFormat = internalFormat = GL_ALPHA;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- }
- break;
- case QImage::Format_Grayscale8:
- if (options & UseRedFor8BitBindOption) {
- externalFormat = internalFormat = GL_RED;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
- externalFormat = internalFormat = GL_LUMINANCE;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- }
- break;
- default:
- break;
- }
-
- if (targetFormat == QImage::Format_Invalid) {
- externalFormat = internalFormat = GL_RGBA;
- pixelType = GL_UNSIGNED_BYTE;
- if (!image.hasAlphaChannel())
- targetFormat = QImage::Format_RGBX8888;
- else
- targetFormat = QImage::Format_RGBA8888;
- }
-
- if (options & PremultipliedAlphaBindOption) {
- if (targetFormat == QImage::Format_ARGB32)
- targetFormat = QImage::Format_ARGB32_Premultiplied;
- else if (targetFormat == QImage::Format_RGBA8888)
- targetFormat = QImage::Format_RGBA8888_Premultiplied;
- } else {
- if (targetFormat == QImage::Format_ARGB32_Premultiplied)
- targetFormat = QImage::Format_ARGB32;
- else if (targetFormat == QImage::Format_RGBA8888_Premultiplied)
- targetFormat = QImage::Format_RGBA8888;
- }
-
- if (image.format() != targetFormat)
- tx = image.convertToFormat(targetFormat);
- else
- tx = image;
-
- funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, const_cast<const QImage &>(tx).bits());
+ int cost = QOpenGLTextureUploader::textureImage(GL_TEXTURE_2D, image, options);
- int cost = tx.width() * tx.height() * tx.depth() / (1024 * 8);
- m_cache.insert(key, new QOpenGLCachedTexture(id, options, context), cost);
+ m_cache.insert(key, new QOpenGLCachedTexture(id, options, context), cost / 1024);
return id;
}
@@ -371,7 +190,7 @@ static void freeTexture(QOpenGLFunctions *funcs, GLuint id)
funcs->glDeleteTextures(1, &id);
}
-QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLTextureCache::BindOptions options, QOpenGLContext *context) : m_options(options)
+QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLTextureUploader::BindOptions options, QOpenGLContext *context) : m_options(options)
{
m_resource = new QOpenGLSharedResourceGuard(context, id, freeTexture);
}
diff --git a/src/gui/opengl/qopengltexturecache_p.h b/src/gui/opengl/qopengltexturecache_p.h
index b9d7df91e3..88ef06e744 100644
--- a/src/gui/opengl/qopengltexturecache_p.h
+++ b/src/gui/opengl/qopengltexturecache_p.h
@@ -56,6 +56,7 @@
#include <QObject>
#include <QCache>
#include <private/qopenglcontext_p.h>
+#include <private/qopengltextureuploader_p.h>
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
@@ -70,15 +71,10 @@ public:
QOpenGLTextureCache(QOpenGLContext *);
~QOpenGLTextureCache();
- enum BindOption {
- NoBindOption = 0x0000,
- PremultipliedAlphaBindOption = 0x0001,
- UseRedFor8BitBindOption = 0x0002,
- };
- Q_DECLARE_FLAGS(BindOptions, BindOption)
-
- GLuint bindTexture(QOpenGLContext *context, const QPixmap &pixmap, QOpenGLTextureCache::BindOptions options = PremultipliedAlphaBindOption);
- GLuint bindTexture(QOpenGLContext *context, const QImage &image, QOpenGLTextureCache::BindOptions options = PremultipliedAlphaBindOption);
+ GLuint bindTexture(QOpenGLContext *context, const QPixmap &pixmap,
+ QOpenGLTextureUploader::BindOptions options = QOpenGLTextureUploader::PremultipliedAlphaBindOption);
+ GLuint bindTexture(QOpenGLContext *context, const QImage &image,
+ QOpenGLTextureUploader::BindOptions options = QOpenGLTextureUploader::PremultipliedAlphaBindOption);
void invalidate(qint64 key);
@@ -86,26 +82,24 @@ public:
void freeResource(QOpenGLContext *ctx) override;
private:
- GLuint bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, QOpenGLTextureCache::BindOptions options);
+ GLuint bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, QOpenGLTextureUploader::BindOptions options);
QMutex m_mutex;
QCache<quint64, QOpenGLCachedTexture> m_cache;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLTextureCache::BindOptions)
-
class QOpenGLCachedTexture
{
public:
- QOpenGLCachedTexture(GLuint id, QOpenGLTextureCache::BindOptions options, QOpenGLContext *context);
+ QOpenGLCachedTexture(GLuint id, QOpenGLTextureUploader::BindOptions options, QOpenGLContext *context);
~QOpenGLCachedTexture() { m_resource->free(); }
GLuint id() const { return m_resource->id(); }
- QOpenGLTextureCache::BindOptions options() const { return m_options; }
+ QOpenGLTextureUploader::BindOptions options() const { return m_options; }
private:
QOpenGLSharedResourceGuard *m_resource;
- QOpenGLTextureCache::BindOptions m_options;
+ QOpenGLTextureUploader::BindOptions m_options;
};
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp
index 556d52ef99..e3cbba955d 100644
--- a/src/gui/opengl/qopengltextureglyphcache.cpp
+++ b/src/gui/opengl/qopengltextureglyphcache.cpp
@@ -344,15 +344,25 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height)
{
QString source;
+#ifdef Q_OS_WASM
+ source.append(QLatin1String(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader));
+ source.append(QLatin1String(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader));
+#else
source.append(QLatin1String(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader));
source.append(QLatin1String(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader));
+#endif
m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, source);
}
{
QString source;
+#ifdef Q_OS_WASM
+ source.append(QLatin1String(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader));
+ source.append(QLatin1String(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader));
+#else
source.append(QLatin1String(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader));
source.append(QLatin1String(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader));
+#endif
m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, source);
}
diff --git a/src/gui/opengl/qopengltextureuploader.cpp b/src/gui/opengl/qopengltextureuploader.cpp
new file mode 100644
index 0000000000..2428baed93
--- /dev/null
+++ b/src/gui/opengl/qopengltextureuploader.cpp
@@ -0,0 +1,328 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopengltextureuploader_p.h"
+
+#include <qimage.h>
+#include <qmath.h>
+#include <qopenglfunctions.h>
+#include <private/qopenglcontext_p.h>
+#include <private/qopenglextensions_p.h>
+
+#ifndef GL_RED
+#define GL_RED 0x1903
+#endif
+
+#ifndef GL_GREEN
+#define GL_GREEN 0x1904
+#endif
+
+#ifndef GL_BLUE
+#define GL_BLUE 0x1905
+#endif
+
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2 0x8059
+#endif
+
+#ifndef GL_RGBA16
+#define GL_RGBA16 0x805B
+#endif
+
+#ifndef GL_BGRA
+#define GL_BGRA 0x80E1
+#endif
+
+#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#endif
+
+#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#endif
+
+#ifndef GL_TEXTURE_SWIZZLE_RGBA
+#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+#endif
+
+#ifndef GL_SRGB
+#define GL_SRGB 0x8C40
+#endif
+#ifndef GL_SRGB_ALPHA
+#define GL_SRGB_ALPHA 0x8C42
+#endif
+
+QT_BEGIN_NAMESPACE
+
+qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &image, QOpenGLTextureUploader::BindOptions options, QSize maxSize)
+{
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ QOpenGLExtensions *funcs = static_cast<QOpenGLExtensions*>(context->functions());
+
+ QImage tx;
+ GLenum externalFormat;
+ GLenum internalFormat;
+ GLuint pixelType;
+ QImage::Format targetFormat = QImage::Format_Invalid;
+ const bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2);
+ const bool isOpenGLES3orBetter = context->isOpenGLES() && context->format().majorVersion() >= 3;
+ const bool sRgbBinding = (options & SRgbBindOption);
+ Q_ASSERT(isOpenGL12orBetter || context->isOpenGLES());
+ Q_ASSERT((options & (SRgbBindOption | UseRedFor8BitBindOption)) != (SRgbBindOption | UseRedFor8BitBindOption));
+
+ switch (image.format()) {
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ if (isOpenGL12orBetter) {
+ externalFormat = GL_BGRA;
+ internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;
+ } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle) && false) {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ GLint swizzle[4] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
+ funcs->glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+#else
+ GLint swizzle[4] = { GL_GREEN, GL_BLUE, GL_ALPHA, GL_RED };
+ funcs->glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+#endif
+ externalFormat = internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_BYTE;
+ } else {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ // Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian.
+ if (funcs->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat) && !sRgbBinding) {
+ // The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external.
+ externalFormat = internalFormat = GL_BGRA;
+ pixelType = GL_UNSIGNED_BYTE;
+ } else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
+ // Is only allowed as an external format like OpenGL.
+ externalFormat = GL_BGRA;
+ internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_BYTE;
+ } else {
+ // No support for direct ARGB32 upload.
+ break;
+ }
+#else
+ // Big endian requires GL_UNSIGNED_INT_8_8_8_8_REV for ARGB to match BGRA
+ break;
+#endif
+ }
+ targetFormat = image.format();
+ break;
+ case QImage::Format_BGR30:
+ case QImage::Format_A2BGR30_Premultiplied:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (isOpenGL12orBetter || isOpenGLES3orBetter) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ externalFormat = GL_RGBA;
+ internalFormat = GL_RGB10_A2;
+ targetFormat = image.format();
+ }
+ break;
+ case QImage::Format_RGB30:
+ case QImage::Format_A2RGB30_Premultiplied:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (isOpenGL12orBetter) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ externalFormat = GL_BGRA;
+ internalFormat = GL_RGB10_A2;
+ targetFormat = image.format();
+ } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle) && (isOpenGL12orBetter || isOpenGLES3orBetter)) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ externalFormat = GL_RGBA;
+ internalFormat = GL_RGB10_A2;
+ GLint swizzle[4] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
+ funcs->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+ targetFormat = image.format();
+ }
+ break;
+ case QImage::Format_RGB444:
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB16:
+ if (isOpenGL12orBetter || context->isOpenGLES()) {
+ externalFormat = internalFormat = GL_RGB;
+ pixelType = GL_UNSIGNED_SHORT_5_6_5;
+ targetFormat = QImage::Format_RGB16;
+ }
+ break;
+ case QImage::Format_RGB666:
+ case QImage::Format_RGB888:
+ externalFormat = internalFormat = GL_RGB;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = QImage::Format_RGB888;
+ break;
+ case QImage::Format_RGBX8888:
+ case QImage::Format_RGBA8888:
+ case QImage::Format_RGBA8888_Premultiplied:
+ externalFormat = internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ break;
+ case QImage::Format_RGBX64:
+ case QImage::Format_RGBA64:
+ case QImage::Format_RGBA64_Premultiplied:
+ externalFormat = internalFormat = GL_RGBA;
+ if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3))
+ internalFormat = GL_RGBA16;
+ pixelType = GL_UNSIGNED_SHORT;
+ targetFormat = image.format();
+ break;
+ case QImage::Format_Indexed8:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (options & UseRedFor8BitBindOption) {
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ }
+ break;
+ case QImage::Format_Alpha8:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (options & UseRedFor8BitBindOption) {
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
+ externalFormat = internalFormat = GL_ALPHA;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
+ GLint swizzle[4] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
+ funcs->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ }
+ break;
+ case QImage::Format_Grayscale8:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (options & UseRedFor8BitBindOption) {
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
+ externalFormat = internalFormat = GL_LUMINANCE;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
+ GLint swizzle[4] = { GL_RED, GL_RED, GL_RED, GL_ONE };
+ funcs->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ }
+ break;
+ default:
+ break;
+ }
+
+ // If no direct upload was detected above, convert to RGBA8888 and upload that
+ if (targetFormat == QImage::Format_Invalid) {
+ externalFormat = internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_BYTE;
+ if (!image.hasAlphaChannel())
+ targetFormat = QImage::Format_RGBX8888;
+ else
+ targetFormat = QImage::Format_RGBA8888;
+ }
+
+ if (options & PremultipliedAlphaBindOption) {
+ if (targetFormat == QImage::Format_ARGB32)
+ targetFormat = QImage::Format_ARGB32_Premultiplied;
+ else if (targetFormat == QImage::Format_RGBA8888)
+ targetFormat = QImage::Format_RGBA8888_Premultiplied;
+ else if (targetFormat == QImage::Format_RGBA64)
+ targetFormat = QImage::Format_RGBA64_Premultiplied;
+ } else {
+ if (targetFormat == QImage::Format_ARGB32_Premultiplied)
+ targetFormat = QImage::Format_ARGB32;
+ else if (targetFormat == QImage::Format_RGBA8888_Premultiplied)
+ targetFormat = QImage::Format_RGBA8888;
+ else if (targetFormat == QImage::Format_RGBA64_Premultiplied)
+ targetFormat = QImage::Format_RGBA64;
+ }
+
+ if (sRgbBinding) {
+ Q_ASSERT(internalFormat == GL_RGBA || internalFormat == GL_RGB);
+ if (image.hasAlphaChannel())
+ internalFormat = GL_SRGB_ALPHA;
+ else
+ internalFormat = GL_SRGB;
+ }
+
+ if (image.format() != targetFormat)
+ tx = image.convertToFormat(targetFormat);
+ else
+ tx = image;
+
+ QSize newSize = tx.size();
+ if (!maxSize.isEmpty())
+ newSize = newSize.boundedTo(maxSize);
+ if (options & PowerOfTwoBindOption) {
+ newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1));
+ newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1));
+ }
+
+ if (newSize != tx.size())
+ tx = tx.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+ // Handle cases where the QImage is actually a sub image of its image data:
+ qsizetype naturalBpl = ((qsizetype(tx.width()) * tx.depth() + 31) >> 5) << 2;
+ if (tx.bytesPerLine() != naturalBpl)
+ tx = tx.copy(tx.rect());
+
+ funcs->glTexImage2D(target, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, tx.constBits());
+
+ qsizetype cost = qint64(tx.width()) * tx.height() * tx.depth() / 8;
+
+ return cost;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopengltextureuploader_p.h b/src/gui/opengl/qopengltextureuploader_p.h
new file mode 100644
index 0000000000..d758b3787b
--- /dev/null
+++ b/src/gui/opengl/qopengltextureuploader_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QOPENGLTEXTUREUPLOADER_P_H
+#define QOPENGLTEXTUREUPLOADER_P_H
+
+#include <QtCore/qsize.h>
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtGui/private/qopenglcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QImage;
+
+class Q_GUI_EXPORT QOpenGLTextureUploader
+{
+public:
+ enum BindOption {
+ NoBindOption = 0x0000,
+ PremultipliedAlphaBindOption = 0x0001,
+ UseRedFor8BitBindOption = 0x0002,
+ SRgbBindOption = 0x0004,
+ PowerOfTwoBindOption = 0x0008
+ };
+ Q_DECLARE_FLAGS(BindOptions, BindOption)
+ Q_FLAGS(BindOptions)
+
+ static qsizetype textureImage(GLenum target, const QImage &image, BindOptions options, QSize maxSize = QSize());
+
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLTextureUploader::BindOptions)
+
+QT_END_NAMESPACE
+
+#endif
+