summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp22
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h3
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp11
-rw-r--r--src/opengl/qgl.cpp159
-rw-r--r--src/opengl/qgl.h1
-rw-r--r--src/opengl/qgl_p.h95
6 files changed, 228 insertions, 63 deletions
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index 27636f4..d7c91b8 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -49,6 +49,28 @@
QT_BEGIN_NAMESPACE
+static void QGLEngineShaderManager_free(void *ptr)
+{
+ delete reinterpret_cast<QGLEngineShaderManager *>(ptr);
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shader_managers, (QGLEngineShaderManager_free))
+
+QGLEngineShaderManager *QGLEngineShaderManager::managerForContext(const QGLContext *context)
+{
+ QGLEngineShaderManager *p = reinterpret_cast<QGLEngineShaderManager *>(qt_shader_managers()->value(context));
+ if (!p) {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != context)
+ const_cast<QGLContext *>(context)->makeCurrent();
+ p = new QGLEngineShaderManager(const_cast<QGLContext *>(context));
+ qt_shader_managers()->insert(context, p);
+ if (oldContext && oldContext != context)
+ oldContext->makeCurrent();
+ }
+ return p;
+}
+
const char* QGLEngineShaderManager::qglEngineShaderSourceCode[] = {
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 442edfe..99711bd40 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -220,6 +220,7 @@
#include <QGLShader>
#include <QGLShaderProgram>
#include <QPainter>
+#include <private/qgl_p.h>
QT_BEGIN_HEADER
@@ -314,6 +315,8 @@ public:
QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
+ static QGLEngineShaderManager *managerForContext(const QGLContext *context);
+
enum ShaderName {
MainVertexShader,
MainWithTexCoordsVertexShader,
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 2bfbf4a..9b0321d 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -266,10 +266,6 @@ extern QImage qt_imageForBrush(int brushStyle, bool invert);
QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
{
- if (shaderManager) {
- delete shaderManager;
- shaderManager = 0;
- }
}
void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
@@ -1209,11 +1205,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
qt_resolve_version_2_0_functions(d->ctx);
#endif
- if (d->shaderManager) {
- d->shaderManager->setDirty();
- } else {
- d->shaderManager = new QGLEngineShaderManager(d->ctx);
- }
+ d->shaderManager = QGLEngineShaderManager::managerForContext(d->ctx);
+ d->shaderManager->setDirty();
glViewport(0, 0, d->width, d->height);
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 0169ea2..f51b271 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -3363,8 +3363,13 @@ bool QGLWidget::event(QEvent *e)
#elif defined(Q_WS_WIN)
if (e->type() == QEvent::ParentChange) {
QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this);
- qgl_share_reg()->replaceShare(d->glcx, newContext);
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(d->glcx);
setContext(newContext);
+ for (int i = 0; i < shares.size(); ++i) {
+ if (newContext != shares.at(i))
+ qgl_share_reg()->addShare(newContext, shares.at(i));
+ }
+
// the overlay needs to be recreated as well
delete d->olcx;
if (isValid() && context()->format().hasOverlay()) {
@@ -4612,4 +4617,156 @@ bool QGLDrawable::autoFillBackground() const
return false;
}
+
+bool QGLShareRegister::checkSharing(const QGLContext *context1, const QGLContext *context2) {
+ bool sharing = (context1 && context2 && context1->d_ptr->groupResources == context2->d_ptr->groupResources);
+ return sharing;
+}
+
+void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) {
+ Q_ASSERT(context && share);
+ if (context->d_ptr->groupResources == share->d_ptr->groupResources)
+ return;
+
+ // Make sure 'context' is not already shared with another group of contexts.
+ Q_ASSERT(reg.find(context->d_ptr->groupResources) == reg.end());
+ Q_ASSERT(context->d_ptr->groupResources->refs == 1);
+
+ // Free 'context' group resources and make it use the same resources as 'share'.
+ delete context->d_ptr->groupResources;
+ context->d_ptr->groupResources = share->d_ptr->groupResources;
+ context->d_ptr->groupResources->refs.ref();
+
+ // Maintain a list of all the contexts in each group of sharing contexts.
+ SharingHash::iterator it = reg.find(share->d_ptr->groupResources);
+ if (it == reg.end())
+ it = reg.insert(share->d_ptr->groupResources, ContextList() << share);
+ it.value() << context;
+}
+
+QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) {
+ SharingHash::const_iterator it = reg.find(context->d_ptr->groupResources);
+ if (it == reg.end())
+ return ContextList();
+ return it.value();
+}
+
+void QGLShareRegister::removeShare(const QGLContext *context) {
+ SharingHash::iterator it = reg.find(context->d_ptr->groupResources);
+ if (it == reg.end())
+ return;
+
+ int count = it.value().removeAll(context);
+ Q_ASSERT(count == 1);
+
+ Q_ASSERT(it.value().size() != 0);
+ if (it.value().size() == 1)
+ reg.erase(it);
+}
+
+QGLContextResource::QGLContextResource(FreeFunc f, QObject *parent)
+ : QObject(parent), free(f)
+{
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)), this, SLOT(aboutToDestroyContext(const QGLContext *)));
+}
+
+QGLContextResource::~QGLContextResource()
+{
+ while (!m_resources.empty())
+ remove(m_resources.begin().key());
+}
+
+void QGLContextResource::insert(const QGLContext *key, void *value)
+{
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
+ if (shares.size() == 0)
+ shares.append(key);
+ void *oldValue = 0;
+ for (int i = 0; i < shares.size(); ++i) {
+ ResourceHash::iterator it = m_resources.find(shares.at(i));
+ if (it != m_resources.end()) {
+ Q_ASSERT(oldValue == 0 || oldValue == it.value());
+ oldValue = it.value();
+ it.value() = value;
+ } else {
+ m_resources.insert(shares.at(i), value);
+ }
+ }
+ if (oldValue != 0 && oldValue != value) {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != key)
+ const_cast<QGLContext *>(key)->makeCurrent();
+ free(oldValue);
+ if (oldContext && oldContext != key)
+ oldContext->makeCurrent();
+ }
+}
+
+void *QGLContextResource::value(const QGLContext *key)
+{
+ ResourceHash::const_iterator it = m_resources.find(key);
+ // Check if there is a value associated with 'key'.
+ if (it != m_resources.end())
+ return it.value();
+ // Check if there is a value associated with sharing contexts.
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
+ for (int i = 0; i < shares.size() && it == m_resources.end(); ++i)
+ it = m_resources.find(shares.at(i));
+ if (it == m_resources.end())
+ return 0; // Didn't find anything.
+
+ // Found something! Share this info with all the buddies.
+ for (int i = 0; i < shares.size(); ++i)
+ m_resources.insert(shares.at(i), it.value());
+ return it.value();
+}
+
+void QGLContextResource::remove(const QGLContext *key)
+{
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
+ if (shares.size() == 0)
+ shares.append(key);
+ void *oldValue = 0;
+ for (int i = 0; i < shares.size(); ++i) {
+ ResourceHash::iterator it = m_resources.find(shares.at(i));
+ if (it != m_resources.end()) {
+ Q_ASSERT(oldValue == 0 || oldValue == it.value());
+ oldValue = it.value();
+ m_resources.erase(it);
+ }
+ }
+ if (oldValue != 0) {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != key)
+ const_cast<QGLContext *>(key)->makeCurrent();
+ free(oldValue);
+ if (oldContext && oldContext != key)
+ oldContext->makeCurrent();
+ }
+}
+
+void QGLContextResource::aboutToDestroyContext(const QGLContext *key)
+{
+ ResourceHash::iterator it = m_resources.find(key);
+ if (it == m_resources.end())
+ return;
+
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
+ if (shares.size() > 1) {
+ Q_ASSERT(key->isSharing());
+ // At least one of the shared contexts must stay in the cache.
+ // Otherwise, the value pointer is lost.
+ for (int i = 0; i < 2/*shares.size()*/; ++i)
+ m_resources.insert(shares.at(i), it.value());
+ } else {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != key)
+ const_cast<QGLContext *>(key)->makeCurrent();
+ free(it.value());
+ if (oldContext && oldContext != key)
+ oldContext->makeCurrent();
+ }
+ m_resources.erase(it);
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index 86555da..31b9543 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -364,6 +364,7 @@ private:
friend class QGLPixmapData;
friend class QGLPixmapFilterBase;
friend class QGLTextureGlyphCache;
+ friend class QGLShareRegister;
friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags();
#ifdef Q_WS_MAC
public:
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index ac19d64..fda0257 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -196,12 +196,19 @@ public:
#endif
};
+struct QGLContextGroupResources
+{
+ QGLContextGroupResources() : refs(1) { }
+ QGLExtensionFuncs extensionFuncs;
+ QAtomicInt refs;
+};
+
class QGLContextPrivate
{
Q_DECLARE_PUBLIC(QGLContext)
public:
- explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {}
- ~QGLContextPrivate() {}
+ explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {groupResources = new QGLContextGroupResources;}
+ ~QGLContextPrivate() {if (!groupResources->refs.deref()) delete groupResources;}
GLuint bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
bool clean = false);
GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean);
@@ -257,14 +264,14 @@ public:
QGLContext *q_ptr;
QGLFormat::OpenGLVersionFlags version_flags;
- QGLExtensionFuncs extensionFuncs;
+ QGLContextGroupResources *groupResources;
GLint max_texture_size;
GLuint current_fbo;
QPaintEngine *active_engine;
#ifdef Q_WS_WIN
- static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->extensionFuncs; }
+ static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->groupResources->extensionFuncs; }
#endif
#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
@@ -371,62 +378,21 @@ struct QGLThreadContext {
};
extern QThreadStorage<QGLThreadContext *> qgl_context_storage;
-typedef QMultiHash<const QGLContext *, const QGLContext *> QGLSharingHash;
class QGLShareRegister
{
public:
QGLShareRegister() {}
~QGLShareRegister() { reg.clear(); }
- bool checkSharing(const QGLContext *context1, const QGLContext *context2, const QGLContext * skip=0) {
- if (context1 == context2)
- return true;
- QList<const QGLContext *> shares = reg.values(context1);
- for (int k=0; k<shares.size(); ++k) {
- const QGLContext *ctx = shares.at(k);
- if (ctx == skip) // avoid an indirect circular loop (infinite recursion)
- continue;
- if (ctx == context2)
- return true;
- if (checkSharing(ctx, context2, context1))
- return true;
- }
- return false;
- }
-
- void addShare(const QGLContext *context, const QGLContext *share) {
- reg.insert(context, share); // context sharing works both ways
- reg.insert(share, context);
- }
-
- void removeShare(const QGLContext *context) {
- QGLSharingHash::iterator it = reg.begin();
- while (it != reg.end()) {
- if (it.key() == context || it.value() == context)
- it = reg.erase(it);
- else
- ++it;
- }
- }
-
- void replaceShare(const QGLContext *oldContext, const QGLContext *newContext) {
- QGLSharingHash::iterator it = reg.begin();
- while (it != reg.end()) {
- if (it.key() == oldContext)
- reg.insert(newContext, it.value());
- else if (it.value() == oldContext)
- reg.insert(it.key(), newContext);
- ++it;
- }
- removeShare(oldContext);
- }
-
- QList<const QGLContext *> shares(const QGLContext *context) {
- return reg.values(context);
- }
-
+ bool checkSharing(const QGLContext *context1, const QGLContext *context2);
+ void addShare(const QGLContext *context, const QGLContext *share);
+ QList<const QGLContext *> shares(const QGLContext *context);
+ void removeShare(const QGLContext *context);
private:
- QGLSharingHash reg;
+ // Use a context's 'groupResources' pointer to uniquely identify a group.
+ typedef QList<const QGLContext *> ContextList;
+ typedef QHash<const QGLContextGroupResources *, ContextList> SharingHash;
+ SharingHash reg;
};
extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg();
@@ -464,6 +430,29 @@ inline GLenum qt_gl_preferredTextureTarget()
#endif
}
+// One resource per group of shared contexts.
+class QGLContextResource : public QObject
+{
+ Q_OBJECT
+public:
+ typedef void (*FreeFunc)(void *);
+ QGLContextResource(FreeFunc f, QObject *parent = 0);
+ ~QGLContextResource();
+ // Set resource 'value' for 'key' and all its shared contexts.
+ void insert(const QGLContext *key, void *value);
+ // Return resource for 'key' or a shared context.
+ void *value(const QGLContext *key);
+ // Free resource for 'key' and all its shared contexts.
+ void remove(const QGLContext *key);
+private slots:
+ // Remove entry 'key' from cache and delete resource if there are no shared contexts.
+ void aboutToDestroyContext(const QGLContext *key);
+private:
+ typedef QHash<const QGLContext *, void *> ResourceHash;
+ ResourceHash m_resources;
+ FreeFunc free;
+};
+
QT_END_NAMESPACE
#endif // QGL_P_H