Avoid using direct OpenGL calls in gui and widgets

Change-Id: I5d88a2e204ca23e178a4e3044b9cb13392c3e763
Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
This commit is contained in:
Laszlo Agocs 2014-03-04 15:06:36 +01:00 committed by The Qt Project
parent 11eb9d37dc
commit 1e8de50674
18 changed files with 444 additions and 337 deletions

View File

@ -334,17 +334,18 @@ int QOpenGLContextPrivate::maxTextureSize()
if (max_texture_size != -1) if (max_texture_size != -1)
return max_texture_size; return max_texture_size;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); Q_Q(QOpenGLContext);
QOpenGLFunctions *funcs = q->functions();
funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
#ifndef QT_OPENGL_ES #ifndef QT_OPENGL_ES
Q_Q(QOpenGLContext);
if (!q->isES()) { if (!q->isES()) {
GLenum proxy = GL_PROXY_TEXTURE_2D; GLenum proxy = GL_PROXY_TEXTURE_2D;
GLint size; GLint size;
GLint next = 64; GLint next = 64;
glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); funcs->glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size); funcs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size);
if (size == 0) { if (size == 0) {
return max_texture_size; return max_texture_size;
} }
@ -354,8 +355,8 @@ int QOpenGLContextPrivate::maxTextureSize()
if (next > max_texture_size) if (next > max_texture_size)
break; break;
glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); funcs->glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next); funcs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next);
} while (next > size); } while (next > size);
max_texture_size = size; max_texture_size = size;
@ -864,7 +865,7 @@ void QOpenGLContext::swapBuffers(QSurface *surface)
qWarning() << "QOpenGLContext::swapBuffers() called without corresponding makeCurrent()"; qWarning() << "QOpenGLContext::swapBuffers() called without corresponding makeCurrent()";
#endif #endif
if (surface->format().swapBehavior() == QSurfaceFormat::SingleBuffer) if (surface->format().swapBehavior() == QSurfaceFormat::SingleBuffer)
glFlush(); functions()->glFlush();
d->platformGLContext->swapBuffers(surfaceHandle); d->platformGLContext->swapBuffers(surfaceHandle);
} }

View File

@ -53,7 +53,9 @@ typedef const GLubyte * (QOPENGLF_APIENTRYP qt_glGetStringi)(GLenum, GLuint);
QOpenGLExtensionMatcher::QOpenGLExtensionMatcher() QOpenGLExtensionMatcher::QOpenGLExtensionMatcher()
{ {
const char *extensionStr = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); QOpenGLContext *ctx = QOpenGLContext::currentContext();
QOpenGLFunctions *funcs = ctx->functions();
const char *extensionStr = reinterpret_cast<const char *>(funcs->glGetString(GL_EXTENSIONS));
if (extensionStr) { if (extensionStr) {
QByteArray ba(extensionStr); QByteArray ba(extensionStr);
@ -64,9 +66,8 @@ QOpenGLExtensionMatcher::QOpenGLExtensionMatcher()
#else #else
} else { } else {
// clear error state // clear error state
while (glGetError()) {} while (funcs->glGetError()) {}
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx) { if (ctx) {
qt_glGetStringi glGetStringi = (qt_glGetStringi)ctx->getProcAddress("glGetStringi"); qt_glGetStringi glGetStringi = (qt_glGetStringi)ctx->getProcAddress("glGetStringi");
@ -74,7 +75,7 @@ QOpenGLExtensionMatcher::QOpenGLExtensionMatcher()
return; return;
GLint numExtensions; GLint numExtensions;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); funcs->glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
for (int i = 0; i < numExtensions; ++i) { for (int i = 0; i < numExtensions; ++i) {
const char *str = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i)); const char *str = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));

View File

@ -66,7 +66,7 @@
// which the system headers do not. // which the system headers do not.
#if defined(QT_OPENGL_ES_2) #if defined(QT_OPENGL_ES_2)
# if defined(Q_OS_MAC) # if defined(Q_OS_MAC) // iOS
# include <OpenGLES/ES2/gl.h> # include <OpenGLES/ES2/gl.h>
# include <OpenGLES/ES2/glext.h> # include <OpenGLES/ES2/glext.h>
@ -78,7 +78,7 @@
*/ */
typedef void* GLeglImageOES; typedef void* GLeglImageOES;
# else // "uncontrolled" platforms # else // "uncontrolled" ES2 platforms
# include <GLES2/gl2.h> # include <GLES2/gl2.h>
/* /*
@ -90,14 +90,14 @@ typedef void* GLeglImageOES;
typedef char GLchar; typedef char GLchar;
# include <QtGui/qopengles2ext.h> # include <QtGui/qopengles2ext.h>
# ifndef GL_DOUBLE
# define GL_DOUBLE GL_FLOAT
# endif
# ifndef GLdouble
typedef GLfloat GLdouble;
# endif
# endif // Q_OS_MAC # endif // Q_OS_MAC
#else # ifndef GL_DOUBLE
# define GL_DOUBLE GL_FLOAT
# endif
# ifndef GLdouble
typedef GLfloat GLdouble;
# endif
#else // non-ES2 platforms
# if defined(Q_OS_MAC) # if defined(Q_OS_MAC)
# include <OpenGL/gl.h> # include <OpenGL/gl.h>
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 # if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
@ -110,7 +110,7 @@ typedef GLfloat GLdouble;
# include <GL/gl.h> # include <GL/gl.h>
# include <QtGui/qopenglext.h> # include <QtGui/qopenglext.h>
# endif // Q_OS_MAC # endif // Q_OS_MAC
#endif #endif // QT_OPENGL_ES_2
// Desktops, apart from Mac OS X prior to 10.7 can support OpenGL 3 // Desktops, apart from Mac OS X prior to 10.7 can support OpenGL 3
// and desktops apart from Mac can support OpenGL 4 // and desktops apart from Mac can support OpenGL 4

View File

@ -337,9 +337,9 @@ bool QOpenGLBuffer::read(int offset, void *data, int count)
Q_D(QOpenGLBuffer); Q_D(QOpenGLBuffer);
if (!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id()) if (!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id())
return false; return false;
while (glGetError() != GL_NO_ERROR) ; // Clear error state. while (d->funcs->glGetError() != GL_NO_ERROR) ; // Clear error state.
d->funcs->glGetBufferSubData(d->type, offset, count, data); d->funcs->glGetBufferSubData(d->type, offset, count, data);
return glGetError() == GL_NO_ERROR; return d->funcs->glGetError() == GL_NO_ERROR;
} }
#else #else
Q_UNUSED(offset); Q_UNUSED(offset);

View File

@ -43,6 +43,7 @@
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
#include <QtCore/qvarlengtharray.h> #include <QtCore/qvarlengtharray.h>
#include <QtGui/qopengl.h> #include <QtGui/qopengl.h>
#include <QtGui/qopenglfunctions.h>
#include "qopengldebug.h" #include "qopengldebug.h"
@ -1380,7 +1381,7 @@ bool QOpenGLDebugLogger::initialize()
#undef GET_DEBUG_PROC_ADDRESS #undef GET_DEBUG_PROC_ADDRESS
glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &d->maxMessageLength); QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &d->maxMessageLength);
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
if (!d->context->format().testOption(QSurfaceFormat::DebugContext)) { if (!d->context->format().testOption(QSurfaceFormat::DebugContext)) {
@ -1448,15 +1449,16 @@ void QOpenGLDebugLogger::startLogging(QOpenGLDebugLogger::LoggingMode loggingMod
d->glDebugMessageCallback(&qt_opengl_debug_callback, d); d->glDebugMessageCallback(&qt_opengl_debug_callback, d);
d->debugWasEnabled = glIsEnabled(GL_DEBUG_OUTPUT); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
d->syncDebugWasEnabled = glIsEnabled(GL_DEBUG_OUTPUT_SYNCHRONOUS); d->debugWasEnabled = funcs->glIsEnabled(GL_DEBUG_OUTPUT);
d->syncDebugWasEnabled = funcs->glIsEnabled(GL_DEBUG_OUTPUT_SYNCHRONOUS);
if (d->loggingMode == SynchronousLogging) if (d->loggingMode == SynchronousLogging)
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); funcs->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
else else
glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS); funcs->glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glEnable(GL_DEBUG_OUTPUT); funcs->glEnable(GL_DEBUG_OUTPUT);
} }
/*! /*!
@ -1485,13 +1487,14 @@ void QOpenGLDebugLogger::stopLogging()
d->glDebugMessageCallback(d->oldDebugCallbackFunction, d->oldDebugCallbackParameter); d->glDebugMessageCallback(d->oldDebugCallbackFunction, d->oldDebugCallbackParameter);
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (!d->debugWasEnabled) if (!d->debugWasEnabled)
glDisable(GL_DEBUG_OUTPUT); funcs->glDisable(GL_DEBUG_OUTPUT);
if (d->syncDebugWasEnabled) if (d->syncDebugWasEnabled)
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); funcs->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
else else
glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS); funcs->glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
} }
/*! /*!

View File

@ -57,11 +57,11 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
#define QT_RESET_GLERROR() \ #define QT_RESET_GLERROR() \
{ \ { \
while (glGetError() != GL_NO_ERROR) {} \ while (QOpenGLContext::currentContext()->functions()->glGetError() != GL_NO_ERROR) {} \
} }
#define QT_CHECK_GLERROR() \ #define QT_CHECK_GLERROR() \
{ \ { \
GLenum err = glGetError(); \ GLenum err = QOpenGLContext::currentContext()->functions()->glGetError(); \
if (err != GL_NO_ERROR) { \ if (err != GL_NO_ERROR) { \
qDebug("[%s line %d] OpenGL Error: %d", \ qDebug("[%s line %d] OpenGL Error: %d", \
__FILE__, __LINE__, (int)err); \ __FILE__, __LINE__, (int)err); \
@ -405,9 +405,9 @@ namespace
funcs->glDeleteRenderbuffers(1, &id); funcs->glDeleteRenderbuffers(1, &id);
} }
void freeTextureFunc(QOpenGLFunctions *, GLuint id) void freeTextureFunc(QOpenGLFunctions *funcs, GLuint id)
{ {
glDeleteTextures(1, &id); funcs->glDeleteTextures(1, &id);
} }
} }
@ -432,7 +432,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
#ifndef QT_OPENGL_ES_2 #ifndef QT_OPENGL_ES_2
GLint maxSamples; GLint maxSamples;
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); funcs.glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
samples = qBound(0, int(samples), int(maxSamples)); samples = qBound(0, int(samples), int(maxSamples));
#endif #endif
@ -497,16 +497,16 @@ void QOpenGLFramebufferObjectPrivate::initTexture(GLenum target, GLenum internal
QOpenGLContext *ctx = QOpenGLContext::currentContext(); QOpenGLContext *ctx = QOpenGLContext::currentContext();
GLuint texture = 0; GLuint texture = 0;
glGenTextures(1, &texture); funcs.glGenTextures(1, &texture);
glBindTexture(target, texture); funcs.glBindTexture(target, texture);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0, funcs.glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL); GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if (mipmap) { if (mipmap) {
int width = size.width(); int width = size.width();
int height = size.height(); int height = size.height();
@ -515,20 +515,20 @@ void QOpenGLFramebufferObjectPrivate::initTexture(GLenum target, GLenum internal
width = qMax(1, width >> 1); width = qMax(1, width >> 1);
height = qMax(1, height >> 1); height = qMax(1, height >> 1);
++level; ++level;
glTexImage2D(target, level, internal_format, width, height, 0, funcs.glTexImage2D(target, level, internal_format, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL); GL_RGBA, GL_UNSIGNED_BYTE, NULL);
} }
} }
funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
target, texture, 0); target, texture, 0);
QT_CHECK_GLERROR(); QT_CHECK_GLERROR();
glBindTexture(target, 0); funcs.glBindTexture(target, 0);
valid = checkFramebufferStatus(ctx); valid = checkFramebufferStatus(ctx);
if (valid) if (valid)
texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc); texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
else else
glDeleteTextures(1, &texture); funcs.glDeleteTextures(1, &texture);
} }
void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment) void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment)
@ -1084,7 +1084,8 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
int w = size.width(); int w = size.width();
int h = size.height(); int h = size.height();
while (glGetError()); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
while (funcs->glGetError());
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied
@ -1094,14 +1095,14 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
#else #else
GLint fmt = GL_BGRA; GLint fmt = GL_BGRA;
#endif #endif
glReadPixels(0, 0, w, h, fmt, GL_UNSIGNED_BYTE, img.bits()); funcs->glReadPixels(0, 0, w, h, fmt, GL_UNSIGNED_BYTE, img.bits());
if (!glGetError()) if (!funcs->glGetError())
return img.mirrored(); return img.mirrored();
#endif #endif
QImage rgbaImage(size, (alpha_format && include_alpha) ? QImage::Format_RGBA8888_Premultiplied QImage rgbaImage(size, (alpha_format && include_alpha) ? QImage::Format_RGBA8888_Premultiplied
: QImage::Format_RGBX8888); : QImage::Format_RGBX8888);
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaImage.bits()); funcs->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaImage.bits());
return rgbaImage.mirrored(); return rgbaImage.mirrored();
} }

View File

@ -1992,6 +1992,12 @@ void QOpenGLFunctions::initializeOpenGLFunctions()
This convenience function will do nothing on OpenGL/ES 1.x systems. This convenience function will do nothing on OpenGL/ES 1.x systems.
*/ */
/*!
\fn void QOpenGLFunctions::glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
\internal
*/
/*! /*!
\fn bool QOpenGLFunctions::isInitialized(const QOpenGLFunctionsPrivate *d) \fn bool QOpenGLFunctions::isInitialized(const QOpenGLFunctionsPrivate *d)
\internal \internal
@ -2394,6 +2400,15 @@ static void QOPENGLF_APIENTRY qopenglfResolveClearColor(GLclampf red, GLclampf g
RESOLVE_FUNC_VOID(0, ClearColor)(red, green, blue, alpha); RESOLVE_FUNC_VOID(0, ClearColor)(red, green, blue, alpha);
} }
static void QOPENGLF_APIENTRY qopenglfResolveClearDepthf(GLclampf depth)
{
if (QOpenGLContext::currentContext()->isES()) {
RESOLVE_FUNC_VOID(0, ClearDepthf)(depth);
} else {
RESOLVE_FUNC_VOID(0, ClearDepth)((GLdouble) depth);
}
}
static void QOPENGLF_APIENTRY qopenglfResolveClearStencil(GLint s) static void QOPENGLF_APIENTRY qopenglfResolveClearStencil(GLint s)
{ {
RESOLVE_FUNC_VOID(0, ClearStencil)(s); RESOLVE_FUNC_VOID(0, ClearStencil)(s);
@ -2434,6 +2449,15 @@ static void QOPENGLF_APIENTRY qopenglfResolveDepthMask(GLboolean flag)
RESOLVE_FUNC_VOID(0, DepthMask)(flag); RESOLVE_FUNC_VOID(0, DepthMask)(flag);
} }
static void QOPENGLF_APIENTRY qopenglfResolveDepthRangef(GLclampf zNear, GLclampf zFar)
{
if (QOpenGLContext::currentContext()->isES()) {
RESOLVE_FUNC_VOID(0, DepthRangef)(zNear, zFar);
} else {
RESOLVE_FUNC_VOID(0, DepthRange)((GLdouble) zNear, (GLdouble) zFar);
}
}
static void QOPENGLF_APIENTRY qopenglfResolveDisable(GLenum cap) static void QOPENGLF_APIENTRY qopenglfResolveDisable(GLenum cap)
{ {
RESOLVE_FUNC_VOID(0, Disable)(cap); RESOLVE_FUNC_VOID(0, Disable)(cap);
@ -3131,6 +3155,29 @@ static void QOPENGLF_APIENTRY qopenglfResolveGetBufferSubData(GLenum target, qop
(target, offset, size, data); (target, offset, size, data);
} }
#if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_DYNAMIC)
// Desktop only
static void QOPENGLF_APIENTRY qopenglfResolveGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
{
RESOLVE_FUNC_VOID(0, GetTexLevelParameteriv)(target, level, pname, params);
}
// Special translation functions for ES-specific calls on desktop GL
static void QOPENGLF_APIENTRY qopenglfTranslateClearDepthf(GLclampf depth)
{
::glClearDepth(depth);
}
static void QOPENGLF_APIENTRY qopenglfTranslateDepthRangef(GLclampf zNear, GLclampf zFar)
{
::glDepthRange(zNear, zFar);
}
#endif // !ES2 && !DYNAMIC
QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *) QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *)
{ {
/* Assign a pointer to an above defined static function /* Assign a pointer to an above defined static function
@ -3145,6 +3192,7 @@ QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *)
BlendFunc = qopenglfResolveBlendFunc; BlendFunc = qopenglfResolveBlendFunc;
Clear = qopenglfResolveClear; Clear = qopenglfResolveClear;
ClearColor = qopenglfResolveClearColor; ClearColor = qopenglfResolveClearColor;
ClearDepthf = qopenglfResolveClearDepthf;
ClearStencil = qopenglfResolveClearStencil; ClearStencil = qopenglfResolveClearStencil;
ColorMask = qopenglfResolveColorMask; ColorMask = qopenglfResolveColorMask;
CopyTexImage2D = qopenglfResolveCopyTexImage2D; CopyTexImage2D = qopenglfResolveCopyTexImage2D;
@ -3153,6 +3201,7 @@ QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *)
DeleteTextures = qopenglfResolveDeleteTextures; DeleteTextures = qopenglfResolveDeleteTextures;
DepthFunc = qopenglfResolveDepthFunc; DepthFunc = qopenglfResolveDepthFunc;
DepthMask = qopenglfResolveDepthMask; DepthMask = qopenglfResolveDepthMask;
DepthRangef = qopenglfResolveDepthRangef;
Disable = qopenglfResolveDisable; Disable = qopenglfResolveDisable;
DrawArrays = qopenglfResolveDrawArrays; DrawArrays = qopenglfResolveDrawArrays;
DrawElements = qopenglfResolveDrawElements; DrawElements = qopenglfResolveDrawElements;
@ -3186,6 +3235,8 @@ QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *)
TexParameteriv = qopenglfResolveTexParameteriv; TexParameteriv = qopenglfResolveTexParameteriv;
TexSubImage2D = qopenglfResolveTexSubImage2D; TexSubImage2D = qopenglfResolveTexSubImage2D;
Viewport = qopenglfResolveViewport; Viewport = qopenglfResolveViewport;
GetTexLevelParameteriv = qopenglfResolveGetTexLevelParameteriv;
} else { } else {
#ifndef QT_OPENGL_DYNAMIC #ifndef QT_OPENGL_DYNAMIC
// Use the functions directly. This requires linking QtGui to an OpenGL implementation. // Use the functions directly. This requires linking QtGui to an OpenGL implementation.
@ -3193,6 +3244,7 @@ QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *)
BlendFunc = ::glBlendFunc; BlendFunc = ::glBlendFunc;
Clear = ::glClear; Clear = ::glClear;
ClearColor = ::glClearColor; ClearColor = ::glClearColor;
ClearDepthf = qopenglfTranslateClearDepthf;
ClearStencil = ::glClearStencil; ClearStencil = ::glClearStencil;
ColorMask = ::glColorMask; ColorMask = ::glColorMask;
CopyTexImage2D = ::glCopyTexImage2D; CopyTexImage2D = ::glCopyTexImage2D;
@ -3201,6 +3253,7 @@ QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *)
DeleteTextures = ::glDeleteTextures; DeleteTextures = ::glDeleteTextures;
DepthFunc = ::glDepthFunc; DepthFunc = ::glDepthFunc;
DepthMask = ::glDepthMask; DepthMask = ::glDepthMask;
DepthRangef = qopenglfTranslateDepthRangef;
Disable = ::glDisable; Disable = ::glDisable;
DrawArrays = ::glDrawArrays; DrawArrays = ::glDrawArrays;
DrawElements = ::glDrawElements; DrawElements = ::glDrawElements;
@ -3234,6 +3287,8 @@ QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *)
TexParameteriv = ::glTexParameteriv; TexParameteriv = ::glTexParameteriv;
TexSubImage2D = ::glTexSubImage2D; TexSubImage2D = ::glTexSubImage2D;
Viewport = ::glViewport; Viewport = ::glViewport;
GetTexLevelParameteriv = ::glGetTexLevelParameteriv;
#else // QT_OPENGL_DYNAMIC #else // QT_OPENGL_DYNAMIC
// This should not happen. // This should not happen.
qFatal("QOpenGLFunctions: Dynamic OpenGL builds do not support platforms with insufficient function resolving capabilities"); qFatal("QOpenGLFunctions: Dynamic OpenGL builds do not support platforms with insufficient function resolving capabilities");

View File

@ -223,6 +223,8 @@ struct QOpenGLFunctionsPrivate;
#undef glVertexAttrib4fv #undef glVertexAttrib4fv
#undef glVertexAttribPointer #undef glVertexAttribPointer
#undef glTexLevelParameteriv
class Q_GUI_EXPORT QOpenGLFunctions class Q_GUI_EXPORT QOpenGLFunctions
{ {
public: public:
@ -405,6 +407,9 @@ public:
void glVertexAttrib4fv(GLuint indx, const GLfloat* values); void glVertexAttrib4fv(GLuint indx, const GLfloat* values);
void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
// OpenGL1, not GLES2
void glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params);
protected: protected:
QOpenGLFunctionsPrivate *d_ptr; QOpenGLFunctionsPrivate *d_ptr;
static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; } static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; }
@ -420,6 +425,7 @@ struct QOpenGLFunctionsPrivate
void (QOPENGLF_APIENTRYP BlendFunc)(GLenum sfactor, GLenum dfactor); void (QOPENGLF_APIENTRYP BlendFunc)(GLenum sfactor, GLenum dfactor);
void (QOPENGLF_APIENTRYP Clear)(GLbitfield mask); void (QOPENGLF_APIENTRYP Clear)(GLbitfield mask);
void (QOPENGLF_APIENTRYP ClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); void (QOPENGLF_APIENTRYP ClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void (QOPENGLF_APIENTRYP ClearDepthf)(GLclampf depth);
void (QOPENGLF_APIENTRYP ClearStencil)(GLint s); void (QOPENGLF_APIENTRYP ClearStencil)(GLint s);
void (QOPENGLF_APIENTRYP ColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); void (QOPENGLF_APIENTRYP ColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
void (QOPENGLF_APIENTRYP CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); void (QOPENGLF_APIENTRYP CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
@ -428,6 +434,7 @@ struct QOpenGLFunctionsPrivate
void (QOPENGLF_APIENTRYP DeleteTextures)(GLsizei n, const GLuint* textures); void (QOPENGLF_APIENTRYP DeleteTextures)(GLsizei n, const GLuint* textures);
void (QOPENGLF_APIENTRYP DepthFunc)(GLenum func); void (QOPENGLF_APIENTRYP DepthFunc)(GLenum func);
void (QOPENGLF_APIENTRYP DepthMask)(GLboolean flag); void (QOPENGLF_APIENTRYP DepthMask)(GLboolean flag);
void (QOPENGLF_APIENTRYP DepthRangef)(GLclampf nearVal, GLclampf farVal);
void (QOPENGLF_APIENTRYP Disable)(GLenum cap); void (QOPENGLF_APIENTRYP Disable)(GLenum cap);
void (QOPENGLF_APIENTRYP DrawArrays)(GLenum mode, GLint first, GLsizei count); void (QOPENGLF_APIENTRYP DrawArrays)(GLenum mode, GLint first, GLsizei count);
void (QOPENGLF_APIENTRYP DrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); void (QOPENGLF_APIENTRYP DrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
@ -557,6 +564,13 @@ struct QOpenGLFunctionsPrivate
void (QOPENGLF_APIENTRYP VertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); void (QOPENGLF_APIENTRYP VertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void (QOPENGLF_APIENTRYP VertexAttrib4fv)(GLuint indx, const GLfloat* values); void (QOPENGLF_APIENTRYP VertexAttrib4fv)(GLuint indx, const GLfloat* values);
void (QOPENGLF_APIENTRYP VertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); void (QOPENGLF_APIENTRYP VertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
// OpenGL1 only, not GLES2
void (QOPENGLF_APIENTRYP GetTexLevelParameteriv)(GLenum target, GLint level, GLenum pname, GLint *params);
// Special non-ES OpenGL variants, not to be called directly
void (QOPENGLF_APIENTRYP ClearDepth)(GLdouble depth);
void (QOPENGLF_APIENTRYP DepthRange)(GLdouble zNear, GLdouble zFar);
}; };
// GLES2 + OpenGL1 common subset // GLES2 + OpenGL1 common subset
@ -1210,7 +1224,8 @@ inline GLenum QOpenGLFunctions::glCheckFramebufferStatus(GLenum target)
inline void QOpenGLFunctions::glClearDepthf(GLclampf depth) inline void QOpenGLFunctions::glClearDepthf(GLclampf depth)
{ {
#ifndef QT_OPENGL_ES #ifndef QT_OPENGL_ES
::glClearDepth(depth); Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->ClearDepthf(depth);
#else #else
::glClearDepthf(depth); ::glClearDepthf(depth);
#endif #endif
@ -1332,7 +1347,8 @@ inline void QOpenGLFunctions::glDeleteShader(GLuint shader)
inline void QOpenGLFunctions::glDepthRangef(GLclampf zNear, GLclampf zFar) inline void QOpenGLFunctions::glDepthRangef(GLclampf zNear, GLclampf zFar)
{ {
#ifndef QT_OPENGL_ES #ifndef QT_OPENGL_ES
::glDepthRange(zNear, zFar); Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->DepthRangef(zNear, zFar);
#else #else
::glDepthRangef(zNear, zFar); ::glDepthRangef(zNear, zFar);
#endif #endif
@ -2138,6 +2154,24 @@ inline void QOpenGLFunctions::glVertexAttribPointer(GLuint indx, GLint size, GLe
Q_OPENGL_FUNCTIONS_DEBUG Q_OPENGL_FUNCTIONS_DEBUG
} }
// OpenGL1, not GLES2
inline void QOpenGLFunctions::glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
{
#ifdef QT_OPENGL_ES_2
Q_UNUSED(target);
Q_UNUSED(level);
Q_UNUSED(pname);
Q_UNUSED(params);
// Cannot get here.
qFatal("QOpenGLFunctions: glGetTexLevelParameteriv not available with OpenGL ES");
#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->GetTexLevelParameteriv(target, level, pname, params);
#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
QT_END_NAMESPACE QT_END_NAMESPACE
#endif // QT_NO_OPENGL #endif // QT_NO_OPENGL

View File

@ -43,6 +43,7 @@
#include <private/qdrawhelper_p.h> #include <private/qdrawhelper_p.h>
#include <private/qopenglcontext_p.h> #include <private/qopenglcontext_p.h>
#include <QtCore/qmutex.h> #include <QtCore/qmutex.h>
#include <QtGui/qopenglfunctions.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -91,9 +92,10 @@ void QOpenGL2GradientCache::cleanCache()
{ {
QMutexLocker lock(&m_mutex); QMutexLocker lock(&m_mutex);
QOpenGLGradientColorTableHash::const_iterator it = cache.constBegin(); QOpenGLGradientColorTableHash::const_iterator it = cache.constBegin();
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
for (; it != cache.constEnd(); ++it) { for (; it != cache.constEnd(); ++it) {
const CacheInfo &cache_info = it.value(); const CacheInfo &cache_info = it.value();
glDeleteTextures(1, &cache_info.texId); funcs->glDeleteTextures(1, &cache_info.texId);
} }
cache.clear(); cache.clear();
} }
@ -129,6 +131,7 @@ GLuint QOpenGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity
GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)
{ {
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (cache.size() == maxCacheSize()) { if (cache.size() == maxCacheSize()) {
int elem_to_remove = qrand() % maxCacheSize(); int elem_to_remove = qrand() % maxCacheSize();
quint64 key = cache.keys()[elem_to_remove]; quint64 key = cache.keys()[elem_to_remove];
@ -136,7 +139,7 @@ GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient
// need to call glDeleteTextures on each removed cache entry: // need to call glDeleteTextures on each removed cache entry:
QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key); QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key);
do { do {
glDeleteTextures(1, &it.value().texId); funcs->glDeleteTextures(1, &it.value().texId);
} while (++it != cache.constEnd() && it.key() == key); } while (++it != cache.constEnd() && it.key() == key);
cache.remove(key); // may remove more than 1, but OK cache.remove(key); // may remove more than 1, but OK
} }
@ -144,10 +147,10 @@ GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient
CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode()); CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
uint buffer[1024]; uint buffer[1024];
generateGradientColorTable(gradient, buffer, paletteSize(), opacity); generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
glGenTextures(1, &cache_entry.texId); funcs->glGenTextures(1, &cache_entry.texId);
glBindTexture(GL_TEXTURE_2D, cache_entry.texId); funcs->glBindTexture(GL_TEXTURE_2D, cache_entry.texId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1, funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1,
0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
return cache.insert(hash_val, cache_entry).value().texId; return cache.insert(hash_val, cache_entry).value().texId;
} }

View File

@ -123,14 +123,14 @@ void QOpenGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wra
lastTextureUsed = id; lastTextureUsed = id;
if (smoothPixmapTransform) { if (smoothPixmapTransform) {
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else { } else {
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} }
glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode); funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode); funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode);
} }
@ -204,7 +204,7 @@ void QOpenGL2PaintEngineExPrivate::updateBrushTexture()
GLuint texId = QOpenGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); GLuint texId = QOpenGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0);
funcs.glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); funcs.glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, texId); funcs.glBindTexture(GL_TEXTURE_2D, texId);
if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient) if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient)
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
@ -439,43 +439,43 @@ void QOpenGL2PaintEngineExPrivate::updateCompositionMode()
// qDebug() << "QOpenGL2PaintEngineExPrivate::updateCompositionMode() - Setting GL composition mode for " << q->state()->composition_mode; // qDebug() << "QOpenGL2PaintEngineExPrivate::updateCompositionMode() - Setting GL composition mode for " << q->state()->composition_mode;
switch(q->state()->composition_mode) { switch(q->state()->composition_mode) {
case QPainter::CompositionMode_SourceOver: case QPainter::CompositionMode_SourceOver:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); funcs.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
break; break;
case QPainter::CompositionMode_DestinationOver: case QPainter::CompositionMode_DestinationOver:
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE); funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
break; break;
case QPainter::CompositionMode_Clear: case QPainter::CompositionMode_Clear:
glBlendFunc(GL_ZERO, GL_ZERO); funcs.glBlendFunc(GL_ZERO, GL_ZERO);
break; break;
case QPainter::CompositionMode_Source: case QPainter::CompositionMode_Source:
glBlendFunc(GL_ONE, GL_ZERO); funcs.glBlendFunc(GL_ONE, GL_ZERO);
break; break;
case QPainter::CompositionMode_Destination: case QPainter::CompositionMode_Destination:
glBlendFunc(GL_ZERO, GL_ONE); funcs.glBlendFunc(GL_ZERO, GL_ONE);
break; break;
case QPainter::CompositionMode_SourceIn: case QPainter::CompositionMode_SourceIn:
glBlendFunc(GL_DST_ALPHA, GL_ZERO); funcs.glBlendFunc(GL_DST_ALPHA, GL_ZERO);
break; break;
case QPainter::CompositionMode_DestinationIn: case QPainter::CompositionMode_DestinationIn:
glBlendFunc(GL_ZERO, GL_SRC_ALPHA); funcs.glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
break; break;
case QPainter::CompositionMode_SourceOut: case QPainter::CompositionMode_SourceOut:
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO); funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);
break; break;
case QPainter::CompositionMode_DestinationOut: case QPainter::CompositionMode_DestinationOut:
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); funcs.glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
break; break;
case QPainter::CompositionMode_SourceAtop: case QPainter::CompositionMode_SourceAtop:
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); funcs.glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break; break;
case QPainter::CompositionMode_DestinationAtop: case QPainter::CompositionMode_DestinationAtop:
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA); funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA);
break; break;
case QPainter::CompositionMode_Xor: case QPainter::CompositionMode_Xor:
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break; break;
case QPainter::CompositionMode_Plus: case QPainter::CompositionMode_Plus:
glBlendFunc(GL_ONE, GL_ONE); funcs.glBlendFunc(GL_ONE, GL_ONE);
break; break;
default: default:
qWarning("Unsupported composition mode"); qWarning("Unsupported composition mode");
@ -524,7 +524,7 @@ void QOpenGL2PaintEngineExPrivate::drawTexture(const QOpenGLRect& dest, const QO
setCoords(staticVertexCoordinateArray, dest); setCoords(staticVertexCoordinateArray, dest);
setCoords(staticTextureCoordinateArray, srcTextureRect); setCoords(staticTextureCoordinateArray, srcTextureRect);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
} }
void QOpenGL2PaintEngineEx::beginNativePainting() void QOpenGL2PaintEngineEx::beginNativePainting()
@ -541,37 +541,35 @@ void QOpenGL2PaintEngineEx::beginNativePainting()
for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
d->funcs.glDisableVertexAttribArray(i); d->funcs.glDisableVertexAttribArray(i);
#ifndef QT_OPENGL_ES_2 #if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_DYNAMIC)
if (!QOpenGLContext::currentContext()->isES()) { Q_ASSERT(QOpenGLContext::currentContext());
Q_ASSERT(QOpenGLContext::currentContext()); const QOpenGLContext *ctx = d->ctx;
const QOpenGLContext *ctx = d->ctx; const QSurfaceFormat &fmt = d->device->context()->format();
const QSurfaceFormat &fmt = d->device->context()->format(); if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1)
if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1) || (fmt.majorVersion() == 3 && fmt.minorVersion() == 1 && ctx->hasExtension(QByteArrayLiteral("GL_ARB_compatibility")))
|| (fmt.majorVersion() == 3 && fmt.minorVersion() == 1 && ctx->hasExtension(QByteArrayLiteral("GL_ARB_compatibility"))) || fmt.profile() == QSurfaceFormat::CompatibilityProfile)
|| fmt.profile() == QSurfaceFormat::CompatibilityProfile) {
{ // be nice to people who mix OpenGL 1.x code with QPainter commands
// be nice to people who mix OpenGL 1.x code with QPainter commands // by setting modelview and projection matrices to mirror the GL 1
// by setting modelview and projection matrices to mirror the GL 1 // paint engine
// paint engine const QTransform& mtx = state()->matrix;
const QTransform& mtx = state()->matrix;
float mv_matrix[4][4] = float mv_matrix[4][4] =
{ {
{ float(mtx.m11()), float(mtx.m12()), 0, float(mtx.m13()) }, { float(mtx.m11()), float(mtx.m12()), 0, float(mtx.m13()) },
{ float(mtx.m21()), float(mtx.m22()), 0, float(mtx.m23()) }, { float(mtx.m21()), float(mtx.m22()), 0, float(mtx.m23()) },
{ 0, 0, 1, 0 }, { 0, 0, 1, 0 },
{ float(mtx.dx()), float(mtx.dy()), 0, float(mtx.m33()) } { float(mtx.dx()), float(mtx.dy()), 0, float(mtx.m33()) }
}; };
const QSize sz = d->device->size(); const QSize sz = d->device->size();
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(&mv_matrix[0][0]); glLoadMatrixf(&mv_matrix[0][0]);
}
} }
#endif // QT_OPENGL_ES_2 #endif // QT_OPENGL_ES_2
@ -586,17 +584,17 @@ void QOpenGL2PaintEngineEx::beginNativePainting()
void QOpenGL2PaintEngineExPrivate::resetGLState() void QOpenGL2PaintEngineExPrivate::resetGLState()
{ {
glDisable(GL_BLEND); funcs.glDisable(GL_BLEND);
funcs.glActiveTexture(GL_TEXTURE0); funcs.glActiveTexture(GL_TEXTURE0);
glDisable(GL_STENCIL_TEST); funcs.glDisable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST); funcs.glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST); funcs.glDisable(GL_SCISSOR_TEST);
glDepthMask(true); funcs.glDepthMask(true);
glDepthFunc(GL_LESS); funcs.glDepthFunc(GL_LESS);
funcs.glClearDepthf(1); funcs.glClearDepthf(1);
glStencilMask(0xff); funcs.glStencilMask(0xff);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilFunc(GL_ALWAYS, 0, 0xff); funcs.glStencilFunc(GL_ALWAYS, 0, 0xff);
setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false); setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false);
setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false); setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false);
setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
@ -755,9 +753,9 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
cache->primitiveType = GL_TRIANGLE_FAN; cache->primitiveType = GL_TRIANGLE_FAN;
cache->iscale = inverseScale; cache->iscale = inverseScale;
#ifdef QT_OPENGL_CACHE_AS_VBOS #ifdef QT_OPENGL_CACHE_AS_VBOS
glGenBuffers(1, &cache->vbo); funcs.glGenBuffers(1, &cache->vbo);
glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW); funcs.glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW);
cache->ibo = 0; cache->ibo = 0;
#else #else
cache->vertices = (float *) malloc(floatSizeInBytes); cache->vertices = (float *) malloc(floatSizeInBytes);
@ -768,12 +766,12 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
prepareForDraw(currentBrush.isOpaque()); prepareForDraw(currentBrush.isOpaque());
#ifdef QT_OPENGL_CACHE_AS_VBOS #ifdef QT_OPENGL_CACHE_AS_VBOS
glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
#else #else
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
#endif #endif
glDrawArrays(cache->primitiveType, 0, cache->vertexCount); funcs.glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
} else { } else {
// printf(" - Marking path as cachable...\n"); // printf(" - Marking path as cachable...\n");
@ -833,10 +831,10 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
cache->iscale = inverseScale; cache->iscale = inverseScale;
cache->indexType = polys.indices.type(); cache->indexType = polys.indices.type();
#ifdef QT_OPENGL_CACHE_AS_VBOS #ifdef QT_OPENGL_CACHE_AS_VBOS
glGenBuffers(1, &cache->vbo); funcs.glGenBuffers(1, &cache->vbo);
glGenBuffers(1, &cache->ibo); funcs.glGenBuffers(1, &cache->ibo);
glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
if (polys.indices.type() == QVertexIndexVector::UnsignedInt) if (polys.indices.type() == QVertexIndexVector::UnsignedInt)
funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint32) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW); funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint32) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW);
@ -863,21 +861,21 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
prepareForDraw(currentBrush.isOpaque()); prepareForDraw(currentBrush.isOpaque());
#ifdef QT_OPENGL_CACHE_AS_VBOS #ifdef QT_OPENGL_CACHE_AS_VBOS
glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
if (cache->indexType == QVertexIndexVector::UnsignedInt) if (cache->indexType == QVertexIndexVector::UnsignedInt)
glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0); funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0);
else else
glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, 0); funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0); funcs.glBindBuffer(GL_ARRAY_BUFFER, 0);
#else #else
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
if (cache->indexType == QVertexIndexVector::UnsignedInt) if (cache->indexType == QVertexIndexVector::UnsignedInt)
glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, (qint32 *)cache->indices); funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, (qint32 *)cache->indices);
else else
glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, (qint16 *)cache->indices); funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, (qint16 *)cache->indices);
#endif #endif
} else { } else {
@ -904,9 +902,9 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
prepareForDraw(currentBrush.isOpaque()); prepareForDraw(currentBrush.isOpaque());
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData()); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData());
if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint)) if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint))
glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.data()); funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.data());
else else
glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_SHORT, polys.indices.data()); funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_SHORT, polys.indices.data());
} else { } else {
// We can't handle big, concave painter paths with OpenGL without stencil buffer. // We can't handle big, concave painter paths with OpenGL without stencil buffer.
qWarning("Painter path exceeds +/-32767 pixels."); qWarning("Painter path exceeds +/-32767 pixels.");
@ -920,24 +918,24 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
glStencilMask(0xff); funcs.glStencilMask(0xff);
glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
if (q->state()->clipTestEnabled) { if (q->state()->clipTestEnabled) {
// Pass when high bit is set, replace stencil value with current clip // Pass when high bit is set, replace stencil value with current clip
glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT);
} else if (path.hasWindingFill()) { } else if (path.hasWindingFill()) {
// Pass when any bit is set, replace stencil value with 0 // Pass when any bit is set, replace stencil value with 0
glStencilFunc(GL_NOTEQUAL, 0, 0xff); funcs.glStencilFunc(GL_NOTEQUAL, 0, 0xff);
} else { } else {
// Pass when high bit is set, replace stencil value with 0 // Pass when high bit is set, replace stencil value with 0
glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
} }
prepareForDraw(currentBrush.isOpaque()); prepareForDraw(currentBrush.isOpaque());
// Stencil the brush onto the dest buffer // Stencil the brush onto the dest buffer
composite(vertexCoordinateArray.boundingRect()); composite(vertexCoordinateArray.boundingRect());
glStencilMask(0); funcs.glStencilMask(0);
updateClipScissorTest(); updateClipScissorTest();
} }
} }
@ -954,16 +952,16 @@ void QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
Q_ASSERT(count || stops); Q_ASSERT(count || stops);
// qDebug("QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); // qDebug("QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray()");
glStencilMask(0xff); // Enable stencil writes funcs.glStencilMask(0xff); // Enable stencil writes
if (dirtyStencilRegion.intersects(currentScissorBounds)) { if (dirtyStencilRegion.intersects(currentScissorBounds)) {
QVector<QRect> clearRegion = dirtyStencilRegion.intersected(currentScissorBounds).rects(); QVector<QRect> clearRegion = dirtyStencilRegion.intersected(currentScissorBounds).rects();
glClearStencil(0); // Clear to zero funcs.glClearStencil(0); // Clear to zero
for (int i = 0; i < clearRegion.size(); ++i) { for (int i = 0; i < clearRegion.size(); ++i) {
#ifndef QT_GL_NO_SCISSOR_TEST #ifndef QT_GL_NO_SCISSOR_TEST
setScissor(clearRegion.at(i)); setScissor(clearRegion.at(i));
#endif #endif
glClear(GL_STENCIL_BUFFER_BIT); funcs.glClear(GL_STENCIL_BUFFER_BIT);
} }
dirtyStencilRegion -= currentScissorBounds; dirtyStencilRegion -= currentScissorBounds;
@ -973,23 +971,23 @@ void QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
#endif #endif
} }
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes funcs.glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
useSimpleShader(); useSimpleShader();
glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d funcs.glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
if (mode == WindingFillMode) { if (mode == WindingFillMode) {
Q_ASSERT(stops && !count); Q_ASSERT(stops && !count);
if (q->state()->clipTestEnabled) { if (q->state()->clipTestEnabled) {
// Flatten clip values higher than current clip, and set high bit to match current clip // Flatten clip values higher than current clip, and set high bit to match current clip
glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
composite(bounds); composite(bounds);
glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT);
} else if (!stencilClean) { } else if (!stencilClean) {
// Clear stencil buffer within bounding rect // Clear stencil buffer within bounding rect
glStencilFunc(GL_ALWAYS, 0, 0xff); funcs.glStencilFunc(GL_ALWAYS, 0, 0xff);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); funcs.glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
composite(bounds); composite(bounds);
} }
@ -997,44 +995,44 @@ void QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
funcs.glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP); funcs.glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP);
// Dec. for back-facing "holes" // Dec. for back-facing "holes"
funcs.glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); funcs.glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP);
glStencilMask(~GL_STENCIL_HIGH_BIT); funcs.glStencilMask(~GL_STENCIL_HIGH_BIT);
drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
if (q->state()->clipTestEnabled) { if (q->state()->clipTestEnabled) {
// Clear high bit of stencil outside of path // Clear high bit of stencil outside of path
glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
glStencilMask(GL_STENCIL_HIGH_BIT); funcs.glStencilMask(GL_STENCIL_HIGH_BIT);
composite(bounds); composite(bounds);
} }
} else if (mode == OddEvenFillMode) { } else if (mode == OddEvenFillMode) {
glStencilMask(GL_STENCIL_HIGH_BIT); funcs.glStencilMask(GL_STENCIL_HIGH_BIT);
glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
} else { // TriStripStrokeFillMode } else { // TriStripStrokeFillMode
Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
glStencilMask(GL_STENCIL_HIGH_BIT); funcs.glStencilMask(GL_STENCIL_HIGH_BIT);
#if 0 #if 0
glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
glDrawArrays(GL_TRIANGLE_STRIP, 0, count); funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
#else #else
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
if (q->state()->clipTestEnabled) { if (q->state()->clipTestEnabled) {
glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT, funcs.glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT,
~GL_STENCIL_HIGH_BIT); ~GL_STENCIL_HIGH_BIT);
} else { } else {
glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); funcs.glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
} }
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
glDrawArrays(GL_TRIANGLE_STRIP, 0, count); funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
#endif #endif
} }
// Enable color writes & disable stencil writes // Enable color writes & disable stencil writes
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); funcs.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
} }
/* /*
@ -1050,22 +1048,22 @@ void QOpenGL2PaintEngineExPrivate::resetClipIfNeeded()
Q_Q(QOpenGL2PaintEngineEx); Q_Q(QOpenGL2PaintEngineEx);
useSimpleShader(); useSimpleShader();
glEnable(GL_STENCIL_TEST); funcs.glEnable(GL_STENCIL_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); funcs.glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height)); QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height));
QOpenGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); QOpenGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
// Set high bit on clip region // Set high bit on clip region
glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff); funcs.glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff);
glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); funcs.glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
glStencilMask(GL_STENCIL_HIGH_BIT); funcs.glStencilMask(GL_STENCIL_HIGH_BIT);
composite(rect); composite(rect);
// Reset clipping to 1 and everything else to zero // Reset clipping to 1 and everything else to zero
glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT);
glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE); funcs.glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE);
glStencilMask(0xff); funcs.glStencilMask(0xff);
composite(rect); composite(rect);
q->state()->currentClip = 1; q->state()->currentClip = 1;
@ -1073,8 +1071,8 @@ void QOpenGL2PaintEngineExPrivate::resetClipIfNeeded()
maxClip = 1; maxClip = 1;
glStencilMask(0x0); funcs.glStencilMask(0x0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); funcs.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
} }
bool QOpenGL2PaintEngineExPrivate::prepareForCachedGlyphDraw(const QFontEngineGlyphCache &cache) bool QOpenGL2PaintEngineExPrivate::prepareForCachedGlyphDraw(const QFontEngineGlyphCache &cache)
@ -1107,9 +1105,9 @@ bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
|| (q->state()->composition_mode == QPainter::CompositionMode_SourceOver || (q->state()->composition_mode == QPainter::CompositionMode_SourceOver
&& srcPixelsAreOpaque && !stateHasOpacity)) && srcPixelsAreOpaque && !stateHasOpacity))
{ {
glDisable(GL_BLEND); funcs.glDisable(GL_BLEND);
} else { } else {
glEnable(GL_BLEND); funcs.glEnable(GL_BLEND);
} }
QOpenGLEngineShaderManager::OpacityMode opacityMode; QOpenGLEngineShaderManager::OpacityMode opacityMode;
@ -1159,7 +1157,7 @@ void QOpenGL2PaintEngineExPrivate::composite(const QOpenGLRect& boundingRect)
{ {
setCoords(staticVertexCoordinateArray, boundingRect); setCoords(staticVertexCoordinateArray, boundingRect);
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
} }
// Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans. // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
@ -1177,7 +1175,7 @@ void QOpenGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stop
for (int i=previousStop; i<stop; ++i) for (int i=previousStop; i<stop; ++i)
qDebug(" %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y); qDebug(" %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
*/ */
glDrawArrays(primitive, previousStop, stop - previousStop); funcs.glDrawArrays(primitive, previousStop, stop - previousStop);
previousStop = stop; previousStop = stop;
} }
} }
@ -1269,7 +1267,7 @@ void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &p
if (opaque) { if (opaque) {
prepareForDraw(opaque); prepareForDraw(opaque);
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices()); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices());
glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2); funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
// QBrush b(Qt::green); // QBrush b(Qt::green);
// d->setBrush(&b); // d->setBrush(&b);
@ -1292,16 +1290,16 @@ void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &p
fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2, fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2,
0, 0, bounds, QOpenGL2PaintEngineExPrivate::TriStripStrokeFillMode); 0, 0, bounds, QOpenGL2PaintEngineExPrivate::TriStripStrokeFillMode);
glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
// Pass when any bit is set, replace stencil value with 0 // Pass when any bit is set, replace stencil value with 0
glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
prepareForDraw(false); prepareForDraw(false);
// Stencil the brush onto the dest buffer // Stencil the brush onto the dest buffer
composite(bounds); composite(bounds);
glStencilMask(0); funcs.glStencilMask(0);
updateClipScissorTest(); updateClipScissorTest();
} }
@ -1336,11 +1334,12 @@ void QOpenGL2PaintEngineEx::renderHintsChanged()
#ifndef QT_OPENGL_ES_2 #ifndef QT_OPENGL_ES_2
if (!QOpenGLContext::currentContext()->isES()) { if (!QOpenGLContext::currentContext()->isES()) {
Q_D(QOpenGL2PaintEngineEx);
if ((state()->renderHints & QPainter::Antialiasing) if ((state()->renderHints & QPainter::Antialiasing)
|| (state()->renderHints & QPainter::HighQualityAntialiasing)) || (state()->renderHints & QPainter::HighQualityAntialiasing))
glEnable(GL_MULTISAMPLE); d->funcs.glEnable(GL_MULTISAMPLE);
else else
glDisable(GL_MULTISAMPLE); d->funcs.glDisable(GL_MULTISAMPLE);
} }
#endif // QT_OPENGL_ES_2 #endif // QT_OPENGL_ES_2
@ -1461,7 +1460,7 @@ bool QOpenGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, co
d->transferMode(ImageDrawingMode); d->transferMode(ImageDrawingMode);
d->funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); d->funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, textureId); d->funcs.glBindTexture(GL_TEXTURE_2D, textureId);
QOpenGLRect srcRect(src.left(), src.bottom(), src.right(), src.top()); QOpenGLRect srcRect(src.left(), src.bottom(), src.right(), src.top());
@ -1720,15 +1719,15 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
if (elementIndicesVBOId == 0) if (elementIndicesVBOId == 0)
glGenBuffers(1, &elementIndicesVBOId); funcs.glGenBuffers(1, &elementIndicesVBOId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() * sizeof(GLushort), funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() * sizeof(GLushort),
elementIndices.constData(), GL_STATIC_DRAW); elementIndices.constData(), GL_STATIC_DRAW);
#endif #endif
} else { } else {
#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
#endif #endif
} }
@ -1774,8 +1773,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
opacityUniformDirty = true; opacityUniformDirty = true;
} }
glEnable(GL_BLEND); funcs.glEnable(GL_BLEND);
glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR); funcs.glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
funcs.glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()); funcs.glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
} else { } else {
// Other brush styles need two passes. // Other brush styles need two passes.
@ -1790,17 +1789,17 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
compositionModeDirty = false; // I can handle this myself, thank you very much compositionModeDirty = false; // I can handle this myself, thank you very much
prepareForCachedGlyphDraw(*cache); prepareForCachedGlyphDraw(*cache);
glEnable(GL_BLEND); funcs.glEnable(GL_BLEND);
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); funcs.glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, cache->texture()); funcs.glBindTexture(GL_TEXTURE_2D, cache->texture());
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0);
#else #else
glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
#endif #endif
shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass2); shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass2);
@ -1814,8 +1813,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
compositionModeDirty = false; compositionModeDirty = false;
prepareForCachedGlyphDraw(*cache); prepareForCachedGlyphDraw(*cache);
glEnable(GL_BLEND); funcs.glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE); funcs.glBlendFunc(GL_ONE, GL_ONE);
} }
compositionModeDirty = true; compositionModeDirty = true;
} else if (glyphFormat == QFontEngine::Format_ARGB) { } else if (glyphFormat == QFontEngine::Format_ARGB) {
@ -1839,27 +1838,27 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
if (lastMaskTextureUsed != cache->texture()) { if (lastMaskTextureUsed != cache->texture()) {
glBindTexture(GL_TEXTURE_2D, cache->texture()); funcs.glBindTexture(GL_TEXTURE_2D, cache->texture());
lastMaskTextureUsed = cache->texture(); lastMaskTextureUsed = cache->texture();
} }
if (cache->filterMode() != filterMode) { if (cache->filterMode() != filterMode) {
if (filterMode == QOpenGLTextureGlyphCache::Linear) { if (filterMode == QOpenGLTextureGlyphCache::Linear) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); funcs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); funcs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else { } else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} }
cache->setFilterMode(filterMode); cache->setFilterMode(filterMode);
} }
} }
#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#else #else
glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
#endif #endif
} }
@ -1960,7 +1959,7 @@ void QOpenGL2PaintEngineExPrivate::drawPixmapFragments(const QPainter::PixmapFra
shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col); shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col);
} }
glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount); funcs.glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount);
} }
bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
@ -2005,15 +2004,15 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
d->shaderManager = new QOpenGLEngineShaderManager(d->ctx); d->shaderManager = new QOpenGLEngineShaderManager(d->ctx);
glDisable(GL_STENCIL_TEST); d->funcs.glDisable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST); d->funcs.glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST); d->funcs.glDisable(GL_SCISSOR_TEST);
d->glyphCacheFormat = QFontEngine::Format_A8; d->glyphCacheFormat = QFontEngine::Format_A8;
#ifndef QT_OPENGL_ES_2 #ifndef QT_OPENGL_ES_2
if (!QOpenGLContext::currentContext()->isES()) { if (!QOpenGLContext::currentContext()->isES()) {
glDisable(GL_MULTISAMPLE); d->funcs.glDisable(GL_MULTISAMPLE);
d->glyphCacheFormat = QFontEngine::Format_A32; d->glyphCacheFormat = QFontEngine::Format_A32;
d->multisamplingAlwaysEnabled = false; d->multisamplingAlwaysEnabled = false;
} else } else
@ -2071,7 +2070,7 @@ void QOpenGL2PaintEngineEx::ensureActive()
d->device->ensureActiveTarget(); d->device->ensureActiveTarget();
d->transferMode(BrushDrawingMode); d->transferMode(BrushDrawingMode);
glViewport(0, 0, d->width, d->height); d->funcs.glViewport(0, 0, d->width, d->height);
d->needsSync = false; d->needsSync = false;
d->lastMaskTextureUsed = 0; d->lastMaskTextureUsed = 0;
d->shaderManager->setDirty(); d->shaderManager->setDirty();
@ -2086,11 +2085,11 @@ void QOpenGL2PaintEngineExPrivate::updateClipScissorTest()
{ {
Q_Q(QOpenGL2PaintEngineEx); Q_Q(QOpenGL2PaintEngineEx);
if (q->state()->clipTestEnabled) { if (q->state()->clipTestEnabled) {
glEnable(GL_STENCIL_TEST); funcs.glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
} else { } else {
glDisable(GL_STENCIL_TEST); funcs.glDisable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 0xff); funcs.glStencilFunc(GL_ALWAYS, 0, 0xff);
} }
#ifdef QT_GL_NO_SCISSOR_TEST #ifdef QT_GL_NO_SCISSOR_TEST
@ -2112,9 +2111,9 @@ void QOpenGL2PaintEngineExPrivate::updateClipScissorTest()
currentScissorBounds = bounds; currentScissorBounds = bounds;
if (bounds == QRect(0, 0, width, height)) { if (bounds == QRect(0, 0, width, height)) {
glDisable(GL_SCISSOR_TEST); funcs.glDisable(GL_SCISSOR_TEST);
} else { } else {
glEnable(GL_SCISSOR_TEST); funcs.glEnable(GL_SCISSOR_TEST);
setScissor(bounds); setScissor(bounds);
} }
#endif #endif
@ -2130,7 +2129,7 @@ void QOpenGL2PaintEngineExPrivate::setScissor(const QRect &rect)
} }
const int height = rect.height(); const int height = rect.height();
glScissor(left, bottom, width, height); funcs.glScissor(left, bottom, width, height);
} }
void QOpenGL2PaintEngineEx::clipEnabledChanged() void QOpenGL2PaintEngineEx::clipEnabledChanged()
@ -2149,10 +2148,10 @@ void QOpenGL2PaintEngineExPrivate::clearClip(uint value)
{ {
dirtyStencilRegion -= currentScissorBounds; dirtyStencilRegion -= currentScissorBounds;
glStencilMask(0xff); funcs.glStencilMask(0xff);
glClearStencil(value); funcs.glClearStencil(value);
glClear(GL_STENCIL_BUFFER_BIT); funcs.glClear(GL_STENCIL_BUFFER_BIT);
glStencilMask(0x0); funcs.glStencilMask(0x0);
q->state()->needsClipBufferClear = false; q->state()->needsClipBufferClear = false;
} }
@ -2180,15 +2179,15 @@ void QOpenGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value
clearClip(1); clearClip(1);
if (path.isEmpty()) { if (path.isEmpty()) {
glEnable(GL_STENCIL_TEST); funcs.glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT);
return; return;
} }
if (q->state()->clipTestEnabled) if (q->state()->clipTestEnabled)
glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
else else
glStencilFunc(GL_ALWAYS, 0, 0xff); funcs.glStencilFunc(GL_ALWAYS, 0, 0xff);
vertexCoordinateArray.clear(); vertexCoordinateArray.clear();
vertexCoordinateArray.addPath(path, inverseScale, false); vertexCoordinateArray.addPath(path, inverseScale, false);
@ -2196,39 +2195,39 @@ void QOpenGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value
if (!singlePass) if (!singlePass)
fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
glColorMask(false, false, false, false); funcs.glColorMask(false, false, false, false);
glEnable(GL_STENCIL_TEST); funcs.glEnable(GL_STENCIL_TEST);
useSimpleShader(); useSimpleShader();
if (singlePass) { if (singlePass) {
// Under these conditions we can set the new stencil value in a single // Under these conditions we can set the new stencil value in a single
// pass, by using the current value and the "new value" as the toggles // pass, by using the current value and the "new value" as the toggles
glStencilFunc(GL_LEQUAL, referenceClipValue, ~GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_LEQUAL, referenceClipValue, ~GL_STENCIL_HIGH_BIT);
glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); funcs.glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
glStencilMask(value ^ referenceClipValue); funcs.glStencilMask(value ^ referenceClipValue);
drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
} else { } else {
glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
glStencilMask(0xff); funcs.glStencilMask(0xff);
if (!q->state()->clipTestEnabled && path.hasWindingFill()) { if (!q->state()->clipTestEnabled && path.hasWindingFill()) {
// Pass when any clip bit is set, set high bit // Pass when any clip bit is set, set high bit
glStencilFunc(GL_NOTEQUAL, GL_STENCIL_HIGH_BIT, ~GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_NOTEQUAL, GL_STENCIL_HIGH_BIT, ~GL_STENCIL_HIGH_BIT);
composite(vertexCoordinateArray.boundingRect()); composite(vertexCoordinateArray.boundingRect());
} }
// Pass when high bit is set, replace stencil value with new clip value // Pass when high bit is set, replace stencil value with new clip value
glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT);
composite(vertexCoordinateArray.boundingRect()); composite(vertexCoordinateArray.boundingRect());
} }
glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); funcs.glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT);
glStencilMask(0); funcs.glStencilMask(0);
glColorMask(true, true, true, true); funcs.glColorMask(true, true, true, true);
} }
void QOpenGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) void QOpenGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
@ -2384,7 +2383,7 @@ void QOpenGL2PaintEngineEx::setState(QPainterState *new_state)
if (old_state == s || old_state->clipChanged) { if (old_state == s || old_state->clipChanged) {
if (old_state && old_state != s && old_state->canRestoreClip) { if (old_state && old_state != s && old_state->canRestoreClip) {
d->updateClipScissorTest(); d->updateClipScissorTest();
glDepthFunc(GL_LEQUAL); d->funcs.glDepthFunc(GL_LEQUAL);
} else { } else {
d->regenerateClip(); d->regenerateClip();
} }

View File

@ -3035,7 +3035,8 @@ int QOpenGLShaderProgram::maxGeometryOutputVertices() const
{ {
GLint n = 0; GLint n = 0;
#if defined(QT_OPENGL_3_2) #if defined(QT_OPENGL_3_2)
glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n); Q_D(const QOpenGLShaderProgram);
d->glfuncs->glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n);
#endif #endif
return n; return n;
} }

View File

@ -1633,7 +1633,7 @@ GLuint QOpenGLTexture::boundTextureId(BindingTarget target)
} }
GLint textureId = 0; GLint textureId = 0;
glGetIntegerv(target, &textureId); ctx->functions()->glGetIntegerv(target, &textureId);
return static_cast<GLuint>(textureId); return static_cast<GLuint>(textureId);
} }
@ -1653,11 +1653,11 @@ GLuint QOpenGLTexture::boundTextureId(uint unit, BindingTarget target)
funcs->initializeOpenGLFunctions(); funcs->initializeOpenGLFunctions();
GLint oldTextureUnit = 0; GLint oldTextureUnit = 0;
glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit); funcs->glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit);
funcs->glActiveTexture(unit); funcs->glActiveTexture(unit);
GLint textureId = 0; GLint textureId = 0;
glGetIntegerv(target, &textureId); funcs->glGetIntegerv(target, &textureId);
funcs->glActiveTexture(oldTextureUnit); funcs->glActiveTexture(oldTextureUnit);
return static_cast<GLuint>(textureId); return static_cast<GLuint>(textureId);

View File

@ -45,6 +45,7 @@
#include <QtGui/QOpenGLShaderProgram> #include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLVertexArrayObject> #include <QtGui/QOpenGLVertexArrayObject>
#include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -120,11 +121,11 @@ class TextureBinder
public: public:
TextureBinder(GLuint textureId) TextureBinder(GLuint textureId)
{ {
glBindTexture(GL_TEXTURE_2D, textureId); QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, textureId);
} }
~TextureBinder() ~TextureBinder()
{ {
glBindTexture(GL_TEXTURE_2D, 0); QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, 0);
} }
}; };
@ -196,7 +197,7 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture,
program->setUniformValue(textureTransformUniformPos, textureTransform); program->setUniformValue(textureTransformUniformPos, textureTransform);
textureMatrixUniformState = User; textureMatrixUniformState = User;
glDrawArrays(GL_TRIANGLES, 0, 6); QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6);
} }
void QOpenGLTextureBlitterPrivate::blit(GLuint texture, void QOpenGLTextureBlitterPrivate::blit(GLuint texture,
@ -219,7 +220,7 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture,
textureMatrixUniformState = Identity; textureMatrixUniformState = Identity;
} }
glDrawArrays(GL_TRIANGLES, 0, 6); QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6);
} }
QOpenGLTextureBlitter::QOpenGLTextureBlitter() QOpenGLTextureBlitter::QOpenGLTextureBlitter()

View File

@ -117,7 +117,7 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QPixmap &
if (!pixmap.paintingActive()) { if (!pixmap.paintingActive()) {
QOpenGLCachedTexture *entry = m_cache.object(key); QOpenGLCachedTexture *entry = m_cache.object(key);
if (entry) { if (entry) {
glBindTexture(GL_TEXTURE_2D, entry->id()); context->functions()->glBindTexture(GL_TEXTURE_2D, entry->id());
return entry->id(); return entry->id();
} }
} }
@ -154,7 +154,7 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &i
if (!image.paintingActive()) { if (!image.paintingActive()) {
QOpenGLCachedTexture *entry = m_cache.object(key); QOpenGLCachedTexture *entry = m_cache.object(key);
if (entry) { if (entry) {
glBindTexture(GL_TEXTURE_2D, entry->id()); context->functions()->glBindTexture(GL_TEXTURE_2D, entry->id());
return entry->id(); return entry->id();
} }
} }
@ -181,12 +181,13 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &i
GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, const QImage &image) GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, const QImage &image)
{ {
GLuint id; GLuint id;
glGenTextures(1, &id); QOpenGLFunctions *funcs = context->functions();
glBindTexture(GL_TEXTURE_2D, id); funcs->glGenTextures(1, &id);
funcs->glBindTexture(GL_TEXTURE_2D, id);
QImage tx = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied); QImage tx = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx.width(), tx.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, const_cast<const QImage &>(tx).bits()); funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx.width(), tx.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, const_cast<const QImage &>(tx).bits());
int cost = tx.width() * tx.height() * 4 / 1024; int cost = tx.width() * tx.height() * 4 / 1024;
m_cache.insert(key, new QOpenGLCachedTexture(id, context), cost); m_cache.insert(key, new QOpenGLCachedTexture(id, context), cost);
@ -210,9 +211,9 @@ void QOpenGLTextureCache::freeResource(QOpenGLContext *)
Q_ASSERT(false); // the texture cache lives until the context group disappears Q_ASSERT(false); // the texture cache lives until the context group disappears
} }
static void freeTexture(QOpenGLFunctions *, GLuint id) static void freeTexture(QOpenGLFunctions *funcs, GLuint id)
{ {
glDeleteTextures(1, &id); funcs->glDeleteTextures(1, &id);
} }
QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLContext *context) QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLContext *context)

View File

@ -122,8 +122,9 @@ void QOpenGLTextureGlyphCache::createTextureData(int width, int height)
if (!m_textureResource) if (!m_textureResource)
m_textureResource = new QOpenGLGlyphTexture(ctx); m_textureResource = new QOpenGLGlyphTexture(ctx);
glGenTextures(1, &m_textureResource->m_texture); QOpenGLFunctions *funcs = ctx->functions();
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); funcs->glGenTextures(1, &m_textureResource->m_texture);
funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
m_textureResource->m_width = width; m_textureResource->m_width = width;
m_textureResource->m_height = height; m_textureResource->m_height = height;
@ -132,7 +133,7 @@ void QOpenGLTextureGlyphCache::createTextureData(int width, int height)
QVarLengthArray<uchar> data(width * height * 4); QVarLengthArray<uchar> data(width * height * 4);
for (int i = 0; i < data.size(); ++i) for (int i = 0; i < data.size(); ++i)
data[i] = 0; data[i] = 0;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
} else { } else {
QVarLengthArray<uchar> data(width * height); QVarLengthArray<uchar> data(width * height);
for (int i = 0; i < data.size(); ++i) for (int i = 0; i < data.size(); ++i)
@ -144,13 +145,13 @@ void QOpenGLTextureGlyphCache::createTextureData(int width, int height)
const GLint internalFormat = GL_ALPHA; const GLint internalFormat = GL_ALPHA;
const GLenum format = GL_ALPHA; const GLenum format = GL_ALPHA;
#endif #endif
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, &data[0]); funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, &data[0]);
} }
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_filterMode = Nearest; m_filterMode = Nearest;
if (!m_buffer.isCreated()) { if (!m_buffer.isCreated()) {
@ -187,8 +188,9 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height)
return; return;
} }
QOpenGLFunctions *funcs = ctx->functions();
GLint oldFbo; GLint oldFbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFbo); funcs->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFbo);
int oldWidth = m_textureResource->m_width; int oldWidth = m_textureResource->m_width;
int oldHeight = m_textureResource->m_height; int oldHeight = m_textureResource->m_height;
@ -205,44 +207,42 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height)
if (ctx->d_func()->workaround_brokenFBOReadBack) { if (ctx->d_func()->workaround_brokenFBOReadBack) {
QImageTextureGlyphCache::resizeTextureData(width, height); QImageTextureGlyphCache::resizeTextureData(width, height);
Q_ASSERT(image().depth() == 8); Q_ASSERT(image().depth() == 8);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, image().constBits()); funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, image().constBits());
glDeleteTextures(1, &oldTexture); funcs->glDeleteTextures(1, &oldTexture);
return; return;
} }
// ### the QTextureGlyphCache API needs to be reworked to allow // ### the QTextureGlyphCache API needs to be reworked to allow
// ### resizeTextureData to fail // ### resizeTextureData to fail
QOpenGLFunctions funcs(ctx); funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_textureResource->m_fbo);
funcs.glBindFramebuffer(GL_FRAMEBUFFER, m_textureResource->m_fbo);
GLuint tmp_texture; GLuint tmp_texture;
glGenTextures(1, &tmp_texture); funcs->glGenTextures(1, &tmp_texture);
glBindTexture(GL_TEXTURE_2D, tmp_texture); funcs->glBindTexture(GL_TEXTURE_2D, tmp_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0, funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL); GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_filterMode = Nearest; m_filterMode = Nearest;
glBindTexture(GL_TEXTURE_2D, 0); funcs->glBindTexture(GL_TEXTURE_2D, 0);
funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tmp_texture, 0); GL_TEXTURE_2D, tmp_texture, 0);
funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); funcs->glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, oldTexture); funcs->glBindTexture(GL_TEXTURE_2D, oldTexture);
if (pex != 0) if (pex != 0)
pex->transferMode(BrushDrawingMode); pex->transferMode(BrushDrawingMode);
glDisable(GL_STENCIL_TEST); funcs->glDisable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST); funcs->glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST); funcs->glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND); funcs->glDisable(GL_BLEND);
glViewport(0, 0, oldWidth, oldHeight); funcs->glViewport(0, 0, oldWidth, oldHeight);
QOpenGLShaderProgram *blitProgram = 0; QOpenGLShaderProgram *blitProgram = 0;
if (pex == 0) { if (pex == 0) {
@ -301,21 +301,21 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height)
blitProgram->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); blitProgram->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); funcs->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); funcs->glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, 0); GL_RENDERBUFFER, 0);
glDeleteTextures(1, &tmp_texture); funcs->glDeleteTextures(1, &tmp_texture);
glDeleteTextures(1, &oldTexture); funcs->glDeleteTextures(1, &oldTexture);
funcs.glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)oldFbo); funcs->glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)oldFbo);
if (pex != 0) { if (pex != 0) {
glViewport(0, 0, pex->width, pex->height); funcs->glViewport(0, 0, pex->width, pex->height);
pex->updateClipScissorTest(); pex->updateClipScissorTest();
} else { } else {
if (m_vao.isCreated()) { if (m_vao.isCreated()) {
@ -335,15 +335,16 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed
return; return;
} }
QOpenGLFunctions *funcs = ctx->functions();
if (ctx->d_func()->workaround_brokenFBOReadBack) { if (ctx->d_func()->workaround_brokenFBOReadBack) {
QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition); QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition);
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
const QImage &texture = image(); const QImage &texture = image();
const uchar *bits = texture.constBits(); const uchar *bits = texture.constBits();
bits += c.y * texture.bytesPerLine() + c.x; bits += c.y * texture.bytesPerLine() + c.x;
for (int i=0; i<c.h; ++i) { for (int i=0; i<c.h; ++i) {
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, c.w, 1, GL_ALPHA, GL_UNSIGNED_BYTE, bits); funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, c.w, 1, GL_ALPHA, GL_UNSIGNED_BYTE, bits);
bits += texture.bytesPerLine(); bits += texture.bytesPerLine();
} }
return; return;
@ -404,7 +405,7 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed
} }
} }
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
if (mask.depth() == 32) { if (mask.depth() == 32) {
#ifdef QT_OPENGL_ES_2 #ifdef QT_OPENGL_ES_2
GLenum fmt = GL_RGBA; GLenum fmt = GL_RGBA;
@ -415,7 +416,7 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed
#if Q_BYTE_ORDER == Q_BIG_ENDIAN #if Q_BYTE_ORDER == Q_BIG_ENDIAN
fmt = GL_RGBA; fmt = GL_RGBA;
#endif #endif
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, fmt, GL_UNSIGNED_BYTE, mask.bits()); funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, fmt, GL_UNSIGNED_BYTE, mask.bits());
} else { } else {
// glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is
// not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista
@ -438,7 +439,7 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed
#if 0 #if 0
if (ctx->d_func()->workaround_brokenAlphaTexSubImage) { if (ctx->d_func()->workaround_brokenAlphaTexSubImage) {
for (int i = 0; i < maskHeight; ++i) for (int i = 0; i < maskHeight; ++i)
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i));
} else { } else {
#endif #endif
@ -447,7 +448,7 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed
#else #else
const GLenum format = GL_ALPHA; const GLenum format = GL_ALPHA;
#endif #endif
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, format, GL_UNSIGNED_BYTE, mask.bits()); funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, format, GL_UNSIGNED_BYTE, mask.bits());
#if 0 #if 0
} }

View File

@ -89,9 +89,9 @@ public:
qDebug("~QOpenGLGlyphTexture() %p for context %p.", this, ctx); qDebug("~QOpenGLGlyphTexture() %p for context %p.", this, ctx);
#endif #endif
if (!ctx->d_func()->workaround_brokenFBOReadBack) if (!ctx->d_func()->workaround_brokenFBOReadBack)
QOpenGLFunctions(ctx).glDeleteFramebuffers(1, &m_fbo); ctx->functions()->glDeleteFramebuffers(1, &m_fbo);
if (m_width || m_height) if (m_width || m_height)
glDeleteTextures(1, &m_texture); ctx->functions()->glDeleteTextures(1, &m_texture);
} }
void invalidateResource() void invalidateResource()

View File

@ -204,7 +204,8 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
Q_UNUSED(offset); Q_UNUSED(offset);
context->makeCurrent(window); context->makeCurrent(window);
glViewport(0, 0, window->width(), window->height()); QOpenGLFunctions *funcs = context->functions();
funcs->glViewport(0, 0, window->width(), window->height());
if (!d_ptr->blitter) { if (!d_ptr->blitter) {
d_ptr->blitter = new QOpenGLTextureBlitter; d_ptr->blitter = new QOpenGLTextureBlitter;
@ -216,7 +217,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
QRect windowRect(QPoint(), window->size()); QRect windowRect(QPoint(), window->size());
for (int i = 0; i < textures->count(); ++i) { for (int i = 0; i < textures->count(); ++i) {
GLuint textureId = textures->textureId(i); GLuint textureId = textures->textureId(i);
glBindTexture(GL_TEXTURE_2D, textureId); funcs->glBindTexture(GL_TEXTURE_2D, textureId);
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), windowRect); QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), windowRect);
d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft); d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft);
@ -226,15 +227,15 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
if (!textureId) if (!textureId)
return; return;
glEnable(GL_BLEND); funcs->glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); funcs->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(windowRect, windowRect); QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(windowRect, windowRect);
d_ptr->blitter->setSwizzleRB(true); d_ptr->blitter->setSwizzleRB(true);
d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
d_ptr->blitter->setSwizzleRB(false); d_ptr->blitter->setSwizzleRB(false);
glDisable(GL_BLEND); funcs->glDisable(GL_BLEND);
d_ptr->blitter->release(); d_ptr->blitter->release();
context->swapBuffers(window); context->swapBuffers(window);
} }
@ -280,27 +281,29 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion) const
if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_RGBA8888) if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_RGBA8888)
image = image.convertToFormat(QImage::Format_RGBA8888); image = image.convertToFormat(QImage::Format_RGBA8888);
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (resized) { if (resized) {
if (d_ptr->textureId) if (d_ptr->textureId)
glDeleteTextures(1, &d_ptr->textureId); funcs->glDeleteTextures(1, &d_ptr->textureId);
glGenTextures(1, &d_ptr->textureId); funcs->glGenTextures(1, &d_ptr->textureId);
glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
#ifndef QT_OPENGL_ES_2 #ifndef QT_OPENGL_ES_2
if (!QOpenGLContext::currentContext()->isES()) { if (!QOpenGLContext::currentContext()->isES()) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
} }
#endif #endif
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageSize.width(), imageSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageSize.width(), imageSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
const_cast<uchar*>(image.constBits())); const_cast<uchar*>(image.constBits()));
d_ptr->textureSize = imageSize; d_ptr->textureSize = imageSize;
} else { } else {
glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
QRect imageRect = image.rect(); QRect imageRect = image.rect();
QRect rect = dirtyRegion.boundingRect() & imageRect; QRect rect = dirtyRegion.boundingRect() & imageRect;
// if the rect is wide enough it's cheaper to just // if the rect is wide enough it's cheaper to just
@ -314,11 +317,11 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion) const
// OpenGL instead of copying, since there's no gap between scanlines // OpenGL instead of copying, since there's no gap between scanlines
if (rect.width() == imageRect.width()) { if (rect.width() == imageRect.width()) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
image.constScanLine(rect.y())); image.constScanLine(rect.y()));
} else { } else {
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
image.copy(rect).constBits()); image.copy(rect).constBits());
} }
} }

View File

@ -44,6 +44,7 @@
#include <QtWidgets/private/qwidget_p.h> #include <QtWidgets/private/qwidget_p.h>
#include <QOpenGLFramebufferObject> #include <QOpenGLFramebufferObject>
#include <QOpenGLFunctions>
#include <QWindow> #include <QWindow>
#include <qpa/qplatformwindow.h> #include <qpa/qplatformwindow.h>
#include <QDebug> #include <QDebug>
@ -144,9 +145,10 @@ void QOpenGLWidget::paintGL()
void QOpenGLWidget::updateGL() void QOpenGLWidget::updateGL()
{ {
Q_D(QOpenGLWidget);
makeCurrent(); makeCurrent();
paintGL(); paintGL();
glFlush(); d->context.functions()->glFlush();
doneCurrent(); doneCurrent();
update(); update();
} }
@ -163,15 +165,16 @@ void QOpenGLWidget::resizeEvent(QResizeEvent *)
delete d->fbo; // recreate when resized delete d->fbo; // recreate when resized
d->fbo = new QOpenGLFramebufferObject(size()); d->fbo = new QOpenGLFramebufferObject(size());
d->fbo->bind(); d->fbo->bind();
glBindTexture(GL_TEXTURE_2D, d->fbo->texture()); QOpenGLFunctions *funcs = d->context.functions();
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs->glBindTexture(GL_TEXTURE_2D, d->fbo->texture());
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
resizeGL(width(), height()); resizeGL(width(), height());
paintGL(); paintGL();
glFlush(); funcs->glFlush();
} }
void QOpenGLWidget::paintEvent(QPaintEvent *) void QOpenGLWidget::paintEvent(QPaintEvent *)