Move GL resource handling enablers to QtGui.

Made resource handling more robust by attempting to free GL resources in
the correct thread, and not forcing a context to become current to free
resources.

Change-Id: Ie81d4005b608972375755571d9b50ce82080709b
Reviewed-on: http://codereview.qt.nokia.com/3258
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
This commit is contained in:
Samuel Rødal 2011-08-16 09:29:44 +02:00
parent 00fd783a39
commit aaa4a26f82
20 changed files with 775 additions and 488 deletions

View File

@ -51,6 +51,7 @@ qpa {
kernel/qplatformwindow_qpa.h \
kernel/qplatformglcontext_qpa.h \
kernel/qguiglcontext_qpa.h \
kernel/qguiglcontext_qpa_p.h \
kernel/qplatformcursor_qpa.h \
kernel/qplatformclipboard_qpa.h \
kernel/qplatformnativeinterface_qpa.h \

View File

@ -41,6 +41,7 @@
#include "qplatformglcontext_qpa.h"
#include "qguiglcontext_qpa.h"
#include "qguiglcontext_qpa_p.h"
#include "qwindow.h"
#include <QtCore/QThreadStorage>
@ -63,35 +64,6 @@ public:
static QThreadStorage<QGuiGLThreadContext *> qwindow_context_storage;
class QGuiGLContextPrivate
{
public:
QGuiGLContextPrivate()
: qGLContextHandle(0)
, platformGLContext(0)
, shareContext(0)
, screen(0)
, surface(0)
{
}
virtual ~QGuiGLContextPrivate()
{
//do not delete the QGLContext handle here as it is deleted in
//QWidgetPrivate::deleteTLSysExtra()
}
void *qGLContextHandle;
void (*qGLContextDeleteFunction)(void *handle);
QSurfaceFormat requestedFormat;
QPlatformGLContext *platformGLContext;
QGuiGLContext *shareContext;
QScreen *screen;
QSurface *surface;
static void setCurrentContext(QGuiGLContext *context);
};
void QGuiGLContextPrivate::setCurrentContext(QGuiGLContext *context)
{
QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
@ -118,6 +90,11 @@ QGuiGLContext* QGuiGLContext::currentContext()
return 0;
}
bool QGuiGLContext::areSharing(QGuiGLContext *first, QGuiGLContext *second)
{
return first->shareGroup() == second->shareGroup();
}
QPlatformGLContext *QGuiGLContext::handle() const
{
Q_D(const QGuiGLContext);
@ -136,7 +113,7 @@ QPlatformGLContext *QGuiGLContext::shareHandle() const
Creates a new GL context instance, you need to call create() before it can be used.
*/
QGuiGLContext::QGuiGLContext()
: d_ptr(new QGuiGLContextPrivate())
: QObject(*new QGuiGLContextPrivate())
{
Q_D(QGuiGLContext);
d->screen = QGuiApplication::primaryScreen();
@ -174,7 +151,7 @@ void QGuiGLContext::setScreen(QScreen *screen)
/*!
Attempts to create the GL context with the desired parameters.
Returns true if the native context was successfully created and is ready to be used.d
Returns true if the native context was successfully created and is ready to be used.
*/
bool QGuiGLContext::create()
{
@ -183,6 +160,8 @@ bool QGuiGLContext::create()
Q_D(QGuiGLContext);
d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformGLContext(this);
d->platformGLContext->setContext(this);
d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QGuiGLContextGroup;
d->shareGroup->d_func()->addContext(this);
return d->platformGLContext;
}
@ -191,6 +170,9 @@ void QGuiGLContext::destroy()
Q_D(QGuiGLContext);
if (QGuiGLContext::currentContext() == this)
doneCurrent();
if (d->shareGroup)
d->shareGroup->d_func()->removeContext(this);
d->shareGroup = 0;
delete d->platformGLContext;
d->platformGLContext = 0;
}
@ -232,6 +214,9 @@ bool QGuiGLContext::makeCurrent(QSurface *surface)
if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) {
QGuiGLContextPrivate::setCurrentContext(this);
d->surface = surface;
d->shareGroup->d_func()->deletePendingResources(this);
return true;
}
@ -247,6 +232,9 @@ void QGuiGLContext::doneCurrent()
if (!d->platformGLContext)
return;
if (QGuiGLContext::currentContext() == this)
d->shareGroup->d_func()->deletePendingResources(this);
d->platformGLContext->doneCurrent();
QGuiGLContextPrivate::setCurrentContext(0);
@ -293,6 +281,12 @@ QSurfaceFormat QGuiGLContext::format() const
return d->platformGLContext->format();
}
QGuiGLContextGroup *QGuiGLContext::shareGroup() const
{
Q_D(const QGuiGLContext);
return d->shareGroup;
}
QGuiGLContext *QGuiGLContext::shareContext() const
{
Q_D(const QGuiGLContext);
@ -331,3 +325,176 @@ void QGuiGLContext::deleteQGLContext()
d->qGLContextHandle = 0;
}
}
QGuiGLContextGroup::QGuiGLContextGroup()
: QObject(*new QGuiGLContextGroupPrivate())
{
}
QGuiGLContextGroup::~QGuiGLContextGroup()
{
Q_D(QGuiGLContextGroup);
QList<QGLSharedResource *>::iterator it = d->m_sharedResources.begin();
QList<QGLSharedResource *>::iterator end = d->m_sharedResources.end();
while (it != end) {
(*it)->invalidateResource();
(*it)->m_group = 0;
++it;
}
qDeleteAll(d->m_pendingDeletion.begin(), d->m_pendingDeletion.end());
}
QList<QGuiGLContext *> QGuiGLContextGroup::shares() const
{
Q_D(const QGuiGLContextGroup);
return d->m_shares;
}
QGuiGLContextGroup *QGuiGLContextGroup::currentContextGroup()
{
QGuiGLContext *current = QGuiGLContext::currentContext();
return current ? current->shareGroup() : 0;
}
void QGuiGLContextGroupPrivate::addContext(QGuiGLContext *ctx)
{
QMutexLocker locker(&m_mutex);
m_refs.ref();
m_shares << ctx;
}
void QGuiGLContextGroupPrivate::removeContext(QGuiGLContext *ctx)
{
Q_Q(QGuiGLContextGroup);
QMutexLocker locker(&m_mutex);
m_shares.removeOne(ctx);
if (ctx == m_context && !m_shares.isEmpty())
m_context = m_shares.first();
if (!m_refs.deref())
q->deleteLater();
}
void QGuiGLContextGroupPrivate::deletePendingResources(QGuiGLContext *ctx)
{
QMutexLocker locker(&m_mutex);
QList<QGLSharedResource *>::iterator it = m_pendingDeletion.begin();
QList<QGLSharedResource *>::iterator end = m_pendingDeletion.end();
while (it != end) {
(*it)->freeResource(ctx);
delete *it;
++it;
}
m_pendingDeletion.clear();
}
QGLSharedResource::QGLSharedResource(QGuiGLContextGroup *group)
: m_group(group)
{
QMutexLocker locker(&m_group->d_func()->m_mutex);
m_group->d_func()->m_sharedResources << this;
}
QGLSharedResource::~QGLSharedResource()
{
}
// schedule the resource for deletion at an appropriate time
void QGLSharedResource::free()
{
if (!m_group) {
delete this;
return;
}
QMutexLocker locker(&m_group->d_func()->m_mutex);
m_group->d_func()->m_sharedResources.removeOne(this);
m_group->d_func()->m_pendingDeletion << this;
// can we delete right away?
QGuiGLContext *current = QGuiGLContext::currentContext();
if (current && current->shareGroup() == m_group) {
m_group->d_func()->deletePendingResources(current);
}
}
QGLMultiGroupSharedResource::QGLMultiGroupSharedResource()
: active(0)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Creating context group resource object %p.", this);
#endif
}
QGLMultiGroupSharedResource::~QGLMultiGroupSharedResource()
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
#endif
for (int i = 0; i < m_groups.size(); ++i) {
QGuiGLContext *context = m_groups.at(i)->shares().first();
QGLSharedResource *resource = value(context);
if (resource)
resource->free();
m_groups.at(i)->d_func()->m_resources.remove(this);
active.deref();
}
#ifndef QT_NO_DEBUG
if (active != 0) {
qWarning("QtOpenGL: Resources are still available at program shutdown.\n"
" This is possibly caused by a leaked QGLWidget, \n"
" QGLFramebufferObject or QGLPixelBuffer.");
}
#endif
}
void QGLMultiGroupSharedResource::insert(QGuiGLContext *context, QGLSharedResource *value)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
#endif
QGuiGLContextGroup *group = context->shareGroup();
Q_ASSERT(!group->d_func()->m_resources.contains(this));
group->d_func()->m_resources.insert(this, value);
m_groups.append(group);
active.ref();
}
QGLSharedResource *QGLMultiGroupSharedResource::value(QGuiGLContext *context)
{
QGuiGLContextGroup *group = context->shareGroup();
return group->d_func()->m_resources.value(this, 0);
}
void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx)
{
QGLSharedResource *resource = value(ctx);
if (resource != 0) {
resource->free();
QGuiGLContextGroup *group = ctx->shareGroup();
group->d_func()->m_resources.remove(this);
m_groups.removeOne(group);
active.deref();
}
}
void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx, QGLSharedResource *value)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Cleaning up context group resource %p, for context %p in thread %p.", this, ctx, QThread::currentThread());
#endif
value->free();
active.deref();
QGuiGLContextGroup *group = ctx->shareGroup();
m_groups.removeOne(group);
}

View File

@ -54,12 +54,34 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QGuiGLContextPrivate;
class QGuiGLContextGroupPrivate;
class QPlatformGLContext;
class QSurface;
class Q_GUI_EXPORT QGuiGLContext
class Q_GUI_EXPORT QGuiGLContextGroup : public QObject
{
Q_DECLARE_PRIVATE(QGuiGLContext);
Q_OBJECT
Q_DECLARE_PRIVATE(QGuiGLContextGroup)
public:
~QGuiGLContextGroup();
QList<QGuiGLContext *> shares() const;
static QGuiGLContextGroup *currentContextGroup();
private:
QGuiGLContextGroup();
friend class QGuiGLContext;
friend class QGLContextGroupResourceBase;
friend class QGLSharedResource;
friend class QGLMultiGroupSharedResource;
};
class Q_GUI_EXPORT QGuiGLContext : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QGuiGLContext);
public:
QGuiGLContext();
~QGuiGLContext();
@ -73,6 +95,7 @@ public:
QSurfaceFormat format() const;
QGuiGLContext *shareContext() const;
QGuiGLContextGroup *shareGroup() const;
QScreen *screen() const;
bool makeCurrent(QSurface *surface);
@ -84,15 +107,15 @@ public:
QSurface *surface() const;
static QGuiGLContext *currentContext();
static bool areSharing(QGuiGLContext *first, QGuiGLContext *second);
QPlatformGLContext *handle() const;
QPlatformGLContext *shareHandle() const;
private:
QScopedPointer<QGuiGLContextPrivate> d_ptr;
//hack to make it work with QGLContext::CurrentContext
friend class QGLContext;
friend class QGLContextResourceBase;
friend class QWidgetPrivate;
void *qGLContextHandle() const;
@ -100,8 +123,6 @@ private:
void deleteQGLContext();
void destroy();
Q_DISABLE_COPY(QGuiGLContext);
};
QT_END_NAMESPACE

View File

@ -0,0 +1,181 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenGL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QGUIGLCONTEXT_P_H
#define QGUIGLCONTEXT_P_H
#include "qguiglcontext_qpa.h"
#include <private/qobject_p.h>
#include <qmutex.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QGuiGLContext;
class QGLMultiGroupSharedResource;
class Q_GUI_EXPORT QGLSharedResource
{
public:
QGLSharedResource(QGuiGLContextGroup *group);
virtual ~QGLSharedResource() = 0;
QGuiGLContextGroup *group() const { return m_group; }
// schedule the resource for deletion at an appropriate time
void free();
protected:
// the resource's share group no longer exists, invalidate the resource
virtual void invalidateResource() = 0;
// a valid context in the group is current, free the resource
virtual void freeResource(QGuiGLContext *context) = 0;
private:
QGuiGLContextGroup *m_group;
friend class QGuiGLContextGroup;
friend class QGuiGLContextGroupPrivate;
Q_DISABLE_COPY(QGLSharedResource);
};
class Q_GUI_EXPORT QGuiGLContextGroupPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QGuiGLContextGroup);
public:
QGuiGLContextGroupPrivate()
: m_context(0)
, m_mutex(QMutex::Recursive)
, m_refs(0)
{
}
void addContext(QGuiGLContext *ctx);
void removeContext(QGuiGLContext *ctx);
void deletePendingResources(QGuiGLContext *ctx);
QGuiGLContext *m_context;
QList<QGuiGLContext *> m_shares;
QMutex m_mutex;
QHash<QGLMultiGroupSharedResource *, QGLSharedResource *> m_resources;
QAtomicInt m_refs;
QList<QGLSharedResource *> m_sharedResources;
QList<QGLSharedResource *> m_pendingDeletion;
void cleanupResources(QGuiGLContext *ctx);
};
class Q_GUI_EXPORT QGLMultiGroupSharedResource
{
public:
QGLMultiGroupSharedResource();
~QGLMultiGroupSharedResource();
void insert(QGuiGLContext *context, QGLSharedResource *value);
void cleanup(QGuiGLContext *context);
void cleanup(QGuiGLContext *context, QGLSharedResource *value);
QGLSharedResource *value(QGuiGLContext *context);
template <typename T>
T *value(QGuiGLContext *context) {
QGuiGLContextGroup *group = context->shareGroup();
T *resource = static_cast<T *>(group->d_func()->m_resources.value(this, 0));
if (!resource) {
resource = new T(context);
insert(context, resource);
}
return resource;
}
private:
QAtomicInt active;
QList<QGuiGLContextGroup *> m_groups;
};
class Q_GUI_EXPORT QGuiGLContextPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QGuiGLContext);
public:
QGuiGLContextPrivate()
: qGLContextHandle(0)
, platformGLContext(0)
, shareContext(0)
, shareGroup(0)
, screen(0)
, surface(0)
{
}
virtual ~QGuiGLContextPrivate()
{
//do not delete the QGLContext handle here as it is deleted in
//QWidgetPrivate::deleteTLSysExtra()
}
void *qGLContextHandle;
void (*qGLContextDeleteFunction)(void *handle);
QSurfaceFormat requestedFormat;
QPlatformGLContext *platformGLContext;
QGuiGLContext *shareContext;
QGuiGLContextGroup *shareGroup;
QScreen *screen;
QSurface *surface;
QHash<QGLMultiGroupSharedResource *, void *> m_resources;
static void setCurrentContext(QGuiGLContext *context);
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QGUIGLCONTEXT_P_H

View File

@ -65,6 +65,8 @@
/*! \fn void QPlatformGLContext::swapBuffers()
Reimplement in subclass to native swap buffers calls
The implementation must support being called in a thread different than the gui-thread.
*/
/*! \fn void *QPlatformGLContext::getProcAddress(const QString &procName)

View File

@ -44,6 +44,8 @@
#include "qpaintengineex_opengl2_p.h"
#include "qglshadercache_p.h"
#include <QtGui/private/qguiglcontext_qpa_p.h>
#if defined(QT_DEBUG)
#include <QMetaEnum>
#endif
@ -52,18 +54,50 @@
QT_BEGIN_NAMESPACE
class QGLEngineSharedShadersResource : public QGLSharedResource
{
public:
QGLEngineSharedShadersResource(QGuiGLContext *ctx)
: QGLSharedResource(ctx->shareGroup())
, m_shaders(new QGLEngineSharedShaders(QGLContext::fromGuiGLContext(ctx)))
{
}
~QGLEngineSharedShadersResource()
{
delete m_shaders;
}
void invalidateResource()
{
delete m_shaders;
m_shaders = 0;
}
void freeResource(QGuiGLContext *)
{
}
QGLEngineSharedShaders *shaders() const { return m_shaders; }
private:
QGLEngineSharedShaders *m_shaders;
};
class QGLShaderStorage
{
public:
QGLEngineSharedShaders *shadersForThread(const QGLContext *context) {
QGLContextGroupResource<QGLEngineSharedShaders> *&shaders = m_storage.localData();
QGLMultiGroupSharedResource *&shaders = m_storage.localData();
if (!shaders)
shaders = new QGLContextGroupResource<QGLEngineSharedShaders>();
return shaders->value(context);
shaders = new QGLMultiGroupSharedResource;
QGLEngineSharedShadersResource *resource =
shaders->value<QGLEngineSharedShadersResource>(context->contextHandle());
return resource ? resource->shaders() : 0;
}
private:
QThreadStorage<QGLContextGroupResource<QGLEngineSharedShaders> *> m_storage;
QThreadStorage<QGLMultiGroupSharedResource *> m_storage;
};
Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage);
@ -81,8 +115,7 @@ const char* QGLEngineSharedShaders::qShaderSnippets[] = {
};
QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
: ctxGuard(context)
, blitShaderProg(0)
: blitShaderProg(0)
, simpleShaderProg(0)
{
@ -327,14 +360,14 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
vertexSource.append(qShaderSnippets[prog.mainVertexShader]);
vertexSource.append(qShaderSnippets[prog.positionVertexShader]);
QScopedPointer<QGLShaderProgram> shaderProgram(new QGLShaderProgram(ctxGuard.context(), 0));
QScopedPointer<QGLShaderProgram> shaderProgram(new QGLShaderProgram);
CachedShader shaderCache(fragSource, vertexSource);
bool inCache = shaderCache.load(shaderProgram.data(), ctxGuard.context());
bool inCache = shaderCache.load(shaderProgram.data(), QGLContext::currentContext());
if (!inCache) {
QScopedPointer<QGLShader> fragShader(new QGLShader(QGLShader::Fragment, ctxGuard.context(), 0));
QScopedPointer<QGLShader> fragShader(new QGLShader(QGLShader::Fragment));
QByteArray description;
#if defined(QT_DEBUG)
// Name the shader for easier debugging
@ -357,7 +390,7 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
break;
}
QScopedPointer<QGLShader> vertexShader(new QGLShader(QGLShader::Vertex, ctxGuard.context(), 0));
QScopedPointer<QGLShader> vertexShader(new QGLShader(QGLShader::Vertex));
#if defined(QT_DEBUG)
// Name the shader for easier debugging
description.clear();
@ -396,7 +429,7 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
newProg->program->link();
if (newProg->program->isLinked()) {
if (!inCache)
shaderCache.store(newProg->program, ctxGuard.context());
shaderCache.store(newProg->program, QGLContext::currentContext());
} else {
QLatin1String none("none");
QLatin1String br("\n");

View File

@ -365,7 +365,6 @@ public:
void cleanupCustomStage(QGLCustomShaderStage* stage);
private:
QGLSharedResourceGuard ctxGuard;
QGLShaderProgram *blitShaderProg;
QGLShaderProgram *simpleShaderProg;
QList<QGLEngineShaderProg*> cachedPrograms;

View File

@ -51,21 +51,42 @@ class QGL2GradientCacheWrapper
public:
QGL2GradientCache *cacheForContext(const QGLContext *context) {
QMutexLocker lock(&m_mutex);
return m_resource.value(context);
return m_resource.value<QGL2GradientCache>(context->contextHandle());
}
private:
QGLContextGroupResource<QGL2GradientCache> m_resource;
QGLMultiGroupSharedResource m_resource;
QMutex m_mutex;
};
Q_GLOBAL_STATIC(QGL2GradientCacheWrapper, qt_gradient_caches)
QGL2GradientCache::QGL2GradientCache(QGuiGLContext *ctx)
: QGLSharedResource(ctx->shareGroup())
{
}
QGL2GradientCache::~QGL2GradientCache()
{
cache.clear();
}
QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
{
return qt_gradient_caches()->cacheForContext(context);
}
void QGL2GradientCache::invalidateResource()
{
QMutexLocker lock(&m_mutex);
cache.clear();
}
void QGL2GradientCache::freeResource(QGuiGLContext *)
{
cleanCache();
}
void QGL2GradientCache::cleanCache()
{
QMutexLocker lock(&m_mutex);

View File

@ -58,7 +58,7 @@
QT_BEGIN_NAMESPACE
class QGL2GradientCache
class QGL2GradientCache : public QGLSharedResource
{
struct CacheInfo
{
@ -76,12 +76,15 @@ class QGL2GradientCache
public:
static QGL2GradientCache *cacheForContext(const QGLContext *context);
QGL2GradientCache(const QGLContext *) {}
~QGL2GradientCache() { cleanCache(); }
QGL2GradientCache(QGuiGLContext *);
~QGL2GradientCache();
GLuint getBuffer(const QGradient &gradient, qreal opacity);
inline int paletteSize() const { return 1024; }
void invalidateResource();
void freeResource(QGuiGLContext *ctx);
private:
inline int maxCacheSize() const { return 60; }
inline void generateGradientColorTable(const QGradient& gradient,

View File

@ -1580,10 +1580,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
QGLTextureGlyphCache *cache =
(QGLTextureGlyphCache *) staticTextItem->fontEngine()->glyphCache(cacheKey, glyphType, QTransform());
if (!cache || cache->cacheType() != glyphType || cache->context() == 0) {
cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
if (!cache || cache->cacheType() != glyphType || cache->contextGroup() == 0) {
cache = new QGLTextureGlyphCache(glyphType, QTransform());
staticTextItem->fontEngine()->setGlyphCache(cacheKey, cache);
cache->insert(ctx, cache);
recreateVertexArrays = true;
}

View File

@ -51,19 +51,16 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled;
QBasicAtomicInt qgltextureglyphcache_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
QGLTextureGlyphCache::QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
: QImageTextureGlyphCache(type, matrix), QGLContextGroupResourceBase()
, ctx(0)
QGLTextureGlyphCache::QGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix)
: QImageTextureGlyphCache(type, matrix)
, pex(0)
, m_blitProgram(0)
, m_filterMode(Nearest)
, m_serialNumber(qgltextureglyphcache_serial_number.fetchAndAddRelaxed(1))
{
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, ctx);
qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, QGuiGLContext::currentContext());
#endif
setContext(context);
m_vertexCoordinateArray[0] = -1.0f;
m_vertexCoordinateArray[1] = -1.0f;
m_vertexCoordinateArray[2] = 1.0f;
@ -91,14 +88,9 @@ QGLTextureGlyphCache::~QGLTextureGlyphCache()
delete m_blitProgram;
}
void QGLTextureGlyphCache::setContext(const QGLContext *context)
{
ctx = context;
m_h = 0;
}
void QGLTextureGlyphCache::createTextureData(int width, int height)
{
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
if (ctx == 0) {
qWarning("QGLTextureGlyphCache::createTextureData: Called with no context");
return;
@ -116,12 +108,17 @@ void QGLTextureGlyphCache::createTextureData(int width, int height)
if (height < 16)
height = 16;
QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
glGenTextures(1, &glyphTexture->m_texture);
glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
if (m_textureResource && !m_textureResource->m_texture)
delete m_textureResource;
glyphTexture->m_width = width;
glyphTexture->m_height = height;
if (!m_textureResource)
m_textureResource = new QGLGlyphTexture(ctx);
glGenTextures(1, &m_textureResource->m_texture);
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
m_textureResource->m_width = width;
m_textureResource->m_height = height;
if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
QVarLengthArray<uchar> data(width * height * 4);
@ -144,14 +141,14 @@ void QGLTextureGlyphCache::createTextureData(int width, int height)
void QGLTextureGlyphCache::resizeTextureData(int width, int height)
{
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
if (ctx == 0) {
qWarning("QGLTextureGlyphCache::resizeTextureData: Called with no context");
return;
}
QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
int oldWidth = glyphTexture->m_width;
int oldHeight = glyphTexture->m_height;
int oldWidth = m_textureResource->m_width;
int oldHeight = m_textureResource->m_height;
// Make the lower glyph texture size 16 x 16.
if (width < 16)
@ -159,7 +156,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
if (height < 16)
height = 16;
GLuint oldTexture = glyphTexture->m_texture;
GLuint oldTexture = m_textureResource->m_texture;
createTextureData(width, height);
if (ctx->d_ptr->workaround_brokenFBOReadBack) {
@ -173,7 +170,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
// ### the QTextureGlyphCache API needs to be reworked to allow
// ### resizeTextureData to fail
glBindFramebuffer(GL_FRAMEBUFFER_EXT, glyphTexture->m_fbo);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_textureResource->m_fbo);
GLuint tmp_texture;
glGenTextures(1, &tmp_texture);
@ -257,7 +254,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
@ -276,16 +273,16 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition)
{
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
if (ctx == 0) {
qWarning("QGLTextureGlyphCache::fillTexture: Called with no context");
return;
}
QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
if (ctx->d_ptr->workaround_brokenFBOReadBack) {
QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition);
glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
const QImage &texture = image();
const uchar *bits = texture.constBits();
bits += c.y * texture.bytesPerLine() + c.x;
@ -322,7 +319,7 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed sub
}
}
glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
if (mask.format() == QImage::Format_RGB32) {
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
} else {
@ -358,6 +355,7 @@ int QGLTextureGlyphCache::glyphPadding() const
int QGLTextureGlyphCache::maxTextureWidth() const
{
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
if (ctx == 0)
return QImageTextureGlyphCache::maxTextureWidth();
else
@ -366,6 +364,7 @@ int QGLTextureGlyphCache::maxTextureWidth() const
int QGLTextureGlyphCache::maxTextureHeight() const
{
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
if (ctx == 0)
return QImageTextureGlyphCache::maxTextureHeight();
@ -377,16 +376,15 @@ int QGLTextureGlyphCache::maxTextureHeight() const
void QGLTextureGlyphCache::clear()
{
if (ctx != 0) {
m_textureResource.cleanup(ctx);
m_textureResource->free();
m_textureResource = 0;
m_w = 0;
m_h = 0;
m_cx = 0;
m_cy = 0;
m_currentRowHeight = 0;
coords.clear();
}
m_w = 0;
m_h = 0;
m_cx = 0;
m_cy = 0;
m_currentRowHeight = 0;
coords.clear();
}
QT_END_NAMESPACE

View File

@ -63,10 +63,11 @@ QT_BEGIN_NAMESPACE
class QGL2PaintEngineExPrivate;
struct QGLGlyphTexture
struct QGLGlyphTexture : public QGLSharedResource
{
QGLGlyphTexture(const QGLContext *ctx)
: m_width(0)
: QGLSharedResource(ctx->contextHandle()->shareGroup())
, m_width(0)
, m_height(0)
{
if (ctx && !ctx->d_ptr->workaround_brokenFBOReadBack)
@ -77,19 +78,24 @@ struct QGLGlyphTexture
#endif
}
~QGLGlyphTexture() {
const QGLContext *ctx = QGLContext::currentContext();
void freeResource(QGuiGLContext *context)
{
const QGLContext *ctx = QGLContext::fromGuiGLContext(context);
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
qDebug("~QGLGlyphTexture() %p for context %p.", this, ctx);
#endif
// At this point, the context group is made current, so it's safe to
// release resources without a makeCurrent() call
if (ctx) {
if (!ctx->d_ptr->workaround_brokenFBOReadBack)
glDeleteFramebuffers(1, &m_fbo);
if (m_width || m_height)
glDeleteTextures(1, &m_texture);
}
if (!ctx->d_ptr->workaround_brokenFBOReadBack)
glDeleteFramebuffers(1, &m_fbo);
if (m_width || m_height)
glDeleteTextures(1, &m_texture);
}
void invalidateResource()
{
m_texture = 0;
m_fbo = 0;
m_width = 0;
m_height = 0;
}
GLuint m_texture;
@ -98,10 +104,10 @@ struct QGLGlyphTexture
int m_height;
};
class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QImageTextureGlyphCache, public QGLContextGroupResourceBase
class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QImageTextureGlyphCache
{
public:
QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
QGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix);
~QGLTextureGlyphCache();
virtual void createTextureData(int width, int height);
@ -113,25 +119,24 @@ public:
inline GLuint texture() const {
QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
QGLGlyphTexture *glyphTexture = that->m_textureResource;
return glyphTexture ? glyphTexture->m_texture : 0;
}
inline int width() const {
QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
QGLGlyphTexture *glyphTexture = that->m_textureResource;
return glyphTexture ? glyphTexture->m_width : 0;
}
inline int height() const {
QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
QGLGlyphTexture *glyphTexture = that->m_textureResource;
return glyphTexture ? glyphTexture->m_height : 0;
}
inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
void setContext(const QGLContext *context);
inline const QGLContext *context() const { return ctx; }
inline const QGuiGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : 0; }
inline int serialNumber() const { return m_serialNumber; }
@ -144,12 +149,9 @@ public:
void clear();
void freeResource(void *) { ctx = 0; }
private:
QGLContextGroupResource<QGLGlyphTexture> m_textureResource;
QGLGlyphTexture *m_textureResource;
const QGLContext *ctx;
QGL2PaintEngineExPrivate *pex;
QGLShaderProgram *m_blitProgram;
FilterMode m_filterMode;

View File

@ -1476,42 +1476,16 @@ Q_GLOBAL_STATIC(QGLContextGroupList, qt_context_groups)
*****************************************************************************/
QGLContextGroup::QGLContextGroup(const QGLContext *context)
: m_context(context), m_guards(0), m_refs(1)
: m_context(context), m_refs(1)
{
qt_context_groups()->append(this);
}
QGLContextGroup::~QGLContextGroup()
{
// Clear any remaining QGLSharedResourceGuard objects on the group.
QGLSharedResourceGuard *guard = m_guards;
while (guard != 0) {
guard->m_group = 0;
guard->m_id = 0;
guard = guard->m_next;
}
qt_context_groups()->remove(this);
}
void QGLContextGroup::addGuard(QGLSharedResourceGuard *guard)
{
if (m_guards)
m_guards->m_prev = guard;
guard->m_next = m_guards;
guard->m_prev = 0;
m_guards = guard;
}
void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard)
{
if (guard->m_next)
guard->m_next->m_prev = guard->m_prev;
if (guard->m_prev)
guard->m_prev->m_next = guard->m_next;
else
m_guards = guard->m_next;
}
const QGLContext *qt_gl_transfer_context(const QGLContext *ctx)
{
if (!ctx)
@ -1934,8 +1908,6 @@ QGLContext::~QGLContext()
// clean up resources specific to this context
d_ptr->cleanup();
// clean up resources belonging to this context's group
d_ptr->group->cleanupResources(this);
QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
reset();
@ -5017,108 +4989,6 @@ void QGLContextGroup::removeShare(const QGLContext *context) {
group->m_shares.clear();
}
QGLContextGroupResourceBase::QGLContextGroupResourceBase()
: active(0)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Creating context group resource object %p.", this);
#endif
}
QGLContextGroupResourceBase::~QGLContextGroupResourceBase()
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
#endif
for (int i = 0; i < m_groups.size(); ++i) {
m_groups.at(i)->m_resources.remove(this);
active.deref();
}
#ifndef QT_NO_DEBUG
if (active != 0) {
qWarning("QtOpenGL: Resources are still available at program shutdown.\n"
" This is possibly caused by a leaked QGLWidget, \n"
" QGLFramebufferObject or QGLPixelBuffer.");
}
#endif
}
void QGLContextGroupResourceBase::insert(const QGLContext *context, void *value)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
#endif
QGLContextGroup *group = QGLContextPrivate::contextGroup(context);
Q_ASSERT(!group->m_resources.contains(this));
group->m_resources.insert(this, value);
m_groups.append(group);
active.ref();
}
void *QGLContextGroupResourceBase::value(const QGLContext *context)
{
QGLContextGroup *group = QGLContextPrivate::contextGroup(context);
return group->m_resources.value(this, 0);
}
void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx)
{
void *resource = value(ctx);
if (resource != 0) {
QGLShareContextScope scope(ctx);
freeResource(resource);
QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx);
group->m_resources.remove(this);
m_groups.removeOne(group);
active.deref();
}
}
void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx, void *value)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Cleaning up context group resource %p, for context %p in thread %p.", this, ctx, QThread::currentThread());
#endif
QGLShareContextScope scope(ctx);
freeResource(value);
active.deref();
QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx);
m_groups.removeOne(group);
}
void QGLContextGroup::cleanupResources(const QGLContext *context)
{
// If there are still shares, then no cleanup to be done yet.
if (m_shares.size() > 1)
return;
// Iterate over all resources and free each in turn.
QHash<QGLContextGroupResourceBase *, void *>::ConstIterator it;
for (it = m_resources.begin(); it != m_resources.end(); ++it)
it.key()->cleanup(context, it.value());
}
QGLSharedResourceGuard::~QGLSharedResourceGuard()
{
if (m_group)
m_group->removeGuard(this);
}
void QGLSharedResourceGuard::setContext(const QGLContext *context)
{
if (m_group)
m_group->removeGuard(this);
if (context) {
m_group = QGLContextPrivate::contextGroup(context);
m_group->addGuard(this);
} else {
m_group = 0;
}
}
QSize QGLTexture::bindCompressedTexture
(const QString& fileName, const char *format)
{

View File

@ -374,7 +374,6 @@ private:
friend class QGLTextureGlyphCache;
friend struct QGLGlyphTexture;
friend class QGLContextGroup;
friend class QGLSharedResourceGuard;
friend class QGLPixmapBlurFilter;
friend class QGLExtensions;
friend class QGLTexture;

View File

@ -61,6 +61,7 @@
#include "QtCore/qhash.h"
#include "QtCore/qatomic.h"
#include "QtWidgets/private/qwidget_p.h"
#include "QtGui/private/qguiglcontext_qpa_p.h"
#include "qcache.h"
#include "qglpaintdevice_p.h"
@ -177,9 +178,6 @@ public:
bool disable_clear_on_painter_begin;
};
class QGLContextGroupResourceBase;
class QGLSharedResourceGuard;
// QGLContextPrivate has the responsibility of creating context groups.
// QGLContextPrivate maintains the reference counter and destroys
// context groups when needed.
@ -193,9 +191,6 @@ public:
bool isSharing() const { return m_shares.size() >= 2; }
QList<const QGLContext *> shares() const { return m_shares; }
void addGuard(QGLSharedResourceGuard *guard);
void removeGuard(QGLSharedResourceGuard *guard);
static void addShare(const QGLContext *context, const QGLContext *share);
static void removeShare(const QGLContext *context);
@ -205,12 +200,8 @@ private:
QGLExtensionFuncs m_extensionFuncs;
const QGLContext *m_context; // context group's representative
QList<const QGLContext *> m_shares;
QHash<QGLContextGroupResourceBase *, void *> m_resources;
QGLSharedResourceGuard *m_guards; // double-linked list of active guards.
QAtomicInt m_refs;
void cleanupResources(const QGLContext *ctx);
friend class QGLContext;
friend class QGLContextPrivate;
friend class QGLContextGroupResourceBase;
@ -539,114 +530,69 @@ QGLTexture* QGLTextureCache::getTexture(QGLContext *ctx, qint64 key)
extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine();
/*
Base for resources that are shared in a context group.
*/
class Q_OPENGL_EXPORT QGLContextGroupResourceBase
{
public:
QGLContextGroupResourceBase();
virtual ~QGLContextGroupResourceBase();
void insert(const QGLContext *context, void *value);
void *value(const QGLContext *context);
void cleanup(const QGLContext *context);
void cleanup(const QGLContext *context, void *value);
virtual void freeResource(void *value) = 0;
protected:
QList<QGLContextGroup *> m_groups;
private:
QAtomicInt active;
};
/*
The QGLContextGroupResource template is used to manage a resource
for a group of sharing GL contexts. When the last context in the
group is destroyed, or when the QGLContextGroupResource object
itself is destroyed (implies potential context switches), the
resource will be freed.
The class used as the template class type needs to have a
constructor with the following signature:
T(const QGLContext *);
*/
template <class T>
class QGLContextGroupResource : public QGLContextGroupResourceBase
{
public:
~QGLContextGroupResource() {
for (int i = 0; i < m_groups.size(); ++i) {
const QGLContext *context = m_groups.at(i)->context();
T *resource = reinterpret_cast<T *>(QGLContextGroupResourceBase::value(context));
if (resource) {
QGLShareContextScope scope(context);
delete resource;
}
}
}
T *value(const QGLContext *context) {
T *resource = reinterpret_cast<T *>(QGLContextGroupResourceBase::value(context));
if (!resource) {
resource = new T(context);
insert(context, resource);
}
return resource;
}
protected:
void freeResource(void *resource) {
delete reinterpret_cast<T *>(resource);
}
};
// Put a guard around a GL object identifier and its context.
// When the context goes away, a shared context will be used
// in its place. If there are no more shared contexts, then
// the identifier is returned as zero - it is assumed that the
// context destruction cleaned up the identifier in this case.
class Q_OPENGL_EXPORT QGLSharedResourceGuard
class Q_OPENGL_EXPORT QGLSharedResourceGuardBase : public QGLSharedResource
{
public:
QGLSharedResourceGuard(const QGLContext *context)
: m_group(0), m_id(0), m_next(0), m_prev(0)
QGLSharedResourceGuardBase(QGLContext *context, GLuint id)
: QGLSharedResource(context->contextHandle()->shareGroup())
, m_id(id)
{
setContext(context);
}
QGLSharedResourceGuard(const QGLContext *context, GLuint id)
: m_group(0), m_id(id), m_next(0), m_prev(0)
{
setContext(context);
}
~QGLSharedResourceGuard();
const QGLContext *context() const
{
return m_group ? m_group->context() : 0;
}
void setContext(const QGLContext *context);
GLuint id() const
{
return m_id;
}
void setId(GLuint id)
protected:
void invalidateResource()
{
m_id = id;
m_id = 0;
}
void freeResource(QGuiGLContext *context)
{
if (m_id) {
freeResource(QGLContext::fromGuiGLContext(context), m_id);
}
}
virtual void freeResource(QGLContext *ctx, GLuint id) = 0;
private:
GLuint m_id;
};
template <typename Func>
class QGLSharedResourceGuard : public QGLSharedResourceGuardBase
{
public:
QGLSharedResourceGuard(QGLContext *context, GLuint id, Func func)
: QGLSharedResourceGuardBase(context, id)
, m_func(func)
{
}
protected:
void freeResource(QGLContext *ctx, GLuint id)
{
m_func(ctx, id);
}
private:
QGLContextGroup *m_group;
GLuint m_id;
QGLSharedResourceGuard *m_next;
QGLSharedResourceGuard *m_prev;
friend class QGLContextGroup;
Func m_func;
};
template <typename Func>
QGLSharedResourceGuardBase *createSharedResourceGuard(QGLContext *context, GLuint id, Func cleanupFunc)
{
return new QGLSharedResourceGuard<Func>(context, id, cleanupFunc);
}
class QGLExtensionMatcher
{

View File

@ -141,7 +141,7 @@ public:
QAtomicInt ref;
QGLBuffer::Type type;
QGLSharedResourceGuard guard;
QGLSharedResourceGuardBase *guard;
QGLBuffer::UsagePattern usagePattern;
QGLBuffer::UsagePattern actualUsagePattern;
};
@ -184,7 +184,7 @@ QGLBuffer::QGLBuffer(const QGLBuffer &other)
d_ptr->ref.ref();
}
#define ctx d->guard.context()
#define ctx QGLContext::currentContext();
/*!
Destroys this buffer object, including the storage being
@ -250,6 +250,14 @@ void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value)
#undef ctx
namespace {
void freeBufferFunc(QGLContext *ctx, GLuint id)
{
Q_UNUSED(ctx);
glDeleteBuffers(1, &id);
}
}
/*!
Creates the buffer object in the GL server. Returns true if
the object was created; false otherwise.
@ -266,24 +274,26 @@ void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value)
bool QGLBuffer::create()
{
Q_D(QGLBuffer);
if (d->guard.id())
if (d->guard && d->guard->id())
return true;
const QGLContext *ctx = QGLContext::currentContext();
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
if (ctx) {
if (!qt_resolve_buffer_extensions(const_cast<QGLContext *>(ctx)))
if (!qt_resolve_buffer_extensions(ctx))
return false;
GLuint bufferId = 0;
glGenBuffers(1, &bufferId);
if (bufferId) {
d->guard.setContext(ctx);
d->guard.setId(bufferId);
if (d->guard)
d->guard->free();
d->guard = createSharedResourceGuard(ctx, bufferId, freeBufferFunc);
return true;
}
}
return false;
}
#define ctx d->guard.context()
#define ctx QGLContext::currentContext()
/*!
Returns true if this buffer has been created; false otherwise.
@ -293,7 +303,7 @@ bool QGLBuffer::create()
bool QGLBuffer::isCreated() const
{
Q_D(const QGLBuffer);
return d->guard.id() != 0;
return d->guard && d->guard->id();
}
/*!
@ -304,14 +314,10 @@ bool QGLBuffer::isCreated() const
void QGLBuffer::destroy()
{
Q_D(QGLBuffer);
GLuint bufferId = d->guard.id();
if (bufferId) {
// Switch to the original creating context to destroy it.
QGLShareContextScope scope(d->guard.context());
glDeleteBuffers(1, &bufferId);
if (d->guard) {
d->guard->free();
d->guard = 0;
}
d->guard.setId(0);
d->guard.setContext(0);
}
/*!
@ -358,7 +364,7 @@ void QGLBuffer::write(int offset, const void *data, int count)
qWarning("QGLBuffer::allocate(): buffer not created");
#endif
Q_D(QGLBuffer);
if (d->guard.id())
if (d->guard && d->guard->id())
glBufferSubData(d->type, offset, count, data);
}
@ -378,7 +384,7 @@ void QGLBuffer::allocate(const void *data, int count)
qWarning("QGLBuffer::allocate(): buffer not created");
#endif
Q_D(QGLBuffer);
if (d->guard.id())
if (d->guard && d->guard->id())
glBufferData(d->type, count, data, d->actualUsagePattern);
}
@ -413,10 +419,9 @@ bool QGLBuffer::bind()
qWarning("QGLBuffer::bind(): buffer not created");
#endif
Q_D(const QGLBuffer);
GLuint bufferId = d->guard.id();
GLuint bufferId = d->guard ? d->guard->id() : 0;
if (bufferId) {
if (!QGLContext::areSharing(QGLContext::currentContext(),
d->guard.context())) {
if (d->guard->group() != QGuiGLContextGroup::currentContextGroup()) {
#ifndef QT_NO_DEBUG
qWarning("QGLBuffer::bind: buffer is not valid in the current context");
#endif
@ -445,7 +450,7 @@ void QGLBuffer::release()
qWarning("QGLBuffer::release(): buffer not created");
#endif
Q_D(const QGLBuffer);
if (d->guard.id())
if (d->guard && d->guard->id())
glBindBuffer(d->type, 0);
}
@ -471,7 +476,7 @@ void QGLBuffer::release(QGLBuffer::Type type)
glBindBuffer(GLenum(type), 0);
}
#define ctx d->guard.context()
#define ctx QGLContext::currentContext()
/*!
Returns the GL identifier associated with this buffer; zero if
@ -482,7 +487,7 @@ void QGLBuffer::release(QGLBuffer::Type type)
GLuint QGLBuffer::bufferId() const
{
Q_D(const QGLBuffer);
return d->guard.id();
return d->guard ? d->guard->id() : 0;
}
#ifndef GL_BUFFER_SIZE
@ -501,7 +506,7 @@ GLuint QGLBuffer::bufferId() const
int QGLBuffer::size() const
{
Q_D(const QGLBuffer);
if (!d->guard.id())
if (!d->guard || !d->guard->id())
return -1;
GLint value = -1;
glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value);
@ -529,7 +534,7 @@ void *QGLBuffer::map(QGLBuffer::Access access)
if (!isCreated())
qWarning("QGLBuffer::map(): buffer not created");
#endif
if (!d->guard.id())
if (!d->guard || !d->guard->id())
return 0;
if (!glMapBufferARB)
return 0;
@ -556,7 +561,7 @@ bool QGLBuffer::unmap()
if (!isCreated())
qWarning("QGLBuffer::unmap(): buffer not created");
#endif
if (!d->guard.id())
if (!d->guard || !d->guard->id())
return false;
if (!glUnmapBufferARB)
return false;

View File

@ -55,8 +55,8 @@ QT_BEGIN_NAMESPACE
extern Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
#define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context();
#define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context();
#define QGL_FUNC_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
#define QGL_FUNCP_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
#ifndef QT_NO_DEBUG
#define QT_RESET_GLERROR() \
@ -351,13 +351,7 @@ void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
QGLContext *QGLFBOGLPaintDevice::context() const
{
QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
return currentContext;
else
return fboContext;
return const_cast<QGLContext *>(QGLContext::currentContext());
}
bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
@ -407,13 +401,33 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
return false;
}
namespace
{
void freeFramebufferFunc(QGLContext *ctx, GLuint id)
{
Q_UNUSED(ctx);
glDeleteFramebuffers(1, &id);
}
void freeRenderbufferFunc(QGLContext *ctx, GLuint id)
{
Q_UNUSED(ctx);
glDeleteRenderbuffers(1, &id);
}
void freeTextureFunc(QGLContext *ctx, GLuint id)
{
Q_UNUSED(ctx);
glDeleteTextures(1, &id);
}
}
void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
QGLFramebufferObject::Attachment attachment,
GLenum texture_target, GLenum internal_format,
GLint samples, bool mipmap)
{
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
fbo_guard.setContext(ctx);
bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
@ -427,9 +441,11 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
GLuint fbo = 0;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
fbo_guard.setId(fbo);
glDevice.setFBO(q, attachment);
GLuint texture = 0;
GLuint color_buffer = 0;
GLuint depth_buffer = 0;
GLuint stencil_buffer = 0;
QT_CHECK_GLERROR();
// init texture
@ -603,7 +619,21 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
}
glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
if (!valid) {
if (valid) {
fbo_guard = createSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
if (color_buffer)
color_buffer_guard = createSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
else
texture_guard = createSharedResourceGuard(ctx, texture, freeTextureFunc);
if (depth_buffer)
depth_buffer_guard = createSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
if (stencil_buffer) {
if (stencil_buffer == depth_buffer)
stencil_buffer_guard = depth_buffer_guard;
else
stencil_buffer_guard = createSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
}
} else {
if (color_buffer)
glDeleteRenderbuffers(1, &color_buffer);
else
@ -613,7 +643,6 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
if (stencil_buffer && depth_buffer != stencil_buffer)
glDeleteRenderbuffers(1, &stencil_buffer);
glDeleteFramebuffers(1, &fbo);
fbo_guard.setId(0);
}
QT_CHECK_GLERROR();
@ -622,6 +651,8 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
format.setAttachment(fbo_attachment);
format.setInternalTextureFormat(internal_format);
format.setMipmap(mipmap);
glDevice.setFBO(q, attachment);
}
/*!
@ -849,23 +880,19 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm
QGLFramebufferObject::~QGLFramebufferObject()
{
Q_D(QGLFramebufferObject);
QGL_FUNC_CONTEXT;
delete d->engine;
if (isValid() && ctx) {
QGLShareContextScope scope(ctx);
if (d->texture)
glDeleteTextures(1, &d->texture);
if (d->color_buffer)
glDeleteRenderbuffers(1, &d->color_buffer);
if (d->depth_buffer)
glDeleteRenderbuffers(1, &d->depth_buffer);
if (d->stencil_buffer && d->stencil_buffer != d->depth_buffer)
glDeleteRenderbuffers(1, &d->stencil_buffer);
GLuint fbo = d->fbo();
glDeleteFramebuffers(1, &fbo);
}
if (d->texture_guard)
d->texture_guard->free();
if (d->color_buffer_guard)
d->color_buffer_guard->free();
if (d->depth_buffer_guard)
d->depth_buffer_guard->free();
if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard)
d->stencil_buffer_guard->free();
if (d->fbo_guard)
d->fbo_guard->free();
}
/*!
@ -889,7 +916,7 @@ QGLFramebufferObject::~QGLFramebufferObject()
bool QGLFramebufferObject::isValid() const
{
Q_D(const QGLFramebufferObject);
return d->valid && d->fbo_guard.context();
return d->valid && d->fbo_guard && d->fbo_guard->id();
}
/*!
@ -972,7 +999,7 @@ bool QGLFramebufferObject::release()
GLuint QGLFramebufferObject::texture() const
{
Q_D(const QGLFramebufferObject);
return d->texture;
return d->texture_guard ? d->texture_guard->id() : 0;
}
/*!

View File

@ -130,8 +130,9 @@ private:
class QGLFramebufferObjectPrivate
{
public:
QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_buffer(0), stencil_buffer(0)
, color_buffer(0), valid(false), engine(0) {}
QGLFramebufferObjectPrivate() : fbo_guard(0), texture_guard(0), depth_buffer_guard(0)
, stencil_buffer_guard(0), color_buffer_guard(0)
, valid(false), engine(0) {}
~QGLFramebufferObjectPrivate() {}
void init(QGLFramebufferObject *q, const QSize& sz,
@ -139,11 +140,11 @@ public:
GLenum internal_format, GLenum texture_target,
GLint samples = 0, bool mipmap = false);
bool checkFramebufferStatus() const;
QGLSharedResourceGuard fbo_guard;
GLuint texture;
GLuint depth_buffer;
GLuint stencil_buffer;
GLuint color_buffer;
QGLSharedResourceGuardBase *fbo_guard;
QGLSharedResourceGuardBase *texture_guard;
QGLSharedResourceGuardBase *depth_buffer_guard;
QGLSharedResourceGuardBase *stencil_buffer_guard;
QGLSharedResourceGuardBase *color_buffer_guard;
GLenum target;
QSize size;
QGLFramebufferObjectFormat format;
@ -152,7 +153,7 @@ public:
mutable QPaintEngine *engine;
QGLFBOGLPaintDevice glDevice;
inline GLuint fbo() const { return fbo_guard.id(); }
inline GLuint fbo() const { return fbo_guard ? fbo_guard->id() : 0; }
};

View File

@ -41,6 +41,7 @@
#include "qglfunctions.h"
#include "qgl_p.h"
#include "QtGui/private/qguiglcontext_qpa_p.h"
QT_BEGIN_NAMESPACE
@ -139,16 +140,27 @@ QT_BEGIN_NAMESPACE
*/
// Hidden private fields for additional extension data.
struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate
struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResource
{
QGLFunctionsPrivateEx(const QGLContext *context = 0)
: QGLFunctionsPrivate(context)
QGLFunctionsPrivateEx(QGuiGLContext *context)
: QGLFunctionsPrivate(QGLContext::fromGuiGLContext(context))
, QGLSharedResource(context->shareGroup())
, m_features(-1) {}
void invalidateResource()
{
m_features = -1;
}
void freeResource(QGuiGLContext *)
{
// no gl resources to free
}
int m_features;
};
Q_GLOBAL_STATIC(QGLContextGroupResource<QGLFunctionsPrivateEx>, qt_gl_functions_resource)
Q_GLOBAL_STATIC(QGLMultiGroupSharedResource, qt_gl_functions_resource)
static QGLFunctionsPrivateEx *qt_gl_functions(const QGLContext *context = 0)
{
@ -157,13 +169,7 @@ static QGLFunctionsPrivateEx *qt_gl_functions(const QGLContext *context = 0)
Q_ASSERT(context);
QGLFunctionsPrivateEx *funcs =
reinterpret_cast<QGLFunctionsPrivateEx *>
(qt_gl_functions_resource()->value(context));
#if QT_VERSION < 0x040800
if (!funcs) {
funcs = new QGLFunctionsPrivateEx();
qt_gl_functions_resource()->insert(context, funcs);
}
#endif
(qt_gl_functions_resource()->value<QGLFunctionsPrivateEx>(context->contextHandle()));
return funcs;
}

View File

@ -189,15 +189,15 @@ class QGLShaderPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QGLShader)
public:
QGLShaderPrivate(const QGLContext *context, QGLShader::ShaderType type)
: shaderGuard(context)
QGLShaderPrivate(const QGLContext *, QGLShader::ShaderType type)
: shaderGuard(0)
, shaderType(type)
, compiled(false)
{
}
~QGLShaderPrivate();
QGLSharedResourceGuard shaderGuard;
QGLSharedResourceGuardBase *shaderGuard;
QGLShader::ShaderType shaderType;
bool compiled;
QString log;
@ -207,22 +207,28 @@ public:
void deleteShader();
};
#define ctx shaderGuard.context()
namespace {
void freeShaderFunc(QGLContext *ctx, GLuint id)
{
Q_UNUSED(ctx);
glDeleteShader(id);
}
}
#define ctx QGLContext::currentContext()
QGLShaderPrivate::~QGLShaderPrivate()
{
if (shaderGuard.id()) {
QGLShareContextScope scope(shaderGuard.context());
glDeleteShader(shaderGuard.id());
}
if (shaderGuard)
shaderGuard->free();
}
bool QGLShaderPrivate::create()
{
const QGLContext *context = shaderGuard.context();
QGLContext *context = const_cast<QGLContext *>(QGLContext::currentContext());
if (!context)
return false;
if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
if (qt_resolve_glsl_extensions(context)) {
GLuint shader;
if (shaderType == QGLShader::Vertex)
shader = glCreateShader(GL_VERTEX_SHADER);
@ -234,7 +240,7 @@ bool QGLShaderPrivate::create()
qWarning() << "QGLShader: could not create shader";
return false;
}
shaderGuard.setId(shader);
shaderGuard = createSharedResourceGuard(context, shader, freeShaderFunc);
return true;
} else {
return false;
@ -243,7 +249,7 @@ bool QGLShaderPrivate::create()
bool QGLShaderPrivate::compile(QGLShader *q)
{
GLuint shader = shaderGuard.id();
GLuint shader = shaderGuard ? shaderGuard->id() : 0;
if (!shader)
return false;
glCompileShader(shader);
@ -286,15 +292,12 @@ bool QGLShaderPrivate::compile(QGLShader *q)
void QGLShaderPrivate::deleteShader()
{
if (shaderGuard.id()) {
glDeleteShader(shaderGuard.id());
shaderGuard.setId(0);
if (shaderGuard) {
shaderGuard->free();
shaderGuard = 0;
}
}
#undef ctx
#define ctx d->shaderGuard.context()
/*!
Constructs a new QGLShader object of the specified \a type
and attaches it to \a parent. If shader programs are not supported,
@ -387,7 +390,7 @@ static const char redefineHighp[] =
bool QGLShader::compileSourceCode(const char *source)
{
Q_D(QGLShader);
if (d->shaderGuard.id()) {
if (d->shaderGuard && d->shaderGuard->id()) {
QVarLengthArray<const char *, 4> src;
QVarLengthArray<GLint, 4> srclen;
int headerLen = 0;
@ -420,7 +423,7 @@ bool QGLShader::compileSourceCode(const char *source)
#endif
src.append(source + headerLen);
srclen.append(GLint(qstrlen(source + headerLen)));
glShaderSource(d->shaderGuard.id(), src.size(), src.data(), srclen.data());
glShaderSource(d->shaderGuard->id(), src.size(), src.data(), srclen.data());
return d->compile(this);
} else {
return false;
@ -480,7 +483,7 @@ bool QGLShader::compileSourceFile(const QString& fileName)
QByteArray QGLShader::sourceCode() const
{
Q_D(const QGLShader);
GLuint shader = d->shaderGuard.id();
GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0;
if (!shader)
return QByteArray();
GLint size = 0;
@ -525,22 +528,17 @@ QString QGLShader::log() const
GLuint QGLShader::shaderId() const
{
Q_D(const QGLShader);
return d->shaderGuard.id();
return d->shaderGuard ? d->shaderGuard->id() : 0;
}
#undef ctx
#define ctx programGuard.context()
class QGLShaderProgramPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QGLShaderProgram)
public:
QGLShaderProgramPrivate(const QGLContext *context)
: programGuard(context)
QGLShaderProgramPrivate(const QGLContext *)
: programGuard(0)
, linked(false)
, inited(false)
, removingShaders(false)
@ -551,7 +549,7 @@ public:
}
~QGLShaderProgramPrivate();
QGLSharedResourceGuard programGuard;
QGLSharedResourceGuardBase *programGuard;
bool linked;
bool inited;
bool removingShaders;
@ -567,12 +565,19 @@ public:
bool hasShader(QGLShader::ShaderType type) const;
};
namespace {
void freeProgramFunc(QGLContext *ctx, GLuint id)
{
Q_UNUSED(ctx);
glDeleteProgram(id);
}
}
QGLShaderProgramPrivate::~QGLShaderProgramPrivate()
{
if (programGuard.id()) {
QGLShareContextScope scope(programGuard.context());
glDeleteProgram(programGuard.id());
}
if (programGuard)
programGuard->free();
}
bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
@ -584,8 +589,7 @@ bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
return false;
}
#undef ctx
#define ctx d->programGuard.context()
#define ctx QGLContext::currentContext()
/*!
Constructs a new shader program and attaches it to \a parent.
@ -623,24 +627,21 @@ QGLShaderProgram::~QGLShaderProgram()
bool QGLShaderProgram::init()
{
Q_D(QGLShaderProgram);
if (d->programGuard.id() || d->inited)
if ((d->programGuard && d->programGuard->id()) || d->inited)
return true;
d->inited = true;
const QGLContext *context = d->programGuard.context();
if (!context) {
context = QGLContext::currentContext();
d->programGuard.setContext(context);
}
QGLContext *context = const_cast<QGLContext *>(QGLContext::currentContext());
if (!context)
return false;
if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
if (qt_resolve_glsl_extensions(context)) {
GLuint program = glCreateProgram();
if (!program) {
qWarning() << "QGLShaderProgram: could not create shader program";
return false;
}
d->programGuard.setId(program);
if (d->programGuard)
delete d->programGuard;
d->programGuard = createSharedResourceGuard(context, program, freeProgramFunc);
return true;
} else {
qWarning() << "QGLShaderProgram: shader programs are not supported";
@ -667,15 +668,14 @@ bool QGLShaderProgram::addShader(QGLShader *shader)
return false;
if (d->shaders.contains(shader))
return true; // Already added to this shader program.
if (d->programGuard.id() && shader) {
if (!QGLContext::areSharing(shader->d_func()->shaderGuard.context(),
d->programGuard.context())) {
if (d->programGuard && d->programGuard->id() && shader) {
if (!shader->d_func()->shaderGuard || !shader->d_func()->shaderGuard->id())
return false;
if (d->programGuard->group() != shader->d_func()->shaderGuard->group()) {
qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context.");
return false;
}
if (!shader->d_func()->shaderGuard.id())
return false;
glAttachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
glAttachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
d->linked = false; // Program needs to be relinked.
d->shaders.append(shader);
connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
@ -784,14 +784,17 @@ bool QGLShaderProgram::addShaderFromSourceFile
/*!
Removes \a shader from this shader program. The object is not deleted.
The shader program must be valid in the current QGLContext.
\sa addShader(), link(), removeAllShaders()
*/
void QGLShaderProgram::removeShader(QGLShader *shader)
{
Q_D(QGLShaderProgram);
if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id()) {
QGLShareContextScope scope(d->programGuard.context());
glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
if (d->programGuard && d->programGuard->id()
&& shader && shader->d_func()->shaderGuard)
{
glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
}
d->linked = false; // Program needs to be relinked.
if (shader) {
@ -826,8 +829,11 @@ void QGLShaderProgram::removeAllShaders()
Q_D(QGLShaderProgram);
d->removingShaders = true;
foreach (QGLShader *shader, d->shaders) {
if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id())
glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
if (d->programGuard && d->programGuard->id()
&& shader && shader->d_func()->shaderGuard)
{
glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
}
}
foreach (QGLShader *shader, d->anonShaders) {
// Delete shader objects that were created anonymously.
@ -856,7 +862,7 @@ void QGLShaderProgram::removeAllShaders()
bool QGLShaderProgram::link()
{
Q_D(QGLShaderProgram);
GLuint program = d->programGuard.id();
GLuint program = d->programGuard ? d->programGuard->id() : 0;
if (!program)
return false;
@ -946,13 +952,13 @@ QString QGLShaderProgram::log() const
bool QGLShaderProgram::bind()
{
Q_D(QGLShaderProgram);
GLuint program = d->programGuard.id();
GLuint program = d->programGuard ? d->programGuard->id() : 0;
if (!program)
return false;
if (!d->linked && !link())
return false;
#ifndef QT_NO_DEBUG
if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext())) {
if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup()) {
qWarning("QGLShaderProgram::bind: program is not valid in the current context.");
return false;
}
@ -974,7 +980,7 @@ void QGLShaderProgram::release()
{
#ifndef QT_NO_DEBUG
Q_D(QGLShaderProgram);
if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext()))
if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup())
qWarning("QGLShaderProgram::release: program is not valid in the current context.");
#endif
#if defined(QT_OPENGL_ES_2)
@ -996,7 +1002,7 @@ void QGLShaderProgram::release()
GLuint QGLShaderProgram::programId() const
{
Q_D(const QGLShaderProgram);
GLuint id = d->programGuard.id();
GLuint id = d->programGuard ? d->programGuard->id() : 0;
if (id)
return id;
@ -1005,7 +1011,7 @@ GLuint QGLShaderProgram::programId() const
// themselves, particularly those using program binaries.
if (!const_cast<QGLShaderProgram *>(this)->init())
return 0;
return d->programGuard.id();
return d->programGuard ? d->programGuard->id() : 0;
}
/*!
@ -1022,9 +1028,9 @@ GLuint QGLShaderProgram::programId() const
void QGLShaderProgram::bindAttributeLocation(const char *name, int location)
{
Q_D(QGLShaderProgram);
if (!init())
if (!init() || !d->programGuard || !d->programGuard->id())
return;
glBindAttribLocation(d->programGuard.id(), location, name);
glBindAttribLocation(d->programGuard->id(), location, name);
d->linked = false; // Program needs to be relinked.
}
@ -1074,8 +1080,8 @@ void QGLShaderProgram::bindAttributeLocation(const QString& name, int location)
int QGLShaderProgram::attributeLocation(const char *name) const
{
Q_D(const QGLShaderProgram);
if (d->linked) {
return glGetAttribLocation(d->programGuard.id(), name);
if (d->linked && d->programGuard && d->programGuard->id()) {
return glGetAttribLocation(d->programGuard->id(), name);
} else {
qWarning() << "QGLShaderProgram::attributeLocation(" << name
<< "): shader program is not linked";
@ -1752,8 +1758,8 @@ int QGLShaderProgram::uniformLocation(const char *name) const
{
Q_D(const QGLShaderProgram);
Q_UNUSED(d);
if (d->linked) {
return glGetUniformLocation(d->programGuard.id(), name);
if (d->linked && d->programGuard && d->programGuard->id()) {
return glGetUniformLocation(d->programGuard->id(), name);
} else {
qWarning() << "QGLShaderProgram::uniformLocation(" << name
<< "): shader program is not linked";