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:
parent
00fd783a39
commit
aaa4a26f82
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
181
src/gui/kernel/qguiglcontext_qpa_p.h
Normal file
181
src/gui/kernel/qguiglcontext_qpa_p.h
Normal 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
|
@ -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)
|
||||
|
@ -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");
|
||||
|
@ -365,7 +365,6 @@ public:
|
||||
void cleanupCustomStage(QGLCustomShaderStage* stage);
|
||||
|
||||
private:
|
||||
QGLSharedResourceGuard ctxGuard;
|
||||
QGLShaderProgram *blitShaderProg;
|
||||
QGLShaderProgram *simpleShaderProg;
|
||||
QList<QGLEngineShaderProg*> cachedPrograms;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user