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/qplatformwindow_qpa.h \
|
||||||
kernel/qplatformglcontext_qpa.h \
|
kernel/qplatformglcontext_qpa.h \
|
||||||
kernel/qguiglcontext_qpa.h \
|
kernel/qguiglcontext_qpa.h \
|
||||||
|
kernel/qguiglcontext_qpa_p.h \
|
||||||
kernel/qplatformcursor_qpa.h \
|
kernel/qplatformcursor_qpa.h \
|
||||||
kernel/qplatformclipboard_qpa.h \
|
kernel/qplatformclipboard_qpa.h \
|
||||||
kernel/qplatformnativeinterface_qpa.h \
|
kernel/qplatformnativeinterface_qpa.h \
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
#include "qplatformglcontext_qpa.h"
|
#include "qplatformglcontext_qpa.h"
|
||||||
#include "qguiglcontext_qpa.h"
|
#include "qguiglcontext_qpa.h"
|
||||||
|
#include "qguiglcontext_qpa_p.h"
|
||||||
#include "qwindow.h"
|
#include "qwindow.h"
|
||||||
|
|
||||||
#include <QtCore/QThreadStorage>
|
#include <QtCore/QThreadStorage>
|
||||||
@ -63,35 +64,6 @@ public:
|
|||||||
|
|
||||||
static QThreadStorage<QGuiGLThreadContext *> qwindow_context_storage;
|
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)
|
void QGuiGLContextPrivate::setCurrentContext(QGuiGLContext *context)
|
||||||
{
|
{
|
||||||
QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
|
QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
|
||||||
@ -118,6 +90,11 @@ QGuiGLContext* QGuiGLContext::currentContext()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QGuiGLContext::areSharing(QGuiGLContext *first, QGuiGLContext *second)
|
||||||
|
{
|
||||||
|
return first->shareGroup() == second->shareGroup();
|
||||||
|
}
|
||||||
|
|
||||||
QPlatformGLContext *QGuiGLContext::handle() const
|
QPlatformGLContext *QGuiGLContext::handle() const
|
||||||
{
|
{
|
||||||
Q_D(const QGuiGLContext);
|
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.
|
Creates a new GL context instance, you need to call create() before it can be used.
|
||||||
*/
|
*/
|
||||||
QGuiGLContext::QGuiGLContext()
|
QGuiGLContext::QGuiGLContext()
|
||||||
: d_ptr(new QGuiGLContextPrivate())
|
: QObject(*new QGuiGLContextPrivate())
|
||||||
{
|
{
|
||||||
Q_D(QGuiGLContext);
|
Q_D(QGuiGLContext);
|
||||||
d->screen = QGuiApplication::primaryScreen();
|
d->screen = QGuiApplication::primaryScreen();
|
||||||
@ -174,7 +151,7 @@ void QGuiGLContext::setScreen(QScreen *screen)
|
|||||||
/*!
|
/*!
|
||||||
Attempts to create the GL context with the desired parameters.
|
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()
|
bool QGuiGLContext::create()
|
||||||
{
|
{
|
||||||
@ -183,6 +160,8 @@ bool QGuiGLContext::create()
|
|||||||
Q_D(QGuiGLContext);
|
Q_D(QGuiGLContext);
|
||||||
d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformGLContext(this);
|
d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformGLContext(this);
|
||||||
d->platformGLContext->setContext(this);
|
d->platformGLContext->setContext(this);
|
||||||
|
d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QGuiGLContextGroup;
|
||||||
|
d->shareGroup->d_func()->addContext(this);
|
||||||
return d->platformGLContext;
|
return d->platformGLContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +170,9 @@ void QGuiGLContext::destroy()
|
|||||||
Q_D(QGuiGLContext);
|
Q_D(QGuiGLContext);
|
||||||
if (QGuiGLContext::currentContext() == this)
|
if (QGuiGLContext::currentContext() == this)
|
||||||
doneCurrent();
|
doneCurrent();
|
||||||
|
if (d->shareGroup)
|
||||||
|
d->shareGroup->d_func()->removeContext(this);
|
||||||
|
d->shareGroup = 0;
|
||||||
delete d->platformGLContext;
|
delete d->platformGLContext;
|
||||||
d->platformGLContext = 0;
|
d->platformGLContext = 0;
|
||||||
}
|
}
|
||||||
@ -232,6 +214,9 @@ bool QGuiGLContext::makeCurrent(QSurface *surface)
|
|||||||
if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) {
|
if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) {
|
||||||
QGuiGLContextPrivate::setCurrentContext(this);
|
QGuiGLContextPrivate::setCurrentContext(this);
|
||||||
d->surface = surface;
|
d->surface = surface;
|
||||||
|
|
||||||
|
d->shareGroup->d_func()->deletePendingResources(this);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +232,9 @@ void QGuiGLContext::doneCurrent()
|
|||||||
if (!d->platformGLContext)
|
if (!d->platformGLContext)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (QGuiGLContext::currentContext() == this)
|
||||||
|
d->shareGroup->d_func()->deletePendingResources(this);
|
||||||
|
|
||||||
d->platformGLContext->doneCurrent();
|
d->platformGLContext->doneCurrent();
|
||||||
QGuiGLContextPrivate::setCurrentContext(0);
|
QGuiGLContextPrivate::setCurrentContext(0);
|
||||||
|
|
||||||
@ -293,6 +281,12 @@ QSurfaceFormat QGuiGLContext::format() const
|
|||||||
return d->platformGLContext->format();
|
return d->platformGLContext->format();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QGuiGLContextGroup *QGuiGLContext::shareGroup() const
|
||||||
|
{
|
||||||
|
Q_D(const QGuiGLContext);
|
||||||
|
return d->shareGroup;
|
||||||
|
}
|
||||||
|
|
||||||
QGuiGLContext *QGuiGLContext::shareContext() const
|
QGuiGLContext *QGuiGLContext::shareContext() const
|
||||||
{
|
{
|
||||||
Q_D(const QGuiGLContext);
|
Q_D(const QGuiGLContext);
|
||||||
@ -331,3 +325,176 @@ void QGuiGLContext::deleteQGLContext()
|
|||||||
d->qGLContextHandle = 0;
|
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)
|
QT_MODULE(Gui)
|
||||||
|
|
||||||
class QGuiGLContextPrivate;
|
class QGuiGLContextPrivate;
|
||||||
|
class QGuiGLContextGroupPrivate;
|
||||||
class QPlatformGLContext;
|
class QPlatformGLContext;
|
||||||
class QSurface;
|
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:
|
public:
|
||||||
QGuiGLContext();
|
QGuiGLContext();
|
||||||
~QGuiGLContext();
|
~QGuiGLContext();
|
||||||
@ -73,6 +95,7 @@ public:
|
|||||||
|
|
||||||
QSurfaceFormat format() const;
|
QSurfaceFormat format() const;
|
||||||
QGuiGLContext *shareContext() const;
|
QGuiGLContext *shareContext() const;
|
||||||
|
QGuiGLContextGroup *shareGroup() const;
|
||||||
QScreen *screen() const;
|
QScreen *screen() const;
|
||||||
|
|
||||||
bool makeCurrent(QSurface *surface);
|
bool makeCurrent(QSurface *surface);
|
||||||
@ -84,15 +107,15 @@ public:
|
|||||||
QSurface *surface() const;
|
QSurface *surface() const;
|
||||||
|
|
||||||
static QGuiGLContext *currentContext();
|
static QGuiGLContext *currentContext();
|
||||||
|
static bool areSharing(QGuiGLContext *first, QGuiGLContext *second);
|
||||||
|
|
||||||
QPlatformGLContext *handle() const;
|
QPlatformGLContext *handle() const;
|
||||||
QPlatformGLContext *shareHandle() const;
|
QPlatformGLContext *shareHandle() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<QGuiGLContextPrivate> d_ptr;
|
|
||||||
|
|
||||||
//hack to make it work with QGLContext::CurrentContext
|
//hack to make it work with QGLContext::CurrentContext
|
||||||
friend class QGLContext;
|
friend class QGLContext;
|
||||||
|
friend class QGLContextResourceBase;
|
||||||
friend class QWidgetPrivate;
|
friend class QWidgetPrivate;
|
||||||
|
|
||||||
void *qGLContextHandle() const;
|
void *qGLContextHandle() const;
|
||||||
@ -100,8 +123,6 @@ private:
|
|||||||
void deleteQGLContext();
|
void deleteQGLContext();
|
||||||
|
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
Q_DISABLE_COPY(QGuiGLContext);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
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()
|
/*! \fn void QPlatformGLContext::swapBuffers()
|
||||||
Reimplement in subclass to native swap buffers calls
|
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)
|
/*! \fn void *QPlatformGLContext::getProcAddress(const QString &procName)
|
||||||
|
@ -44,6 +44,8 @@
|
|||||||
#include "qpaintengineex_opengl2_p.h"
|
#include "qpaintengineex_opengl2_p.h"
|
||||||
#include "qglshadercache_p.h"
|
#include "qglshadercache_p.h"
|
||||||
|
|
||||||
|
#include <QtGui/private/qguiglcontext_qpa_p.h>
|
||||||
|
|
||||||
#if defined(QT_DEBUG)
|
#if defined(QT_DEBUG)
|
||||||
#include <QMetaEnum>
|
#include <QMetaEnum>
|
||||||
#endif
|
#endif
|
||||||
@ -52,18 +54,50 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
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
|
class QGLShaderStorage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QGLEngineSharedShaders *shadersForThread(const QGLContext *context) {
|
QGLEngineSharedShaders *shadersForThread(const QGLContext *context) {
|
||||||
QGLContextGroupResource<QGLEngineSharedShaders> *&shaders = m_storage.localData();
|
QGLMultiGroupSharedResource *&shaders = m_storage.localData();
|
||||||
if (!shaders)
|
if (!shaders)
|
||||||
shaders = new QGLContextGroupResource<QGLEngineSharedShaders>();
|
shaders = new QGLMultiGroupSharedResource;
|
||||||
return shaders->value(context);
|
QGLEngineSharedShadersResource *resource =
|
||||||
|
shaders->value<QGLEngineSharedShadersResource>(context->contextHandle());
|
||||||
|
return resource ? resource->shaders() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QThreadStorage<QGLContextGroupResource<QGLEngineSharedShaders> *> m_storage;
|
QThreadStorage<QGLMultiGroupSharedResource *> m_storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage);
|
Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage);
|
||||||
@ -81,8 +115,7 @@ const char* QGLEngineSharedShaders::qShaderSnippets[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
|
QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
|
||||||
: ctxGuard(context)
|
: blitShaderProg(0)
|
||||||
, blitShaderProg(0)
|
|
||||||
, simpleShaderProg(0)
|
, simpleShaderProg(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -327,14 +360,14 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
|
|||||||
vertexSource.append(qShaderSnippets[prog.mainVertexShader]);
|
vertexSource.append(qShaderSnippets[prog.mainVertexShader]);
|
||||||
vertexSource.append(qShaderSnippets[prog.positionVertexShader]);
|
vertexSource.append(qShaderSnippets[prog.positionVertexShader]);
|
||||||
|
|
||||||
QScopedPointer<QGLShaderProgram> shaderProgram(new QGLShaderProgram(ctxGuard.context(), 0));
|
QScopedPointer<QGLShaderProgram> shaderProgram(new QGLShaderProgram);
|
||||||
|
|
||||||
CachedShader shaderCache(fragSource, vertexSource);
|
CachedShader shaderCache(fragSource, vertexSource);
|
||||||
bool inCache = shaderCache.load(shaderProgram.data(), ctxGuard.context());
|
bool inCache = shaderCache.load(shaderProgram.data(), QGLContext::currentContext());
|
||||||
|
|
||||||
if (!inCache) {
|
if (!inCache) {
|
||||||
|
|
||||||
QScopedPointer<QGLShader> fragShader(new QGLShader(QGLShader::Fragment, ctxGuard.context(), 0));
|
QScopedPointer<QGLShader> fragShader(new QGLShader(QGLShader::Fragment));
|
||||||
QByteArray description;
|
QByteArray description;
|
||||||
#if defined(QT_DEBUG)
|
#if defined(QT_DEBUG)
|
||||||
// Name the shader for easier debugging
|
// Name the shader for easier debugging
|
||||||
@ -357,7 +390,7 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QScopedPointer<QGLShader> vertexShader(new QGLShader(QGLShader::Vertex, ctxGuard.context(), 0));
|
QScopedPointer<QGLShader> vertexShader(new QGLShader(QGLShader::Vertex));
|
||||||
#if defined(QT_DEBUG)
|
#if defined(QT_DEBUG)
|
||||||
// Name the shader for easier debugging
|
// Name the shader for easier debugging
|
||||||
description.clear();
|
description.clear();
|
||||||
@ -396,7 +429,7 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
|
|||||||
newProg->program->link();
|
newProg->program->link();
|
||||||
if (newProg->program->isLinked()) {
|
if (newProg->program->isLinked()) {
|
||||||
if (!inCache)
|
if (!inCache)
|
||||||
shaderCache.store(newProg->program, ctxGuard.context());
|
shaderCache.store(newProg->program, QGLContext::currentContext());
|
||||||
} else {
|
} else {
|
||||||
QLatin1String none("none");
|
QLatin1String none("none");
|
||||||
QLatin1String br("\n");
|
QLatin1String br("\n");
|
||||||
|
@ -365,7 +365,6 @@ public:
|
|||||||
void cleanupCustomStage(QGLCustomShaderStage* stage);
|
void cleanupCustomStage(QGLCustomShaderStage* stage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QGLSharedResourceGuard ctxGuard;
|
|
||||||
QGLShaderProgram *blitShaderProg;
|
QGLShaderProgram *blitShaderProg;
|
||||||
QGLShaderProgram *simpleShaderProg;
|
QGLShaderProgram *simpleShaderProg;
|
||||||
QList<QGLEngineShaderProg*> cachedPrograms;
|
QList<QGLEngineShaderProg*> cachedPrograms;
|
||||||
|
@ -51,21 +51,42 @@ class QGL2GradientCacheWrapper
|
|||||||
public:
|
public:
|
||||||
QGL2GradientCache *cacheForContext(const QGLContext *context) {
|
QGL2GradientCache *cacheForContext(const QGLContext *context) {
|
||||||
QMutexLocker lock(&m_mutex);
|
QMutexLocker lock(&m_mutex);
|
||||||
return m_resource.value(context);
|
return m_resource.value<QGL2GradientCache>(context->contextHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QGLContextGroupResource<QGL2GradientCache> m_resource;
|
QGLMultiGroupSharedResource m_resource;
|
||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_GLOBAL_STATIC(QGL2GradientCacheWrapper, qt_gradient_caches)
|
Q_GLOBAL_STATIC(QGL2GradientCacheWrapper, qt_gradient_caches)
|
||||||
|
|
||||||
|
QGL2GradientCache::QGL2GradientCache(QGuiGLContext *ctx)
|
||||||
|
: QGLSharedResource(ctx->shareGroup())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QGL2GradientCache::~QGL2GradientCache()
|
||||||
|
{
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
|
QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
|
||||||
{
|
{
|
||||||
return qt_gradient_caches()->cacheForContext(context);
|
return qt_gradient_caches()->cacheForContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QGL2GradientCache::invalidateResource()
|
||||||
|
{
|
||||||
|
QMutexLocker lock(&m_mutex);
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGL2GradientCache::freeResource(QGuiGLContext *)
|
||||||
|
{
|
||||||
|
cleanCache();
|
||||||
|
}
|
||||||
|
|
||||||
void QGL2GradientCache::cleanCache()
|
void QGL2GradientCache::cleanCache()
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&m_mutex);
|
QMutexLocker lock(&m_mutex);
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QGL2GradientCache
|
class QGL2GradientCache : public QGLSharedResource
|
||||||
{
|
{
|
||||||
struct CacheInfo
|
struct CacheInfo
|
||||||
{
|
{
|
||||||
@ -76,12 +76,15 @@ class QGL2GradientCache
|
|||||||
public:
|
public:
|
||||||
static QGL2GradientCache *cacheForContext(const QGLContext *context);
|
static QGL2GradientCache *cacheForContext(const QGLContext *context);
|
||||||
|
|
||||||
QGL2GradientCache(const QGLContext *) {}
|
QGL2GradientCache(QGuiGLContext *);
|
||||||
~QGL2GradientCache() { cleanCache(); }
|
~QGL2GradientCache();
|
||||||
|
|
||||||
GLuint getBuffer(const QGradient &gradient, qreal opacity);
|
GLuint getBuffer(const QGradient &gradient, qreal opacity);
|
||||||
inline int paletteSize() const { return 1024; }
|
inline int paletteSize() const { return 1024; }
|
||||||
|
|
||||||
|
void invalidateResource();
|
||||||
|
void freeResource(QGuiGLContext *ctx);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline int maxCacheSize() const { return 60; }
|
inline int maxCacheSize() const { return 60; }
|
||||||
inline void generateGradientColorTable(const QGradient& gradient,
|
inline void generateGradientColorTable(const QGradient& gradient,
|
||||||
|
@ -1580,10 +1580,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
|
|||||||
|
|
||||||
QGLTextureGlyphCache *cache =
|
QGLTextureGlyphCache *cache =
|
||||||
(QGLTextureGlyphCache *) staticTextItem->fontEngine()->glyphCache(cacheKey, glyphType, QTransform());
|
(QGLTextureGlyphCache *) staticTextItem->fontEngine()->glyphCache(cacheKey, glyphType, QTransform());
|
||||||
if (!cache || cache->cacheType() != glyphType || cache->context() == 0) {
|
if (!cache || cache->cacheType() != glyphType || cache->contextGroup() == 0) {
|
||||||
cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
|
cache = new QGLTextureGlyphCache(glyphType, QTransform());
|
||||||
staticTextItem->fontEngine()->setGlyphCache(cacheKey, cache);
|
staticTextItem->fontEngine()->setGlyphCache(cacheKey, cache);
|
||||||
cache->insert(ctx, cache);
|
|
||||||
recreateVertexArrays = true;
|
recreateVertexArrays = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,19 +51,16 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled;
|
|||||||
|
|
||||||
QBasicAtomicInt qgltextureglyphcache_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
|
QBasicAtomicInt qgltextureglyphcache_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
|
||||||
|
|
||||||
QGLTextureGlyphCache::QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
|
QGLTextureGlyphCache::QGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix)
|
||||||
: QImageTextureGlyphCache(type, matrix), QGLContextGroupResourceBase()
|
: QImageTextureGlyphCache(type, matrix)
|
||||||
, ctx(0)
|
|
||||||
, pex(0)
|
, pex(0)
|
||||||
, m_blitProgram(0)
|
, m_blitProgram(0)
|
||||||
, m_filterMode(Nearest)
|
, m_filterMode(Nearest)
|
||||||
, m_serialNumber(qgltextureglyphcache_serial_number.fetchAndAddRelaxed(1))
|
, m_serialNumber(qgltextureglyphcache_serial_number.fetchAndAddRelaxed(1))
|
||||||
{
|
{
|
||||||
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
|
#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
|
#endif
|
||||||
setContext(context);
|
|
||||||
|
|
||||||
m_vertexCoordinateArray[0] = -1.0f;
|
m_vertexCoordinateArray[0] = -1.0f;
|
||||||
m_vertexCoordinateArray[1] = -1.0f;
|
m_vertexCoordinateArray[1] = -1.0f;
|
||||||
m_vertexCoordinateArray[2] = 1.0f;
|
m_vertexCoordinateArray[2] = 1.0f;
|
||||||
@ -91,14 +88,9 @@ QGLTextureGlyphCache::~QGLTextureGlyphCache()
|
|||||||
delete m_blitProgram;
|
delete m_blitProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGLTextureGlyphCache::setContext(const QGLContext *context)
|
|
||||||
{
|
|
||||||
ctx = context;
|
|
||||||
m_h = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QGLTextureGlyphCache::createTextureData(int width, int height)
|
void QGLTextureGlyphCache::createTextureData(int width, int height)
|
||||||
{
|
{
|
||||||
|
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
if (ctx == 0) {
|
if (ctx == 0) {
|
||||||
qWarning("QGLTextureGlyphCache::createTextureData: Called with no context");
|
qWarning("QGLTextureGlyphCache::createTextureData: Called with no context");
|
||||||
return;
|
return;
|
||||||
@ -116,12 +108,17 @@ void QGLTextureGlyphCache::createTextureData(int width, int height)
|
|||||||
if (height < 16)
|
if (height < 16)
|
||||||
height = 16;
|
height = 16;
|
||||||
|
|
||||||
QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
|
if (m_textureResource && !m_textureResource->m_texture)
|
||||||
glGenTextures(1, &glyphTexture->m_texture);
|
delete m_textureResource;
|
||||||
glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
|
|
||||||
|
|
||||||
glyphTexture->m_width = width;
|
if (!m_textureResource)
|
||||||
glyphTexture->m_height = height;
|
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) {
|
if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
|
||||||
QVarLengthArray<uchar> data(width * height * 4);
|
QVarLengthArray<uchar> data(width * height * 4);
|
||||||
@ -144,14 +141,14 @@ void QGLTextureGlyphCache::createTextureData(int width, int height)
|
|||||||
|
|
||||||
void QGLTextureGlyphCache::resizeTextureData(int width, int height)
|
void QGLTextureGlyphCache::resizeTextureData(int width, int height)
|
||||||
{
|
{
|
||||||
|
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
if (ctx == 0) {
|
if (ctx == 0) {
|
||||||
qWarning("QGLTextureGlyphCache::resizeTextureData: Called with no context");
|
qWarning("QGLTextureGlyphCache::resizeTextureData: Called with no context");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
|
|
||||||
|
|
||||||
int oldWidth = glyphTexture->m_width;
|
int oldWidth = m_textureResource->m_width;
|
||||||
int oldHeight = glyphTexture->m_height;
|
int oldHeight = m_textureResource->m_height;
|
||||||
|
|
||||||
// Make the lower glyph texture size 16 x 16.
|
// Make the lower glyph texture size 16 x 16.
|
||||||
if (width < 16)
|
if (width < 16)
|
||||||
@ -159,7 +156,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
|
|||||||
if (height < 16)
|
if (height < 16)
|
||||||
height = 16;
|
height = 16;
|
||||||
|
|
||||||
GLuint oldTexture = glyphTexture->m_texture;
|
GLuint oldTexture = m_textureResource->m_texture;
|
||||||
createTextureData(width, height);
|
createTextureData(width, height);
|
||||||
|
|
||||||
if (ctx->d_ptr->workaround_brokenFBOReadBack) {
|
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
|
// ### the QTextureGlyphCache API needs to be reworked to allow
|
||||||
// ### resizeTextureData to fail
|
// ### resizeTextureData to fail
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER_EXT, glyphTexture->m_fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_textureResource->m_fbo);
|
||||||
|
|
||||||
GLuint tmp_texture;
|
GLuint tmp_texture;
|
||||||
glGenTextures(1, &tmp_texture);
|
glGenTextures(1, &tmp_texture);
|
||||||
@ -257,7 +254,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
|
|||||||
|
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
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);
|
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)
|
void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition)
|
||||||
{
|
{
|
||||||
|
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
if (ctx == 0) {
|
if (ctx == 0) {
|
||||||
qWarning("QGLTextureGlyphCache::fillTexture: Called with no context");
|
qWarning("QGLTextureGlyphCache::fillTexture: Called with no context");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
|
|
||||||
if (ctx->d_ptr->workaround_brokenFBOReadBack) {
|
if (ctx->d_ptr->workaround_brokenFBOReadBack) {
|
||||||
QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition);
|
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 QImage &texture = image();
|
||||||
const uchar *bits = texture.constBits();
|
const uchar *bits = texture.constBits();
|
||||||
bits += c.y * texture.bytesPerLine() + c.x;
|
bits += c.y * texture.bytesPerLine() + c.x;
|
||||||
@ -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) {
|
if (mask.format() == QImage::Format_RGB32) {
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
|
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
|
||||||
} else {
|
} else {
|
||||||
@ -358,6 +355,7 @@ int QGLTextureGlyphCache::glyphPadding() const
|
|||||||
|
|
||||||
int QGLTextureGlyphCache::maxTextureWidth() const
|
int QGLTextureGlyphCache::maxTextureWidth() const
|
||||||
{
|
{
|
||||||
|
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
if (ctx == 0)
|
if (ctx == 0)
|
||||||
return QImageTextureGlyphCache::maxTextureWidth();
|
return QImageTextureGlyphCache::maxTextureWidth();
|
||||||
else
|
else
|
||||||
@ -366,6 +364,7 @@ int QGLTextureGlyphCache::maxTextureWidth() const
|
|||||||
|
|
||||||
int QGLTextureGlyphCache::maxTextureHeight() const
|
int QGLTextureGlyphCache::maxTextureHeight() const
|
||||||
{
|
{
|
||||||
|
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
if (ctx == 0)
|
if (ctx == 0)
|
||||||
return QImageTextureGlyphCache::maxTextureHeight();
|
return QImageTextureGlyphCache::maxTextureHeight();
|
||||||
|
|
||||||
@ -377,16 +376,15 @@ int QGLTextureGlyphCache::maxTextureHeight() const
|
|||||||
|
|
||||||
void QGLTextureGlyphCache::clear()
|
void QGLTextureGlyphCache::clear()
|
||||||
{
|
{
|
||||||
if (ctx != 0) {
|
m_textureResource->free();
|
||||||
m_textureResource.cleanup(ctx);
|
m_textureResource = 0;
|
||||||
|
|
||||||
m_w = 0;
|
m_w = 0;
|
||||||
m_h = 0;
|
m_h = 0;
|
||||||
m_cx = 0;
|
m_cx = 0;
|
||||||
m_cy = 0;
|
m_cy = 0;
|
||||||
m_currentRowHeight = 0;
|
m_currentRowHeight = 0;
|
||||||
coords.clear();
|
coords.clear();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -63,10 +63,11 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
class QGL2PaintEngineExPrivate;
|
class QGL2PaintEngineExPrivate;
|
||||||
|
|
||||||
struct QGLGlyphTexture
|
struct QGLGlyphTexture : public QGLSharedResource
|
||||||
{
|
{
|
||||||
QGLGlyphTexture(const QGLContext *ctx)
|
QGLGlyphTexture(const QGLContext *ctx)
|
||||||
: m_width(0)
|
: QGLSharedResource(ctx->contextHandle()->shareGroup())
|
||||||
|
, m_width(0)
|
||||||
, m_height(0)
|
, m_height(0)
|
||||||
{
|
{
|
||||||
if (ctx && !ctx->d_ptr->workaround_brokenFBOReadBack)
|
if (ctx && !ctx->d_ptr->workaround_brokenFBOReadBack)
|
||||||
@ -77,19 +78,24 @@ struct QGLGlyphTexture
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
~QGLGlyphTexture() {
|
void freeResource(QGuiGLContext *context)
|
||||||
const QGLContext *ctx = QGLContext::currentContext();
|
{
|
||||||
|
const QGLContext *ctx = QGLContext::fromGuiGLContext(context);
|
||||||
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
|
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
|
||||||
qDebug("~QGLGlyphTexture() %p for context %p.", this, ctx);
|
qDebug("~QGLGlyphTexture() %p for context %p.", this, ctx);
|
||||||
#endif
|
#endif
|
||||||
// At this point, the context group is made current, so it's safe to
|
if (!ctx->d_ptr->workaround_brokenFBOReadBack)
|
||||||
// release resources without a makeCurrent() call
|
glDeleteFramebuffers(1, &m_fbo);
|
||||||
if (ctx) {
|
if (m_width || m_height)
|
||||||
if (!ctx->d_ptr->workaround_brokenFBOReadBack)
|
glDeleteTextures(1, &m_texture);
|
||||||
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;
|
GLuint m_texture;
|
||||||
@ -98,10 +104,10 @@ struct QGLGlyphTexture
|
|||||||
int m_height;
|
int m_height;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QImageTextureGlyphCache, public QGLContextGroupResourceBase
|
class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QImageTextureGlyphCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
|
QGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix);
|
||||||
~QGLTextureGlyphCache();
|
~QGLTextureGlyphCache();
|
||||||
|
|
||||||
virtual void createTextureData(int width, int height);
|
virtual void createTextureData(int width, int height);
|
||||||
@ -113,25 +119,24 @@ public:
|
|||||||
|
|
||||||
inline GLuint texture() const {
|
inline GLuint texture() const {
|
||||||
QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
|
QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
|
||||||
QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
|
QGLGlyphTexture *glyphTexture = that->m_textureResource;
|
||||||
return glyphTexture ? glyphTexture->m_texture : 0;
|
return glyphTexture ? glyphTexture->m_texture : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int width() const {
|
inline int width() const {
|
||||||
QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
|
QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
|
||||||
QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
|
QGLGlyphTexture *glyphTexture = that->m_textureResource;
|
||||||
return glyphTexture ? glyphTexture->m_width : 0;
|
return glyphTexture ? glyphTexture->m_width : 0;
|
||||||
}
|
}
|
||||||
inline int height() const {
|
inline int height() const {
|
||||||
QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
|
QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
|
||||||
QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
|
QGLGlyphTexture *glyphTexture = that->m_textureResource;
|
||||||
return glyphTexture ? glyphTexture->m_height : 0;
|
return glyphTexture ? glyphTexture->m_height : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
|
inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
|
||||||
|
|
||||||
void setContext(const QGLContext *context);
|
inline const QGuiGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : 0; }
|
||||||
inline const QGLContext *context() const { return ctx; }
|
|
||||||
|
|
||||||
inline int serialNumber() const { return m_serialNumber; }
|
inline int serialNumber() const { return m_serialNumber; }
|
||||||
|
|
||||||
@ -144,12 +149,9 @@ public:
|
|||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void freeResource(void *) { ctx = 0; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QGLContextGroupResource<QGLGlyphTexture> m_textureResource;
|
QGLGlyphTexture *m_textureResource;
|
||||||
|
|
||||||
const QGLContext *ctx;
|
|
||||||
QGL2PaintEngineExPrivate *pex;
|
QGL2PaintEngineExPrivate *pex;
|
||||||
QGLShaderProgram *m_blitProgram;
|
QGLShaderProgram *m_blitProgram;
|
||||||
FilterMode m_filterMode;
|
FilterMode m_filterMode;
|
||||||
|
@ -1476,42 +1476,16 @@ Q_GLOBAL_STATIC(QGLContextGroupList, qt_context_groups)
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
QGLContextGroup::QGLContextGroup(const QGLContext *context)
|
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);
|
qt_context_groups()->append(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
QGLContextGroup::~QGLContextGroup()
|
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);
|
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)
|
const QGLContext *qt_gl_transfer_context(const QGLContext *ctx)
|
||||||
{
|
{
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
@ -1934,8 +1908,6 @@ QGLContext::~QGLContext()
|
|||||||
|
|
||||||
// clean up resources specific to this context
|
// clean up resources specific to this context
|
||||||
d_ptr->cleanup();
|
d_ptr->cleanup();
|
||||||
// clean up resources belonging to this context's group
|
|
||||||
d_ptr->group->cleanupResources(this);
|
|
||||||
|
|
||||||
QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
|
QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
|
||||||
reset();
|
reset();
|
||||||
@ -5017,108 +4989,6 @@ void QGLContextGroup::removeShare(const QGLContext *context) {
|
|||||||
group->m_shares.clear();
|
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
|
QSize QGLTexture::bindCompressedTexture
|
||||||
(const QString& fileName, const char *format)
|
(const QString& fileName, const char *format)
|
||||||
{
|
{
|
||||||
|
@ -374,7 +374,6 @@ private:
|
|||||||
friend class QGLTextureGlyphCache;
|
friend class QGLTextureGlyphCache;
|
||||||
friend struct QGLGlyphTexture;
|
friend struct QGLGlyphTexture;
|
||||||
friend class QGLContextGroup;
|
friend class QGLContextGroup;
|
||||||
friend class QGLSharedResourceGuard;
|
|
||||||
friend class QGLPixmapBlurFilter;
|
friend class QGLPixmapBlurFilter;
|
||||||
friend class QGLExtensions;
|
friend class QGLExtensions;
|
||||||
friend class QGLTexture;
|
friend class QGLTexture;
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
#include "QtCore/qhash.h"
|
#include "QtCore/qhash.h"
|
||||||
#include "QtCore/qatomic.h"
|
#include "QtCore/qatomic.h"
|
||||||
#include "QtWidgets/private/qwidget_p.h"
|
#include "QtWidgets/private/qwidget_p.h"
|
||||||
|
#include "QtGui/private/qguiglcontext_qpa_p.h"
|
||||||
#include "qcache.h"
|
#include "qcache.h"
|
||||||
#include "qglpaintdevice_p.h"
|
#include "qglpaintdevice_p.h"
|
||||||
|
|
||||||
@ -177,9 +178,6 @@ public:
|
|||||||
bool disable_clear_on_painter_begin;
|
bool disable_clear_on_painter_begin;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QGLContextGroupResourceBase;
|
|
||||||
class QGLSharedResourceGuard;
|
|
||||||
|
|
||||||
// QGLContextPrivate has the responsibility of creating context groups.
|
// QGLContextPrivate has the responsibility of creating context groups.
|
||||||
// QGLContextPrivate maintains the reference counter and destroys
|
// QGLContextPrivate maintains the reference counter and destroys
|
||||||
// context groups when needed.
|
// context groups when needed.
|
||||||
@ -193,9 +191,6 @@ public:
|
|||||||
bool isSharing() const { return m_shares.size() >= 2; }
|
bool isSharing() const { return m_shares.size() >= 2; }
|
||||||
QList<const QGLContext *> shares() const { return m_shares; }
|
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 addShare(const QGLContext *context, const QGLContext *share);
|
||||||
static void removeShare(const QGLContext *context);
|
static void removeShare(const QGLContext *context);
|
||||||
|
|
||||||
@ -205,12 +200,8 @@ private:
|
|||||||
QGLExtensionFuncs m_extensionFuncs;
|
QGLExtensionFuncs m_extensionFuncs;
|
||||||
const QGLContext *m_context; // context group's representative
|
const QGLContext *m_context; // context group's representative
|
||||||
QList<const QGLContext *> m_shares;
|
QList<const QGLContext *> m_shares;
|
||||||
QHash<QGLContextGroupResourceBase *, void *> m_resources;
|
|
||||||
QGLSharedResourceGuard *m_guards; // double-linked list of active guards.
|
|
||||||
QAtomicInt m_refs;
|
QAtomicInt m_refs;
|
||||||
|
|
||||||
void cleanupResources(const QGLContext *ctx);
|
|
||||||
|
|
||||||
friend class QGLContext;
|
friend class QGLContext;
|
||||||
friend class QGLContextPrivate;
|
friend class QGLContextPrivate;
|
||||||
friend class QGLContextGroupResourceBase;
|
friend class QGLContextGroupResourceBase;
|
||||||
@ -539,114 +530,69 @@ QGLTexture* QGLTextureCache::getTexture(QGLContext *ctx, qint64 key)
|
|||||||
|
|
||||||
extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine();
|
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.
|
// Put a guard around a GL object identifier and its context.
|
||||||
// When the context goes away, a shared context will be used
|
// When the context goes away, a shared context will be used
|
||||||
// in its place. If there are no more shared contexts, then
|
// in its place. If there are no more shared contexts, then
|
||||||
// the identifier is returned as zero - it is assumed that the
|
// the identifier is returned as zero - it is assumed that the
|
||||||
// context destruction cleaned up the identifier in this case.
|
// context destruction cleaned up the identifier in this case.
|
||||||
class Q_OPENGL_EXPORT QGLSharedResourceGuard
|
class Q_OPENGL_EXPORT QGLSharedResourceGuardBase : public QGLSharedResource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QGLSharedResourceGuard(const QGLContext *context)
|
QGLSharedResourceGuardBase(QGLContext *context, GLuint id)
|
||||||
: m_group(0), m_id(0), m_next(0), m_prev(0)
|
: 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
|
GLuint id() const
|
||||||
{
|
{
|
||||||
return m_id;
|
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:
|
private:
|
||||||
QGLContextGroup *m_group;
|
Func m_func;
|
||||||
GLuint m_id;
|
|
||||||
QGLSharedResourceGuard *m_next;
|
|
||||||
QGLSharedResourceGuard *m_prev;
|
|
||||||
|
|
||||||
friend class QGLContextGroup;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Func>
|
||||||
|
QGLSharedResourceGuardBase *createSharedResourceGuard(QGLContext *context, GLuint id, Func cleanupFunc)
|
||||||
|
{
|
||||||
|
return new QGLSharedResourceGuard<Func>(context, id, cleanupFunc);
|
||||||
|
}
|
||||||
|
|
||||||
class QGLExtensionMatcher
|
class QGLExtensionMatcher
|
||||||
{
|
{
|
||||||
|
@ -141,7 +141,7 @@ public:
|
|||||||
|
|
||||||
QAtomicInt ref;
|
QAtomicInt ref;
|
||||||
QGLBuffer::Type type;
|
QGLBuffer::Type type;
|
||||||
QGLSharedResourceGuard guard;
|
QGLSharedResourceGuardBase *guard;
|
||||||
QGLBuffer::UsagePattern usagePattern;
|
QGLBuffer::UsagePattern usagePattern;
|
||||||
QGLBuffer::UsagePattern actualUsagePattern;
|
QGLBuffer::UsagePattern actualUsagePattern;
|
||||||
};
|
};
|
||||||
@ -184,7 +184,7 @@ QGLBuffer::QGLBuffer(const QGLBuffer &other)
|
|||||||
d_ptr->ref.ref();
|
d_ptr->ref.ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ctx d->guard.context()
|
#define ctx QGLContext::currentContext();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Destroys this buffer object, including the storage being
|
Destroys this buffer object, including the storage being
|
||||||
@ -250,6 +250,14 @@ void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value)
|
|||||||
|
|
||||||
#undef ctx
|
#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
|
Creates the buffer object in the GL server. Returns true if
|
||||||
the object was created; false otherwise.
|
the object was created; false otherwise.
|
||||||
@ -266,24 +274,26 @@ void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value)
|
|||||||
bool QGLBuffer::create()
|
bool QGLBuffer::create()
|
||||||
{
|
{
|
||||||
Q_D(QGLBuffer);
|
Q_D(QGLBuffer);
|
||||||
if (d->guard.id())
|
if (d->guard && d->guard->id())
|
||||||
return true;
|
return true;
|
||||||
const QGLContext *ctx = QGLContext::currentContext();
|
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
if (!qt_resolve_buffer_extensions(const_cast<QGLContext *>(ctx)))
|
if (!qt_resolve_buffer_extensions(ctx))
|
||||||
return false;
|
return false;
|
||||||
GLuint bufferId = 0;
|
GLuint bufferId = 0;
|
||||||
glGenBuffers(1, &bufferId);
|
glGenBuffers(1, &bufferId);
|
||||||
if (bufferId) {
|
if (bufferId) {
|
||||||
d->guard.setContext(ctx);
|
if (d->guard)
|
||||||
d->guard.setId(bufferId);
|
d->guard->free();
|
||||||
|
|
||||||
|
d->guard = createSharedResourceGuard(ctx, bufferId, freeBufferFunc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ctx d->guard.context()
|
#define ctx QGLContext::currentContext()
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns true if this buffer has been created; false otherwise.
|
Returns true if this buffer has been created; false otherwise.
|
||||||
@ -293,7 +303,7 @@ bool QGLBuffer::create()
|
|||||||
bool QGLBuffer::isCreated() const
|
bool QGLBuffer::isCreated() const
|
||||||
{
|
{
|
||||||
Q_D(const QGLBuffer);
|
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()
|
void QGLBuffer::destroy()
|
||||||
{
|
{
|
||||||
Q_D(QGLBuffer);
|
Q_D(QGLBuffer);
|
||||||
GLuint bufferId = d->guard.id();
|
if (d->guard) {
|
||||||
if (bufferId) {
|
d->guard->free();
|
||||||
// Switch to the original creating context to destroy it.
|
d->guard = 0;
|
||||||
QGLShareContextScope scope(d->guard.context());
|
|
||||||
glDeleteBuffers(1, &bufferId);
|
|
||||||
}
|
}
|
||||||
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");
|
qWarning("QGLBuffer::allocate(): buffer not created");
|
||||||
#endif
|
#endif
|
||||||
Q_D(QGLBuffer);
|
Q_D(QGLBuffer);
|
||||||
if (d->guard.id())
|
if (d->guard && d->guard->id())
|
||||||
glBufferSubData(d->type, offset, count, data);
|
glBufferSubData(d->type, offset, count, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,7 +384,7 @@ void QGLBuffer::allocate(const void *data, int count)
|
|||||||
qWarning("QGLBuffer::allocate(): buffer not created");
|
qWarning("QGLBuffer::allocate(): buffer not created");
|
||||||
#endif
|
#endif
|
||||||
Q_D(QGLBuffer);
|
Q_D(QGLBuffer);
|
||||||
if (d->guard.id())
|
if (d->guard && d->guard->id())
|
||||||
glBufferData(d->type, count, data, d->actualUsagePattern);
|
glBufferData(d->type, count, data, d->actualUsagePattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,10 +419,9 @@ bool QGLBuffer::bind()
|
|||||||
qWarning("QGLBuffer::bind(): buffer not created");
|
qWarning("QGLBuffer::bind(): buffer not created");
|
||||||
#endif
|
#endif
|
||||||
Q_D(const QGLBuffer);
|
Q_D(const QGLBuffer);
|
||||||
GLuint bufferId = d->guard.id();
|
GLuint bufferId = d->guard ? d->guard->id() : 0;
|
||||||
if (bufferId) {
|
if (bufferId) {
|
||||||
if (!QGLContext::areSharing(QGLContext::currentContext(),
|
if (d->guard->group() != QGuiGLContextGroup::currentContextGroup()) {
|
||||||
d->guard.context())) {
|
|
||||||
#ifndef QT_NO_DEBUG
|
#ifndef QT_NO_DEBUG
|
||||||
qWarning("QGLBuffer::bind: buffer is not valid in the current context");
|
qWarning("QGLBuffer::bind: buffer is not valid in the current context");
|
||||||
#endif
|
#endif
|
||||||
@ -445,7 +450,7 @@ void QGLBuffer::release()
|
|||||||
qWarning("QGLBuffer::release(): buffer not created");
|
qWarning("QGLBuffer::release(): buffer not created");
|
||||||
#endif
|
#endif
|
||||||
Q_D(const QGLBuffer);
|
Q_D(const QGLBuffer);
|
||||||
if (d->guard.id())
|
if (d->guard && d->guard->id())
|
||||||
glBindBuffer(d->type, 0);
|
glBindBuffer(d->type, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,7 +476,7 @@ void QGLBuffer::release(QGLBuffer::Type type)
|
|||||||
glBindBuffer(GLenum(type), 0);
|
glBindBuffer(GLenum(type), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ctx d->guard.context()
|
#define ctx QGLContext::currentContext()
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the GL identifier associated with this buffer; zero if
|
Returns the GL identifier associated with this buffer; zero if
|
||||||
@ -482,7 +487,7 @@ void QGLBuffer::release(QGLBuffer::Type type)
|
|||||||
GLuint QGLBuffer::bufferId() const
|
GLuint QGLBuffer::bufferId() const
|
||||||
{
|
{
|
||||||
Q_D(const QGLBuffer);
|
Q_D(const QGLBuffer);
|
||||||
return d->guard.id();
|
return d->guard ? d->guard->id() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef GL_BUFFER_SIZE
|
#ifndef GL_BUFFER_SIZE
|
||||||
@ -501,7 +506,7 @@ GLuint QGLBuffer::bufferId() const
|
|||||||
int QGLBuffer::size() const
|
int QGLBuffer::size() const
|
||||||
{
|
{
|
||||||
Q_D(const QGLBuffer);
|
Q_D(const QGLBuffer);
|
||||||
if (!d->guard.id())
|
if (!d->guard || !d->guard->id())
|
||||||
return -1;
|
return -1;
|
||||||
GLint value = -1;
|
GLint value = -1;
|
||||||
glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value);
|
glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value);
|
||||||
@ -529,7 +534,7 @@ void *QGLBuffer::map(QGLBuffer::Access access)
|
|||||||
if (!isCreated())
|
if (!isCreated())
|
||||||
qWarning("QGLBuffer::map(): buffer not created");
|
qWarning("QGLBuffer::map(): buffer not created");
|
||||||
#endif
|
#endif
|
||||||
if (!d->guard.id())
|
if (!d->guard || !d->guard->id())
|
||||||
return 0;
|
return 0;
|
||||||
if (!glMapBufferARB)
|
if (!glMapBufferARB)
|
||||||
return 0;
|
return 0;
|
||||||
@ -556,7 +561,7 @@ bool QGLBuffer::unmap()
|
|||||||
if (!isCreated())
|
if (!isCreated())
|
||||||
qWarning("QGLBuffer::unmap(): buffer not created");
|
qWarning("QGLBuffer::unmap(): buffer not created");
|
||||||
#endif
|
#endif
|
||||||
if (!d->guard.id())
|
if (!d->guard || !d->guard->id())
|
||||||
return false;
|
return false;
|
||||||
if (!glUnmapBufferARB)
|
if (!glUnmapBufferARB)
|
||||||
return false;
|
return false;
|
||||||
|
@ -55,8 +55,8 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
extern Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
|
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_FUNC_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
|
||||||
#define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context();
|
#define QGL_FUNCP_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
#ifndef QT_NO_DEBUG
|
||||||
#define QT_RESET_GLERROR() \
|
#define QT_RESET_GLERROR() \
|
||||||
@ -351,13 +351,7 @@ void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
|
|||||||
|
|
||||||
QGLContext *QGLFBOGLPaintDevice::context() const
|
QGLContext *QGLFBOGLPaintDevice::context() const
|
||||||
{
|
{
|
||||||
QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
|
return const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
|
|
||||||
|
|
||||||
if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
|
|
||||||
return currentContext;
|
|
||||||
else
|
|
||||||
return fboContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
|
bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
|
||||||
@ -407,13 +401,33 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
|
|||||||
return false;
|
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,
|
void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
|
||||||
QGLFramebufferObject::Attachment attachment,
|
QGLFramebufferObject::Attachment attachment,
|
||||||
GLenum texture_target, GLenum internal_format,
|
GLenum texture_target, GLenum internal_format,
|
||||||
GLint samples, bool mipmap)
|
GLint samples, bool mipmap)
|
||||||
{
|
{
|
||||||
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
|
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
fbo_guard.setContext(ctx);
|
|
||||||
|
|
||||||
bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
|
bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
|
||||||
if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
|
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;
|
GLuint fbo = 0;
|
||||||
glGenFramebuffers(1, &fbo);
|
glGenFramebuffers(1, &fbo);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 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();
|
QT_CHECK_GLERROR();
|
||||||
// init texture
|
// init texture
|
||||||
@ -603,7 +619,21 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
|
|||||||
}
|
}
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
|
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)
|
if (color_buffer)
|
||||||
glDeleteRenderbuffers(1, &color_buffer);
|
glDeleteRenderbuffers(1, &color_buffer);
|
||||||
else
|
else
|
||||||
@ -613,7 +643,6 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
|
|||||||
if (stencil_buffer && depth_buffer != stencil_buffer)
|
if (stencil_buffer && depth_buffer != stencil_buffer)
|
||||||
glDeleteRenderbuffers(1, &stencil_buffer);
|
glDeleteRenderbuffers(1, &stencil_buffer);
|
||||||
glDeleteFramebuffers(1, &fbo);
|
glDeleteFramebuffers(1, &fbo);
|
||||||
fbo_guard.setId(0);
|
|
||||||
}
|
}
|
||||||
QT_CHECK_GLERROR();
|
QT_CHECK_GLERROR();
|
||||||
|
|
||||||
@ -622,6 +651,8 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
|
|||||||
format.setAttachment(fbo_attachment);
|
format.setAttachment(fbo_attachment);
|
||||||
format.setInternalTextureFormat(internal_format);
|
format.setInternalTextureFormat(internal_format);
|
||||||
format.setMipmap(mipmap);
|
format.setMipmap(mipmap);
|
||||||
|
|
||||||
|
glDevice.setFBO(q, attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -849,23 +880,19 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm
|
|||||||
QGLFramebufferObject::~QGLFramebufferObject()
|
QGLFramebufferObject::~QGLFramebufferObject()
|
||||||
{
|
{
|
||||||
Q_D(QGLFramebufferObject);
|
Q_D(QGLFramebufferObject);
|
||||||
QGL_FUNC_CONTEXT;
|
|
||||||
|
|
||||||
delete d->engine;
|
delete d->engine;
|
||||||
|
|
||||||
if (isValid() && ctx) {
|
if (d->texture_guard)
|
||||||
QGLShareContextScope scope(ctx);
|
d->texture_guard->free();
|
||||||
if (d->texture)
|
if (d->color_buffer_guard)
|
||||||
glDeleteTextures(1, &d->texture);
|
d->color_buffer_guard->free();
|
||||||
if (d->color_buffer)
|
if (d->depth_buffer_guard)
|
||||||
glDeleteRenderbuffers(1, &d->color_buffer);
|
d->depth_buffer_guard->free();
|
||||||
if (d->depth_buffer)
|
if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard)
|
||||||
glDeleteRenderbuffers(1, &d->depth_buffer);
|
d->stencil_buffer_guard->free();
|
||||||
if (d->stencil_buffer && d->stencil_buffer != d->depth_buffer)
|
if (d->fbo_guard)
|
||||||
glDeleteRenderbuffers(1, &d->stencil_buffer);
|
d->fbo_guard->free();
|
||||||
GLuint fbo = d->fbo();
|
|
||||||
glDeleteFramebuffers(1, &fbo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -889,7 +916,7 @@ QGLFramebufferObject::~QGLFramebufferObject()
|
|||||||
bool QGLFramebufferObject::isValid() const
|
bool QGLFramebufferObject::isValid() const
|
||||||
{
|
{
|
||||||
Q_D(const QGLFramebufferObject);
|
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
|
GLuint QGLFramebufferObject::texture() const
|
||||||
{
|
{
|
||||||
Q_D(const QGLFramebufferObject);
|
Q_D(const QGLFramebufferObject);
|
||||||
return d->texture;
|
return d->texture_guard ? d->texture_guard->id() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -130,8 +130,9 @@ private:
|
|||||||
class QGLFramebufferObjectPrivate
|
class QGLFramebufferObjectPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_buffer(0), stencil_buffer(0)
|
QGLFramebufferObjectPrivate() : fbo_guard(0), texture_guard(0), depth_buffer_guard(0)
|
||||||
, color_buffer(0), valid(false), engine(0) {}
|
, stencil_buffer_guard(0), color_buffer_guard(0)
|
||||||
|
, valid(false), engine(0) {}
|
||||||
~QGLFramebufferObjectPrivate() {}
|
~QGLFramebufferObjectPrivate() {}
|
||||||
|
|
||||||
void init(QGLFramebufferObject *q, const QSize& sz,
|
void init(QGLFramebufferObject *q, const QSize& sz,
|
||||||
@ -139,11 +140,11 @@ public:
|
|||||||
GLenum internal_format, GLenum texture_target,
|
GLenum internal_format, GLenum texture_target,
|
||||||
GLint samples = 0, bool mipmap = false);
|
GLint samples = 0, bool mipmap = false);
|
||||||
bool checkFramebufferStatus() const;
|
bool checkFramebufferStatus() const;
|
||||||
QGLSharedResourceGuard fbo_guard;
|
QGLSharedResourceGuardBase *fbo_guard;
|
||||||
GLuint texture;
|
QGLSharedResourceGuardBase *texture_guard;
|
||||||
GLuint depth_buffer;
|
QGLSharedResourceGuardBase *depth_buffer_guard;
|
||||||
GLuint stencil_buffer;
|
QGLSharedResourceGuardBase *stencil_buffer_guard;
|
||||||
GLuint color_buffer;
|
QGLSharedResourceGuardBase *color_buffer_guard;
|
||||||
GLenum target;
|
GLenum target;
|
||||||
QSize size;
|
QSize size;
|
||||||
QGLFramebufferObjectFormat format;
|
QGLFramebufferObjectFormat format;
|
||||||
@ -152,7 +153,7 @@ public:
|
|||||||
mutable QPaintEngine *engine;
|
mutable QPaintEngine *engine;
|
||||||
QGLFBOGLPaintDevice glDevice;
|
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 "qglfunctions.h"
|
||||||
#include "qgl_p.h"
|
#include "qgl_p.h"
|
||||||
|
#include "QtGui/private/qguiglcontext_qpa_p.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -139,16 +140,27 @@ QT_BEGIN_NAMESPACE
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Hidden private fields for additional extension data.
|
// Hidden private fields for additional extension data.
|
||||||
struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate
|
struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResource
|
||||||
{
|
{
|
||||||
QGLFunctionsPrivateEx(const QGLContext *context = 0)
|
QGLFunctionsPrivateEx(QGuiGLContext *context)
|
||||||
: QGLFunctionsPrivate(context)
|
: QGLFunctionsPrivate(QGLContext::fromGuiGLContext(context))
|
||||||
|
, QGLSharedResource(context->shareGroup())
|
||||||
, m_features(-1) {}
|
, m_features(-1) {}
|
||||||
|
|
||||||
|
void invalidateResource()
|
||||||
|
{
|
||||||
|
m_features = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeResource(QGuiGLContext *)
|
||||||
|
{
|
||||||
|
// no gl resources to free
|
||||||
|
}
|
||||||
|
|
||||||
int m_features;
|
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)
|
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);
|
Q_ASSERT(context);
|
||||||
QGLFunctionsPrivateEx *funcs =
|
QGLFunctionsPrivateEx *funcs =
|
||||||
reinterpret_cast<QGLFunctionsPrivateEx *>
|
reinterpret_cast<QGLFunctionsPrivateEx *>
|
||||||
(qt_gl_functions_resource()->value(context));
|
(qt_gl_functions_resource()->value<QGLFunctionsPrivateEx>(context->contextHandle()));
|
||||||
#if QT_VERSION < 0x040800
|
|
||||||
if (!funcs) {
|
|
||||||
funcs = new QGLFunctionsPrivateEx();
|
|
||||||
qt_gl_functions_resource()->insert(context, funcs);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return funcs;
|
return funcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,15 +189,15 @@ class QGLShaderPrivate : public QObjectPrivate
|
|||||||
{
|
{
|
||||||
Q_DECLARE_PUBLIC(QGLShader)
|
Q_DECLARE_PUBLIC(QGLShader)
|
||||||
public:
|
public:
|
||||||
QGLShaderPrivate(const QGLContext *context, QGLShader::ShaderType type)
|
QGLShaderPrivate(const QGLContext *, QGLShader::ShaderType type)
|
||||||
: shaderGuard(context)
|
: shaderGuard(0)
|
||||||
, shaderType(type)
|
, shaderType(type)
|
||||||
, compiled(false)
|
, compiled(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~QGLShaderPrivate();
|
~QGLShaderPrivate();
|
||||||
|
|
||||||
QGLSharedResourceGuard shaderGuard;
|
QGLSharedResourceGuardBase *shaderGuard;
|
||||||
QGLShader::ShaderType shaderType;
|
QGLShader::ShaderType shaderType;
|
||||||
bool compiled;
|
bool compiled;
|
||||||
QString log;
|
QString log;
|
||||||
@ -207,22 +207,28 @@ public:
|
|||||||
void deleteShader();
|
void deleteShader();
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ctx shaderGuard.context()
|
namespace {
|
||||||
|
void freeShaderFunc(QGLContext *ctx, GLuint id)
|
||||||
|
{
|
||||||
|
Q_UNUSED(ctx);
|
||||||
|
glDeleteShader(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ctx QGLContext::currentContext()
|
||||||
|
|
||||||
QGLShaderPrivate::~QGLShaderPrivate()
|
QGLShaderPrivate::~QGLShaderPrivate()
|
||||||
{
|
{
|
||||||
if (shaderGuard.id()) {
|
if (shaderGuard)
|
||||||
QGLShareContextScope scope(shaderGuard.context());
|
shaderGuard->free();
|
||||||
glDeleteShader(shaderGuard.id());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QGLShaderPrivate::create()
|
bool QGLShaderPrivate::create()
|
||||||
{
|
{
|
||||||
const QGLContext *context = shaderGuard.context();
|
QGLContext *context = const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
if (!context)
|
if (!context)
|
||||||
return false;
|
return false;
|
||||||
if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
|
if (qt_resolve_glsl_extensions(context)) {
|
||||||
GLuint shader;
|
GLuint shader;
|
||||||
if (shaderType == QGLShader::Vertex)
|
if (shaderType == QGLShader::Vertex)
|
||||||
shader = glCreateShader(GL_VERTEX_SHADER);
|
shader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
@ -234,7 +240,7 @@ bool QGLShaderPrivate::create()
|
|||||||
qWarning() << "QGLShader: could not create shader";
|
qWarning() << "QGLShader: could not create shader";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
shaderGuard.setId(shader);
|
shaderGuard = createSharedResourceGuard(context, shader, freeShaderFunc);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -243,7 +249,7 @@ bool QGLShaderPrivate::create()
|
|||||||
|
|
||||||
bool QGLShaderPrivate::compile(QGLShader *q)
|
bool QGLShaderPrivate::compile(QGLShader *q)
|
||||||
{
|
{
|
||||||
GLuint shader = shaderGuard.id();
|
GLuint shader = shaderGuard ? shaderGuard->id() : 0;
|
||||||
if (!shader)
|
if (!shader)
|
||||||
return false;
|
return false;
|
||||||
glCompileShader(shader);
|
glCompileShader(shader);
|
||||||
@ -286,15 +292,12 @@ bool QGLShaderPrivate::compile(QGLShader *q)
|
|||||||
|
|
||||||
void QGLShaderPrivate::deleteShader()
|
void QGLShaderPrivate::deleteShader()
|
||||||
{
|
{
|
||||||
if (shaderGuard.id()) {
|
if (shaderGuard) {
|
||||||
glDeleteShader(shaderGuard.id());
|
shaderGuard->free();
|
||||||
shaderGuard.setId(0);
|
shaderGuard = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ctx
|
|
||||||
#define ctx d->shaderGuard.context()
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Constructs a new QGLShader object of the specified \a type
|
Constructs a new QGLShader object of the specified \a type
|
||||||
and attaches it to \a parent. If shader programs are not supported,
|
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)
|
bool QGLShader::compileSourceCode(const char *source)
|
||||||
{
|
{
|
||||||
Q_D(QGLShader);
|
Q_D(QGLShader);
|
||||||
if (d->shaderGuard.id()) {
|
if (d->shaderGuard && d->shaderGuard->id()) {
|
||||||
QVarLengthArray<const char *, 4> src;
|
QVarLengthArray<const char *, 4> src;
|
||||||
QVarLengthArray<GLint, 4> srclen;
|
QVarLengthArray<GLint, 4> srclen;
|
||||||
int headerLen = 0;
|
int headerLen = 0;
|
||||||
@ -420,7 +423,7 @@ bool QGLShader::compileSourceCode(const char *source)
|
|||||||
#endif
|
#endif
|
||||||
src.append(source + headerLen);
|
src.append(source + headerLen);
|
||||||
srclen.append(GLint(qstrlen(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);
|
return d->compile(this);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -480,7 +483,7 @@ bool QGLShader::compileSourceFile(const QString& fileName)
|
|||||||
QByteArray QGLShader::sourceCode() const
|
QByteArray QGLShader::sourceCode() const
|
||||||
{
|
{
|
||||||
Q_D(const QGLShader);
|
Q_D(const QGLShader);
|
||||||
GLuint shader = d->shaderGuard.id();
|
GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0;
|
||||||
if (!shader)
|
if (!shader)
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
GLint size = 0;
|
GLint size = 0;
|
||||||
@ -525,22 +528,17 @@ QString QGLShader::log() const
|
|||||||
GLuint QGLShader::shaderId() const
|
GLuint QGLShader::shaderId() const
|
||||||
{
|
{
|
||||||
Q_D(const QGLShader);
|
Q_D(const QGLShader);
|
||||||
return d->shaderGuard.id();
|
return d->shaderGuard ? d->shaderGuard->id() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#undef ctx
|
#undef ctx
|
||||||
#define ctx programGuard.context()
|
|
||||||
|
|
||||||
class QGLShaderProgramPrivate : public QObjectPrivate
|
class QGLShaderProgramPrivate : public QObjectPrivate
|
||||||
{
|
{
|
||||||
Q_DECLARE_PUBLIC(QGLShaderProgram)
|
Q_DECLARE_PUBLIC(QGLShaderProgram)
|
||||||
public:
|
public:
|
||||||
QGLShaderProgramPrivate(const QGLContext *context)
|
QGLShaderProgramPrivate(const QGLContext *)
|
||||||
: programGuard(context)
|
: programGuard(0)
|
||||||
, linked(false)
|
, linked(false)
|
||||||
, inited(false)
|
, inited(false)
|
||||||
, removingShaders(false)
|
, removingShaders(false)
|
||||||
@ -551,7 +549,7 @@ public:
|
|||||||
}
|
}
|
||||||
~QGLShaderProgramPrivate();
|
~QGLShaderProgramPrivate();
|
||||||
|
|
||||||
QGLSharedResourceGuard programGuard;
|
QGLSharedResourceGuardBase *programGuard;
|
||||||
bool linked;
|
bool linked;
|
||||||
bool inited;
|
bool inited;
|
||||||
bool removingShaders;
|
bool removingShaders;
|
||||||
@ -567,12 +565,19 @@ public:
|
|||||||
bool hasShader(QGLShader::ShaderType type) const;
|
bool hasShader(QGLShader::ShaderType type) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void freeProgramFunc(QGLContext *ctx, GLuint id)
|
||||||
|
{
|
||||||
|
Q_UNUSED(ctx);
|
||||||
|
glDeleteProgram(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QGLShaderProgramPrivate::~QGLShaderProgramPrivate()
|
QGLShaderProgramPrivate::~QGLShaderProgramPrivate()
|
||||||
{
|
{
|
||||||
if (programGuard.id()) {
|
if (programGuard)
|
||||||
QGLShareContextScope scope(programGuard.context());
|
programGuard->free();
|
||||||
glDeleteProgram(programGuard.id());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
|
bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
|
||||||
@ -584,8 +589,7 @@ bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ctx
|
#define ctx QGLContext::currentContext()
|
||||||
#define ctx d->programGuard.context()
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Constructs a new shader program and attaches it to \a parent.
|
Constructs a new shader program and attaches it to \a parent.
|
||||||
@ -623,24 +627,21 @@ QGLShaderProgram::~QGLShaderProgram()
|
|||||||
bool QGLShaderProgram::init()
|
bool QGLShaderProgram::init()
|
||||||
{
|
{
|
||||||
Q_D(QGLShaderProgram);
|
Q_D(QGLShaderProgram);
|
||||||
if (d->programGuard.id() || d->inited)
|
if ((d->programGuard && d->programGuard->id()) || d->inited)
|
||||||
return true;
|
return true;
|
||||||
d->inited = true;
|
d->inited = true;
|
||||||
const QGLContext *context = d->programGuard.context();
|
QGLContext *context = const_cast<QGLContext *>(QGLContext::currentContext());
|
||||||
if (!context) {
|
|
||||||
context = QGLContext::currentContext();
|
|
||||||
d->programGuard.setContext(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
return false;
|
return false;
|
||||||
if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
|
if (qt_resolve_glsl_extensions(context)) {
|
||||||
GLuint program = glCreateProgram();
|
GLuint program = glCreateProgram();
|
||||||
if (!program) {
|
if (!program) {
|
||||||
qWarning() << "QGLShaderProgram: could not create shader program";
|
qWarning() << "QGLShaderProgram: could not create shader program";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
d->programGuard.setId(program);
|
if (d->programGuard)
|
||||||
|
delete d->programGuard;
|
||||||
|
d->programGuard = createSharedResourceGuard(context, program, freeProgramFunc);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "QGLShaderProgram: shader programs are not supported";
|
qWarning() << "QGLShaderProgram: shader programs are not supported";
|
||||||
@ -667,15 +668,14 @@ bool QGLShaderProgram::addShader(QGLShader *shader)
|
|||||||
return false;
|
return false;
|
||||||
if (d->shaders.contains(shader))
|
if (d->shaders.contains(shader))
|
||||||
return true; // Already added to this shader program.
|
return true; // Already added to this shader program.
|
||||||
if (d->programGuard.id() && shader) {
|
if (d->programGuard && d->programGuard->id() && shader) {
|
||||||
if (!QGLContext::areSharing(shader->d_func()->shaderGuard.context(),
|
if (!shader->d_func()->shaderGuard || !shader->d_func()->shaderGuard->id())
|
||||||
d->programGuard.context())) {
|
return false;
|
||||||
|
if (d->programGuard->group() != shader->d_func()->shaderGuard->group()) {
|
||||||
qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context.");
|
qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!shader->d_func()->shaderGuard.id())
|
glAttachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
|
||||||
return false;
|
|
||||||
glAttachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
|
|
||||||
d->linked = false; // Program needs to be relinked.
|
d->linked = false; // Program needs to be relinked.
|
||||||
d->shaders.append(shader);
|
d->shaders.append(shader);
|
||||||
connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
|
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.
|
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()
|
\sa addShader(), link(), removeAllShaders()
|
||||||
*/
|
*/
|
||||||
void QGLShaderProgram::removeShader(QGLShader *shader)
|
void QGLShaderProgram::removeShader(QGLShader *shader)
|
||||||
{
|
{
|
||||||
Q_D(QGLShaderProgram);
|
Q_D(QGLShaderProgram);
|
||||||
if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id()) {
|
if (d->programGuard && d->programGuard->id()
|
||||||
QGLShareContextScope scope(d->programGuard.context());
|
&& shader && shader->d_func()->shaderGuard)
|
||||||
glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
|
{
|
||||||
|
glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
|
||||||
}
|
}
|
||||||
d->linked = false; // Program needs to be relinked.
|
d->linked = false; // Program needs to be relinked.
|
||||||
if (shader) {
|
if (shader) {
|
||||||
@ -826,8 +829,11 @@ void QGLShaderProgram::removeAllShaders()
|
|||||||
Q_D(QGLShaderProgram);
|
Q_D(QGLShaderProgram);
|
||||||
d->removingShaders = true;
|
d->removingShaders = true;
|
||||||
foreach (QGLShader *shader, d->shaders) {
|
foreach (QGLShader *shader, d->shaders) {
|
||||||
if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id())
|
if (d->programGuard && d->programGuard->id()
|
||||||
glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
|
&& shader && shader->d_func()->shaderGuard)
|
||||||
|
{
|
||||||
|
glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
foreach (QGLShader *shader, d->anonShaders) {
|
foreach (QGLShader *shader, d->anonShaders) {
|
||||||
// Delete shader objects that were created anonymously.
|
// Delete shader objects that were created anonymously.
|
||||||
@ -856,7 +862,7 @@ void QGLShaderProgram::removeAllShaders()
|
|||||||
bool QGLShaderProgram::link()
|
bool QGLShaderProgram::link()
|
||||||
{
|
{
|
||||||
Q_D(QGLShaderProgram);
|
Q_D(QGLShaderProgram);
|
||||||
GLuint program = d->programGuard.id();
|
GLuint program = d->programGuard ? d->programGuard->id() : 0;
|
||||||
if (!program)
|
if (!program)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -946,13 +952,13 @@ QString QGLShaderProgram::log() const
|
|||||||
bool QGLShaderProgram::bind()
|
bool QGLShaderProgram::bind()
|
||||||
{
|
{
|
||||||
Q_D(QGLShaderProgram);
|
Q_D(QGLShaderProgram);
|
||||||
GLuint program = d->programGuard.id();
|
GLuint program = d->programGuard ? d->programGuard->id() : 0;
|
||||||
if (!program)
|
if (!program)
|
||||||
return false;
|
return false;
|
||||||
if (!d->linked && !link())
|
if (!d->linked && !link())
|
||||||
return false;
|
return false;
|
||||||
#ifndef QT_NO_DEBUG
|
#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.");
|
qWarning("QGLShaderProgram::bind: program is not valid in the current context.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -974,7 +980,7 @@ void QGLShaderProgram::release()
|
|||||||
{
|
{
|
||||||
#ifndef QT_NO_DEBUG
|
#ifndef QT_NO_DEBUG
|
||||||
Q_D(QGLShaderProgram);
|
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.");
|
qWarning("QGLShaderProgram::release: program is not valid in the current context.");
|
||||||
#endif
|
#endif
|
||||||
#if defined(QT_OPENGL_ES_2)
|
#if defined(QT_OPENGL_ES_2)
|
||||||
@ -996,7 +1002,7 @@ void QGLShaderProgram::release()
|
|||||||
GLuint QGLShaderProgram::programId() const
|
GLuint QGLShaderProgram::programId() const
|
||||||
{
|
{
|
||||||
Q_D(const QGLShaderProgram);
|
Q_D(const QGLShaderProgram);
|
||||||
GLuint id = d->programGuard.id();
|
GLuint id = d->programGuard ? d->programGuard->id() : 0;
|
||||||
if (id)
|
if (id)
|
||||||
return id;
|
return id;
|
||||||
|
|
||||||
@ -1005,7 +1011,7 @@ GLuint QGLShaderProgram::programId() const
|
|||||||
// themselves, particularly those using program binaries.
|
// themselves, particularly those using program binaries.
|
||||||
if (!const_cast<QGLShaderProgram *>(this)->init())
|
if (!const_cast<QGLShaderProgram *>(this)->init())
|
||||||
return 0;
|
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)
|
void QGLShaderProgram::bindAttributeLocation(const char *name, int location)
|
||||||
{
|
{
|
||||||
Q_D(QGLShaderProgram);
|
Q_D(QGLShaderProgram);
|
||||||
if (!init())
|
if (!init() || !d->programGuard || !d->programGuard->id())
|
||||||
return;
|
return;
|
||||||
glBindAttribLocation(d->programGuard.id(), location, name);
|
glBindAttribLocation(d->programGuard->id(), location, name);
|
||||||
d->linked = false; // Program needs to be relinked.
|
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
|
int QGLShaderProgram::attributeLocation(const char *name) const
|
||||||
{
|
{
|
||||||
Q_D(const QGLShaderProgram);
|
Q_D(const QGLShaderProgram);
|
||||||
if (d->linked) {
|
if (d->linked && d->programGuard && d->programGuard->id()) {
|
||||||
return glGetAttribLocation(d->programGuard.id(), name);
|
return glGetAttribLocation(d->programGuard->id(), name);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "QGLShaderProgram::attributeLocation(" << name
|
qWarning() << "QGLShaderProgram::attributeLocation(" << name
|
||||||
<< "): shader program is not linked";
|
<< "): shader program is not linked";
|
||||||
@ -1752,8 +1758,8 @@ int QGLShaderProgram::uniformLocation(const char *name) const
|
|||||||
{
|
{
|
||||||
Q_D(const QGLShaderProgram);
|
Q_D(const QGLShaderProgram);
|
||||||
Q_UNUSED(d);
|
Q_UNUSED(d);
|
||||||
if (d->linked) {
|
if (d->linked && d->programGuard && d->programGuard->id()) {
|
||||||
return glGetUniformLocation(d->programGuard.id(), name);
|
return glGetUniformLocation(d->programGuard->id(), name);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "QGLShaderProgram::uniformLocation(" << name
|
qWarning() << "QGLShaderProgram::uniformLocation(" << name
|
||||||
<< "): shader program is not linked";
|
<< "): shader program is not linked";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user