Enable access to the VAO resolvers through QOpenGLContextPrivate

This is a commit in preparation for an upcoming change in QtQuick.
We want to store the resolved functions for managing VAOs somewhere;
the "least worst" choice is next to the all other function resolvers,
which are in QOpenGLContext(Private).

To avoid moving the VAO resolvers themselves, leave a hook in
QOGLCPrivate, similar to e.g. the texture function resolvers. The hook
gets populated when the VAO resolvers for a given context are
requested.

This removes memory management burden from the users of those functions
(again, just like other function resolvers), and makes the
initialization of the functions automatic.

Change-Id: I0eba30a85bf8ad82946a5d68e91009d8b4bd91cf
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
Giuseppe D'Angelo 2020-06-18 03:30:47 +02:00
parent f1f0aa4a3a
commit 436b331b71
5 changed files with 62 additions and 37 deletions

View File

@ -484,6 +484,13 @@ void QOpenGLContext::destroy()
} }
d->textureFunctions = nullptr; d->textureFunctions = nullptr;
if (d->vaoHelperDestroyCallback) {
Q_ASSERT(d->vaoHelper);
d->vaoHelperDestroyCallback(d->vaoHelper);
d->vaoHelperDestroyCallback = nullptr;
}
d->vaoHelper = nullptr;
d->nativeHandle = QVariant(); d->nativeHandle = QVariant();
} }

View File

@ -191,6 +191,7 @@ private:
class QPaintEngineEx; class QPaintEngineEx;
class QOpenGLFunctions; class QOpenGLFunctions;
class QOpenGLTextureHelper; class QOpenGLTextureHelper;
class QOpenGLVertexArrayObjectHelper;
class Q_GUI_EXPORT QOpenGLContextVersionFunctionHelper class Q_GUI_EXPORT QOpenGLContextVersionFunctionHelper
{ {
@ -211,6 +212,8 @@ public:
, functions(nullptr) , functions(nullptr)
, textureFunctions(nullptr) , textureFunctions(nullptr)
, versionFunctions(nullptr) , versionFunctions(nullptr)
, vaoHelper(nullptr)
, vaoHelperDestroyCallback(nullptr)
, max_texture_size(-1) , max_texture_size(-1)
, workaround_brokenFBOReadBack(false) , workaround_brokenFBOReadBack(false)
, workaround_brokenTexSubImage(false) , workaround_brokenTexSubImage(false)
@ -242,6 +245,9 @@ public:
QOpenGLTextureHelper* textureFunctions; QOpenGLTextureHelper* textureFunctions;
std::function<void()> textureFunctionsDestroyCallback; std::function<void()> textureFunctionsDestroyCallback;
QOpenGLContextVersionFunctionHelper *versionFunctions; QOpenGLContextVersionFunctionHelper *versionFunctions;
QOpenGLVertexArrayObjectHelper *vaoHelper;
using QOpenGLVertexArrayObjectHelperDestroyCallback_t = void (*)(QOpenGLVertexArrayObjectHelper *);
QOpenGLVertexArrayObjectHelperDestroyCallback_t vaoHelperDestroyCallback;
GLint max_texture_size; GLint max_texture_size;

View File

@ -49,6 +49,7 @@
#include <QtOpenGL/qopenglfunctions_3_0.h> #include <QtOpenGL/qopenglfunctions_3_0.h>
#include <QtOpenGL/qopenglfunctions_3_2_core.h> #include <QtOpenGL/qopenglfunctions_3_2_core.h>
#include <private/qopenglcontext_p.h>
#include <private/qopenglextensions_p.h> #include <private/qopenglextensions_p.h>
#include <private/qopenglvertexarrayobject_p.h> #include <private/qopenglvertexarrayobject_p.h>
@ -57,9 +58,28 @@ QT_BEGIN_NAMESPACE
class QOpenGLFunctions_3_0; class QOpenGLFunctions_3_0;
class QOpenGLFunctions_3_2_Core; class QOpenGLFunctions_3_2_Core;
void qtInitializeVertexArrayObjectHelper(QOpenGLVertexArrayObjectHelper *helper, QOpenGLContext *context) static void vertexArrayObjectHelperDestroyCallback(QOpenGLVertexArrayObjectHelper *vaoHelper)
{
delete vaoHelper;
}
QOpenGLVertexArrayObjectHelper *QOpenGLVertexArrayObjectHelper::vertexArrayObjectHelperForContext(QOpenGLContext *context)
{
Q_ASSERT(context);
auto contextPrivate = QOpenGLContextPrivate::get(context);
auto &vaoHelper = contextPrivate->vaoHelper;
if (!vaoHelper) {
vaoHelper = new QOpenGLVertexArrayObjectHelper(context);
contextPrivate->vaoHelperDestroyCallback = &vertexArrayObjectHelperDestroyCallback;
}
return vaoHelper;
}
void QOpenGLVertexArrayObjectHelper::initializeFromContext(QOpenGLContext *context)
{ {
Q_ASSERT(helper);
Q_ASSERT(context); Q_ASSERT(context);
bool tryARB = true; bool tryARB = true;
@ -67,32 +87,32 @@ void qtInitializeVertexArrayObjectHelper(QOpenGLVertexArrayObjectHelper *helper,
if (context->isOpenGLES()) { if (context->isOpenGLES()) {
if (context->format().majorVersion() >= 3) { if (context->format().majorVersion() >= 3) {
QOpenGLExtraFunctionsPrivate *extra = static_cast<QOpenGLExtensions *>(context->extraFunctions())->d(); QOpenGLExtraFunctionsPrivate *extra = static_cast<QOpenGLExtensions *>(context->extraFunctions())->d();
helper->GenVertexArrays = extra->f.GenVertexArrays; GenVertexArrays = extra->f.GenVertexArrays;
helper->DeleteVertexArrays = extra->f.DeleteVertexArrays; DeleteVertexArrays = extra->f.DeleteVertexArrays;
helper->BindVertexArray = extra->f.BindVertexArray; BindVertexArray = extra->f.BindVertexArray;
helper->IsVertexArray = extra->f.IsVertexArray; IsVertexArray = extra->f.IsVertexArray;
tryARB = false; tryARB = false;
} else if (context->hasExtension(QByteArrayLiteral("GL_OES_vertex_array_object"))) { } else if (context->hasExtension(QByteArrayLiteral("GL_OES_vertex_array_object"))) {
helper->GenVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_GenVertexArrays_t>(context->getProcAddress("glGenVertexArraysOES")); GenVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_GenVertexArrays_t>(context->getProcAddress("glGenVertexArraysOES"));
helper->DeleteVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_DeleteVertexArrays_t>(context->getProcAddress("glDeleteVertexArraysOES")); DeleteVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_DeleteVertexArrays_t>(context->getProcAddress("glDeleteVertexArraysOES"));
helper->BindVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_BindVertexArray_t>(context->getProcAddress("glBindVertexArrayOES")); BindVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_BindVertexArray_t>(context->getProcAddress("glBindVertexArrayOES"));
helper->IsVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_IsVertexArray_t>(context->getProcAddress("glIsVertexArrayOES")); IsVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_IsVertexArray_t>(context->getProcAddress("glIsVertexArrayOES"));
tryARB = false; tryARB = false;
} }
} else if (context->hasExtension(QByteArrayLiteral("GL_APPLE_vertex_array_object")) && } else if (context->hasExtension(QByteArrayLiteral("GL_APPLE_vertex_array_object")) &&
!context->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) { !context->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) {
helper->GenVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_GenVertexArrays_t>(context->getProcAddress("glGenVertexArraysAPPLE")); GenVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_GenVertexArrays_t>(context->getProcAddress("glGenVertexArraysAPPLE"));
helper->DeleteVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_DeleteVertexArrays_t>(context->getProcAddress("glDeleteVertexArraysAPPLE")); DeleteVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_DeleteVertexArrays_t>(context->getProcAddress("glDeleteVertexArraysAPPLE"));
helper->BindVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_BindVertexArray_t>(context->getProcAddress("glBindVertexArrayAPPLE")); BindVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_BindVertexArray_t>(context->getProcAddress("glBindVertexArrayAPPLE"));
helper->IsVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_IsVertexArray_t>(context->getProcAddress("glIsVertexArrayAPPLE")); IsVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_IsVertexArray_t>(context->getProcAddress("glIsVertexArrayAPPLE"));
tryARB = false; tryARB = false;
} }
if (tryARB && context->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) { if (tryARB && context->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) {
helper->GenVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_GenVertexArrays_t>(context->getProcAddress("glGenVertexArrays")); GenVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_GenVertexArrays_t>(context->getProcAddress("glGenVertexArrays"));
helper->DeleteVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_DeleteVertexArrays_t>(context->getProcAddress("glDeleteVertexArrays")); DeleteVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_DeleteVertexArrays_t>(context->getProcAddress("glDeleteVertexArrays"));
helper->BindVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_BindVertexArray_t>(context->getProcAddress("glBindVertexArray")); BindVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_BindVertexArray_t>(context->getProcAddress("glBindVertexArray"));
helper->IsVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_IsVertexArray_t>(context->getProcAddress("glIsVertexArray")); IsVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_IsVertexArray_t>(context->getProcAddress("glIsVertexArray"));
} }
} }
@ -107,12 +127,6 @@ public:
{ {
} }
~QOpenGLVertexArrayObjectPrivate()
{
if (vaoFuncsType == ARB || vaoFuncsType == APPLE || vaoFuncsType == OES)
delete vaoFuncs.helper;
}
bool create(); bool create();
void destroy(); void destroy();
void bind(); void bind();
@ -167,7 +181,7 @@ bool QOpenGLVertexArrayObjectPrivate::create()
if (ctx->isOpenGLES()) { if (ctx->isOpenGLES()) {
if (ctx->format().majorVersion() >= 3 || ctx->hasExtension(QByteArrayLiteral("GL_OES_vertex_array_object"))) { if (ctx->format().majorVersion() >= 3 || ctx->hasExtension(QByteArrayLiteral("GL_OES_vertex_array_object"))) {
vaoFuncs.helper = new QOpenGLVertexArrayObjectHelper(ctx); vaoFuncs.helper = QOpenGLVertexArrayObjectHelper::vertexArrayObjectHelperForContext(ctx);
vaoFuncsType = OES; vaoFuncsType = OES;
vaoFuncs.helper->glGenVertexArrays(1, &vao); vaoFuncs.helper->glGenVertexArrays(1, &vao);
} }
@ -187,11 +201,11 @@ bool QOpenGLVertexArrayObjectPrivate::create()
} else } else
#endif #endif
if (ctx->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) { if (ctx->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) {
vaoFuncs.helper = new QOpenGLVertexArrayObjectHelper(ctx); vaoFuncs.helper = QOpenGLVertexArrayObjectHelper::vertexArrayObjectHelperForContext(ctx);
vaoFuncsType = ARB; vaoFuncsType = ARB;
vaoFuncs.helper->glGenVertexArrays(1, &vao); vaoFuncs.helper->glGenVertexArrays(1, &vao);
} else if (ctx->hasExtension(QByteArrayLiteral("GL_APPLE_vertex_array_object"))) { } else if (ctx->hasExtension(QByteArrayLiteral("GL_APPLE_vertex_array_object"))) {
vaoFuncs.helper = new QOpenGLVertexArrayObjectHelper(ctx); vaoFuncs.helper = QOpenGLVertexArrayObjectHelper::vertexArrayObjectHelperForContext(ctx);
vaoFuncsType = APPLE; vaoFuncsType = APPLE;
vaoFuncs.helper->glGenVertexArrays(1, &vao); vaoFuncs.helper->glGenVertexArrays(1, &vao);
} }

View File

@ -57,25 +57,27 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QOpenGLVertexArrayObjectHelper;
class QOpenGLContext; class QOpenGLContext;
void Q_OPENGL_EXPORT qtInitializeVertexArrayObjectHelper(QOpenGLVertexArrayObjectHelper *helper, QOpenGLContext *context);
class QOpenGLVertexArrayObjectHelper class QOpenGLVertexArrayObjectHelper
{ {
Q_DISABLE_COPY(QOpenGLVertexArrayObjectHelper) Q_DISABLE_COPY(QOpenGLVertexArrayObjectHelper)
public: private:
explicit inline QOpenGLVertexArrayObjectHelper(QOpenGLContext *context) explicit inline QOpenGLVertexArrayObjectHelper(QOpenGLContext *context)
: GenVertexArrays(nullptr) : GenVertexArrays(nullptr)
, DeleteVertexArrays(nullptr) , DeleteVertexArrays(nullptr)
, BindVertexArray(nullptr) , BindVertexArray(nullptr)
, IsVertexArray(nullptr) , IsVertexArray(nullptr)
{ {
qtInitializeVertexArrayObjectHelper(this, context); initializeFromContext(context);
} }
void Q_OPENGL_EXPORT initializeFromContext(QOpenGLContext *context);
public:
static Q_OPENGL_EXPORT QOpenGLVertexArrayObjectHelper *vertexArrayObjectHelperForContext(QOpenGLContext *context);
inline bool isValid() const inline bool isValid() const
{ {
return GenVertexArrays && DeleteVertexArrays && BindVertexArray && IsVertexArray; return GenVertexArrays && DeleteVertexArrays && BindVertexArray && IsVertexArray;
@ -101,9 +103,6 @@ public:
return IsVertexArray(array); return IsVertexArray(array);
} }
private:
friend void Q_OPENGL_EXPORT qtInitializeVertexArrayObjectHelper(QOpenGLVertexArrayObjectHelper *helper, QOpenGLContext *context);
// Function signatures are equivalent between desktop core, ARB, APPLE, ES 3 and ES 2 extensions // Function signatures are equivalent between desktop core, ARB, APPLE, ES 3 and ES 2 extensions
typedef void (QOPENGLF_APIENTRYP qt_GenVertexArrays_t)(GLsizei n, GLuint *arrays); typedef void (QOPENGLF_APIENTRYP qt_GenVertexArrays_t)(GLsizei n, GLuint *arrays);
typedef void (QOPENGLF_APIENTRYP qt_DeleteVertexArrays_t)(GLsizei n, const GLuint *arrays); typedef void (QOPENGLF_APIENTRYP qt_DeleteVertexArrays_t)(GLsizei n, const GLuint *arrays);

View File

@ -375,7 +375,7 @@ struct StateSaver
{ {
StateSaver() { StateSaver() {
f = QOpenGLContext::currentContext()->functions(); f = QOpenGLContext::currentContext()->functions();
vaoHelper = new QOpenGLVertexArrayObjectHelper(QOpenGLContext::currentContext()); vaoHelper = QOpenGLVertexArrayObjectHelper::vertexArrayObjectHelperForContext(QOpenGLContext::currentContext());
static bool windowsChecked = false; static bool windowsChecked = false;
static bool shouldSave = true; static bool shouldSave = true;
@ -446,7 +446,6 @@ struct StateSaver
f->glVertexAttribPointer(i, va[i].size, va[i].type, va[i].normalized, va[i].stride, va[i].pointer); f->glVertexAttribPointer(i, va[i].size, va[i].type, va[i].normalized, va[i].stride, va[i].pointer);
} }
} }
delete vaoHelper;
} }
QOpenGLFunctions *f; QOpenGLFunctions *f;
QOpenGLVertexArrayObjectHelper *vaoHelper; QOpenGLVertexArrayObjectHelper *vaoHelper;