diff options
author | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-09-09 06:23:54 (GMT) |
---|---|---|
committer | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-09-09 06:23:54 (GMT) |
commit | 6eb6920d134ee6a0cc0f27d63d65003a3d9c1fee (patch) | |
tree | e4abaa818134c282dc37e62a241d9b7b89b5fb0b /src | |
parent | 39bcbc8df52eb5df5f7e39dc4265c8a77d3881be (diff) | |
download | Qt-6eb6920d134ee6a0cc0f27d63d65003a3d9c1fee.zip Qt-6eb6920d134ee6a0cc0f27d63d65003a3d9c1fee.tar.gz Qt-6eb6920d134ee6a0cc0f27d63d65003a3d9c1fee.tar.bz2 |
Clean up shader programs properly
QGLShader and QGLShaderProgram used to delete the GL object id
in the wrong context. But fixing this means we must keep track of
when contexts are destroyed so that we don't try to access a
context from a shader if it goes away. We also need to transfer
ownership from one context to another when they are shared.
This change introduces QGLSharedResourceGuard, which keeps track
of a context and a GL object identifier. When the context goes
away, ownership is passed to a shared context. When there are
no more shared contexts, the identifier automatically zeroes.
Reviewed-by: trustme
Diffstat (limited to 'src')
-rw-r--r-- | src/opengl/qgl.cpp | 29 | ||||
-rw-r--r-- | src/opengl/qgl.h | 1 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 86 | ||||
-rw-r--r-- | src/opengl/qglshaderprogram.cpp | 307 |
4 files changed, 232 insertions, 191 deletions
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index a0b2d3a..9618e5c 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1360,6 +1360,9 @@ bool operator!=(const QGLFormat& a, const QGLFormat& b) *****************************************************************************/ QGLContextPrivate::~QGLContextPrivate() { + if (!reference->deref()) + delete reference; + if (!group->m_refs.deref()) { Q_ASSERT(group->context() == q_ptr); delete group; @@ -5007,4 +5010,30 @@ void QGLContextResource::removeOne(const QGLContext *key) m_resources.erase(it); } +QGLContextReference::QGLContextReference(const QGLContext *ctx) + : m_ref(1), m_ctx(ctx) +{ + connect(QGLSignalProxy::instance(), + SIGNAL(aboutToDestroyContext(const QGLContext *)), + this, SLOT(aboutToDestroyContext(const QGLContext *))); +} + +void QGLContextReference::aboutToDestroyContext(const QGLContext *ctx) +{ + // Bail out if our context is not being destroyed. + if (ctx != m_ctx || !m_ctx) + return; + + // Find some other context that this one is shared with to take over. + QList<const QGLContext *> shares = qgl_share_reg()->shares(m_ctx); + shares.removeAll(m_ctx); + if (!shares.isEmpty()) { + m_ctx = shares[0]; + return; + } + + // No more contexts sharing with this one, so the reference is now invalid. + m_ctx = 0; +} + QT_END_NAMESPACE diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 151c7c4..eba027f 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -396,6 +396,7 @@ private: friend class QGLPixmapFilterBase; friend class QGLTextureGlyphCache; friend class QGLShareRegister; + friend class QGLSharedResourceGuard; 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 b10d5da..410dfc1 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -237,13 +237,37 @@ private: friend class QGLContextPrivate; }; +// Reference to a QGLContext which automatically switches to another +// shared context when the main one is destroyed. If there is no +// shared context to switch to, the context pointer is set to null. +// Note: should be merged into QGLContextGroup at some point. +class QGLContextReference : public QObject +{ + Q_OBJECT +public: + QGLContextReference(const QGLContext *ctx); + ~QGLContextReference() {} + + const QGLContext *context() const { return m_ctx; } + + void ref() { m_ref.ref(); } + bool deref() { return m_ref.deref(); } + +private slots: + void aboutToDestroyContext(const QGLContext *ctx); + +private: + QAtomicInt m_ref; + const QGLContext *m_ctx; +}; + class QGLTexture; class QGLContextPrivate { Q_DECLARE_PUBLIC(QGLContext) public: - explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {group = new QGLContextGroup(context);} + explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {reference = new QGLContextReference(context); group = new QGLContextGroup(context);} ~QGLContextPrivate(); QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options); @@ -305,6 +329,7 @@ public: QGLContext *q_ptr; QGLFormat::OpenGLVersionFlags version_flags; + QGLContextReference *reference; QGLContextGroup *group; GLint max_texture_size; @@ -554,6 +579,65 @@ private: QGLContext *m_ctx; }; +// Put a guard around a GL object identifier and its context. +// When the context goes away, a shared context will be used +// in its place. If there are no more shared contexts, then +// the identifier is returned as zero - it is assumed that the +// context destruction cleaned up the identifier in this case. +class Q_OPENGL_EXPORT QGLSharedResourceGuard +{ +public: + QGLSharedResourceGuard(const QGLContext *context) + : m_ctxref(0), m_id(0) + { + setContext(context); + } + QGLSharedResourceGuard(const QGLContext *context, GLuint id) + : m_ctxref(0), m_id(id) + { + setContext(context); + } + ~QGLSharedResourceGuard() + { + if (m_ctxref && !m_ctxref->deref()) + delete m_ctxref; + } + + const QGLContext *context() const + { + return m_ctxref ? m_ctxref->context() : 0; + } + + void setContext(const QGLContext *context) + { + if (m_ctxref && !m_ctxref->deref()) + delete m_ctxref; + if (context) { + m_ctxref = context->d_ptr->reference; + m_ctxref->ref(); + } else { + m_ctxref = 0; + } + } + + GLuint id() const + { + if (m_ctxref && m_ctxref->context()) + return m_id; + else + return 0; + } + + void setId(GLuint id) + { + m_id = id; + } + +private: + QGLContextReference *m_ctxref; + GLuint m_id; +}; + QT_END_NAMESPACE #endif // QGL_P_H diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index bcc6c61..a43088c 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -246,18 +246,11 @@ QT_BEGIN_NAMESPACE #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 #endif -inline bool qt_check_sharing_with_current_context(QGLContextGroup *group) -{ - const QGLContext *context = QGLContext::currentContext(); - return context && QGLContextPrivate::contextGroup(context) == group; -} - class QGLShaderPrivate { public: - QGLShaderPrivate(QGLShader::ShaderType type) - : ctx(0) - , shader(0) + QGLShaderPrivate(const QGLContext *context, QGLShader::ShaderType type) + : shaderGuard(context) , shaderType(type) , compiled(false) , isPartial((type & QGLShader::PartialShader) != 0) @@ -265,8 +258,7 @@ public: { } - QGLContextGroup *ctx; - GLuint shader; + QGLSharedResourceGuard shaderGuard; QGLShader::ShaderType shaderType; bool compiled; bool isPartial; @@ -274,20 +266,22 @@ public: QString log; QByteArray partialSource; - bool create(const QGLContext *context); + bool create(); bool compile(QGLShader *q); + void deleteShader(); }; -bool QGLShaderPrivate::create(const QGLContext *context) +#define ctx shaderGuard.context() + +bool QGLShaderPrivate::create() { - if (!context) - context = QGLContext::currentContext(); + const QGLContext *context = shaderGuard.context(); if (!context) return false; - ctx = QGLContextPrivate::contextGroup(context); if (isPartial) return true; if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) { + GLuint shader; if (shaderType == QGLShader::VertexShader) shader = glCreateShader(GL_VERTEX_SHADER); else @@ -296,6 +290,7 @@ bool QGLShaderPrivate::create(const QGLContext *context) qWarning() << "QGLShader: could not create shader"; return false; } + shaderGuard.setId(shader); return true; } else { return false; @@ -309,6 +304,7 @@ bool QGLShaderPrivate::compile(QGLShader *q) compiled = true; return true; } + GLuint shader = shaderGuard.id(); if (!shader) return false; glCompileShader(shader); @@ -332,6 +328,17 @@ bool QGLShaderPrivate::compile(QGLShader *q) return compiled; } +void QGLShaderPrivate::deleteShader() +{ + if (shaderGuard.id()) { + glDeleteShader(shaderGuard.id()); + shaderGuard.setId(0); + } +} + +#undef ctx +#define ctx d->shaderGuard.context() + /*! Constructs a new QGLShader object of the specified \a type and attaches it to \a parent. If shader programs are not supported, @@ -347,8 +354,8 @@ bool QGLShaderPrivate::compile(QGLShader *q) QGLShader::QGLShader(QGLShader::ShaderType type, QObject *parent) : QObject(parent) { - d = new QGLShaderPrivate(type); - d->create(QGLContext::currentContext()); + d = new QGLShaderPrivate(QGLContext::currentContext(), type); + d->create(); } /*! @@ -364,14 +371,9 @@ QGLShader::QGLShader (const QString& fileName, QGLShader::ShaderType type, QObject *parent) : QObject(parent) { - d = new QGLShaderPrivate(type); - if (d->create(QGLContext::currentContext()) && !compileFile(fileName)) { - if (d->shader) { - QGLContextGroup *ctx = d->ctx; - glDeleteShader(d->shader); - } - d->shader = 0; - } + d = new QGLShaderPrivate(QGLContext::currentContext(), type); + if (d->create() && !compileFile(fileName)) + d->deleteShader(); } /*! @@ -389,14 +391,16 @@ QGLShader::QGLShader QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent) : QObject(parent) { - d = new QGLShaderPrivate(type); + if (!context) + context = QGLContext::currentContext(); + d = new QGLShaderPrivate(context, type); #ifndef QT_NO_DEBUG if (context && !qgl_share_reg()->checkSharing(context, QGLContext::currentContext())) { qWarning("QGLShader::QGLShader: \'context\' must be the currect context or sharing with it."); return; } #endif - d->create(context); + d->create(); } /*! @@ -412,20 +416,17 @@ QGLShader::QGLShader (const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent) : QObject(parent) { - d = new QGLShaderPrivate(type); + if (!context) + context = QGLContext::currentContext(); + d = new QGLShaderPrivate(context, type); #ifndef QT_NO_DEBUG if (context && !qgl_share_reg()->checkSharing(context, QGLContext::currentContext())) { qWarning("QGLShader::QGLShader: \'context\' must be currect context or sharing with it."); return; } #endif - if (d->create(context) && !compileFile(fileName)) { - if (d->shader) { - QGLContextGroup *ctx = d->ctx; - glDeleteShader(d->shader); - } - d->shader = 0; - } + if (d->create() && !compileFile(fileName)) + d->deleteShader(); } /*! @@ -435,14 +436,9 @@ QGLShader::QGLShader */ QGLShader::~QGLShader() { - if (d->shader) { - QGLContextGroup *ctx = d->ctx; -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) - qWarning("QGLShader::~QGLShader: Shader is not associated with current context."); - else -#endif - glDeleteShader(d->shader); + if (d->shaderGuard.id()) { + QGLShareContextScope scope(d->shaderGuard.context()); + glDeleteShader(d->shaderGuard.id()); } delete d; } @@ -489,17 +485,11 @@ static const char redefineHighp[] = */ bool QGLShader::compile(const char *source) { -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(d->ctx)) { - qWarning("QGLShader::compile: Shader is not associated with current context."); - return false; - } -#endif if (d->isPartial) { d->partialSource = QByteArray(source); d->hasPartialSource = true; return d->compile(this); - } else if (d->shader) { + } else if (d->shaderGuard.id()) { QVarLengthArray<const char *> src; int headerLen = 0; while (source && source[headerLen] == '#') { @@ -529,8 +519,7 @@ bool QGLShader::compile(const char *source) src.append(redefineHighp); #endif src.append(source + headerLen); - QGLContextGroup *ctx = d->ctx; - glShaderSource(d->shader, src.size(), src.data(), 0); + glShaderSource(d->shaderGuard.id(), src.size(), src.data(), 0); return d->compile(this); } else { return false; @@ -612,22 +601,15 @@ bool QGLShader::compileFile(const QString& fileName) */ bool QGLShader::setShaderBinary(GLenum format, const void *binary, int length) { - QGLContextGroup *ctx = d->ctx; -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) { - qWarning("QGLShader::setShaderBinary: Shader is not associated with current context."); - return false; - } -#endif - #if !defined(QT_OPENGL_ES_2) if (!glShaderBinary) return false; #endif - if (d->isPartial || !d->shader) + GLuint shader = d->shaderGuard.id(); + if (d->isPartial || !shader) return false; glGetError(); // Clear error state. - glShaderBinary(1, &(d->shader), format, binary, length); + glShaderBinary(1, &shader, format, binary, length); d->compiled = (glGetError() == GL_NO_ERROR); return d->compiled; } @@ -652,26 +634,18 @@ bool QGLShader::setShaderBinary(GLenum format, const void *binary, int length) bool QGLShader::setShaderBinary (QGLShader& otherShader, GLenum format, const void *binary, int length) { - QGLContextGroup *ctx = d->ctx; -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) { - qWarning("QGLShader::setShaderBinary: Shader is not associated with current context."); - return false; - } -#endif - #if !defined(QT_OPENGL_ES_2) if (!glShaderBinary) return false; #endif - if (d->isPartial || !d->shader) + if (d->isPartial || !d->shaderGuard.id()) return false; - if (otherShader.d->isPartial || !otherShader.d->shader) + if (otherShader.d->isPartial || !otherShader.d->shaderGuard.id()) return false; glGetError(); // Clear error state. GLuint shaders[2]; - shaders[0] = d->shader; - shaders[1] = otherShader.d->shader; + shaders[0] = d->shaderGuard.id(); + shaders[1] = otherShader.d->shaderGuard.id(); glShaderBinary(2, shaders, format, binary, length); d->compiled = (glGetError() == GL_NO_ERROR); otherShader.d->compiled = d->compiled; @@ -706,25 +680,18 @@ QList<GLenum> QGLShader::shaderBinaryFormats() */ QByteArray QGLShader::sourceCode() const { -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(d->ctx)) { - qWarning("QGLShader::sourceCode: Shader is not associated with current context."); - return false; - } -#endif - if (d->isPartial) return d->partialSource; - if (!d->shader) + GLuint shader = d->shaderGuard.id(); + if (!shader) return QByteArray(); GLint size = 0; - QGLContextGroup *ctx = d->ctx; - glGetShaderiv(d->shader, GL_SHADER_SOURCE_LENGTH, &size); + glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size); if (size <= 0) return QByteArray(); GLint len = 0; char *source = new char [size]; - glGetShaderSource(d->shader, size, &len, source); + glGetShaderSource(shader, size, &len, source); QByteArray src(source); delete [] source; return src; @@ -761,15 +728,17 @@ QString QGLShader::log() const */ GLuint QGLShader::shaderId() const { - return d->shader; + return d->shaderGuard.id(); } +#undef ctx +#define ctx programGuard.context() + class QGLShaderProgramPrivate { public: QGLShaderProgramPrivate(const QGLContext *context) - : ctx(context ? QGLContextPrivate::contextGroup(context) : 0) - , program(0) + : programGuard(context) , linked(false) , inited(false) , hasPartialShaders(false) @@ -780,8 +749,7 @@ public: } ~QGLShaderProgramPrivate(); - QGLContextGroup *ctx; - GLuint program; + QGLSharedResourceGuard programGuard; bool linked; bool inited; bool hasPartialShaders; @@ -795,16 +763,14 @@ public: QGLShaderProgramPrivate::~QGLShaderProgramPrivate() { - if (program) { -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) - qWarning("QGLShaderProgram: Shader program is not associated with current context."); - else -#endif - glDeleteProgram(program); + if (programGuard.id()) { + QGLShareContextScope scope(programGuard.context()); + glDeleteProgram(programGuard.id()); } } +#undef ctx +#define ctx d->programGuard.context() /*! Constructs a new shader program and attaches it to \a parent. @@ -844,27 +810,23 @@ QGLShaderProgram::~QGLShaderProgram() bool QGLShaderProgram::init() { - if (d->program || d->inited) + if (d->programGuard.id() || d->inited) return true; d->inited = true; - const QGLContext *context = QGLContext::currentContext(); + const QGLContext *context = d->programGuard.context(); + if (!context) { + context = QGLContext::currentContext(); + d->programGuard.setContext(context); + } if (!context) return false; - if (!d->ctx) - d->ctx = QGLContextPrivate::contextGroup(context); -#ifndef QT_NO_DEBUG - else if (!qt_check_sharing_with_current_context(d->ctx)) { - qWarning("QGLShaderProgram: Shader program is not associated with current context."); - return false; - } -#endif if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) { - QGLContextGroup *ctx = d->ctx; - d->program = glCreateProgram(); - if (!(d->program)) { + GLuint program = glCreateProgram(); + if (!program) { qWarning() << "QGLShaderProgram: could not create shader program"; return false; } + d->programGuard.setId(program); return true; } else { qWarning() << "QGLShaderProgram: shader programs are not supported"; @@ -889,24 +851,18 @@ bool QGLShaderProgram::addShader(QGLShader *shader) return false; if (d->shaders.contains(shader)) return true; // Already added to this shader program. - if (d->program && shader) { -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(d->ctx)) { - qWarning("QGLShaderProgram::addShader: Program is not associated with current context."); - return false; - } -#endif - if (shader->d->ctx != d->ctx) { + if (d->programGuard.id() && shader) { + if (!qgl_share_reg()->checkSharing(shader->d->shaderGuard.context(), + d->programGuard.context())) { qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context."); return false; } if (!shader->d->compiled) return false; if (!shader->d->isPartial) { - if (!shader->d->shader) + if (!shader->d->shaderGuard.id()) return false; - QGLContextGroup *ctx = d->ctx; - glAttachShader(d->program, shader->d->shader); + glAttachShader(d->programGuard.id(), shader->d->shaderGuard.id()); } else { d->hasPartialShaders = true; } @@ -1017,14 +973,9 @@ bool QGLShaderProgram::addShaderFromFile */ void QGLShaderProgram::removeShader(QGLShader *shader) { - if (d->program && shader && shader->d->shader) { - QGLContextGroup *ctx = d->ctx; -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) - qWarning("QGLShaderProgram::removeShader: Program is not associated with current context."); - else -#endif - glDetachShader(d->program, shader->d->shader); + if (d->programGuard.id() && shader && shader->d->shaderGuard.id()) { + QGLShareContextScope scope(d->programGuard.context()); + glDetachShader(d->programGuard.id(), shader->d->shaderGuard.id()); } d->linked = false; // Program needs to be relinked. if (shader) { @@ -1056,15 +1007,9 @@ QList<QGLShader *> QGLShaderProgram::shaders() const void QGLShaderProgram::removeAllShaders() { d->removingShaders = true; - QGLContextGroup *ctx = d->ctx; -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) - qWarning("QGLShaderProgram::removeAllShaders: Program is not associated with current context."); - else -#endif foreach (QGLShader *shader, d->shaders) { - if (d->program && shader && shader->d->shader) - glDetachShader(d->program, shader->d->shader); + if (d->programGuard.id() && shader && shader->d->shaderGuard.id()) + glDetachShader(d->programGuard.id(), shader->d->shaderGuard.id()); } foreach (QGLShader *shader, d->anonShaders) { // Delete shader objects that were created anonymously. @@ -1113,22 +1058,17 @@ QByteArray QGLShaderProgram::programBinary(int *format) const if (!isLinked()) return QByteArray(); - QGLContextGroup *ctx = d->ctx; -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) - qWarning("QGLShaderProgram::programBinary: Program is not associated with current context."); -#endif - // Get the length of the binary data, bailing out if there is none. GLint length = 0; - glGetProgramiv(d->program, GL_PROGRAM_BINARY_LENGTH_OES, &length); + GLuint program = d->programGuard.id(); + glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &length); if (length <= 0) return QByteArray(); // Retrieve the binary data. QByteArray binary(length, 0); GLenum binaryFormat; - glGetProgramBinaryOES(d->program, length, 0, &binaryFormat, binary.data()); + glGetProgramBinaryOES(program, length, 0, &binaryFormat, binary.data()); if (format) *format = (int)binaryFormat; return binary; @@ -1149,25 +1089,22 @@ QByteArray QGLShaderProgram::programBinary(int *format) const bool QGLShaderProgram::setProgramBinary(int format, const QByteArray& binary) { #if defined(QT_OPENGL_ES_2) - QGLContextGroup *ctx = d->ctx; -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) - qWarning("QGLShaderProgram::setProgramBinary: Program is not associated with current context."); -#endif - // Load the binary and check that it was linked correctly. - glProgramBinaryOES(d->program, (GLenum)format, + GLuint program = d->programGuard.id(); + if (!program) + return false; + glProgramBinaryOES(program, (GLenum)format, binary.constData(), binary.size()); GLint value = 0; - glGetProgramiv(d->program, GL_LINK_STATUS, &value); + glGetProgramiv(program, GL_LINK_STATUS, &value); d->linked = (value != 0); value = 0; - glGetProgramiv(d->program, GL_INFO_LOG_LENGTH, &value); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value); d->log = QString(); if (value > 1) { char *logbuf = new char [value]; GLint len; - glGetProgramInfoLog(d->program, value, &len, logbuf); + glGetProgramInfoLog(program, value, &len, logbuf); d->log = QString::fromLatin1(logbuf); QString name = objectName(); if (name.isEmpty()) @@ -1222,16 +1159,9 @@ QList<int> QGLShaderProgram::programBinaryFormats() */ bool QGLShaderProgram::link() { - if (!d->program) - return false; - QGLContextGroup *ctx = d->ctx; -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) { - qWarning("QGLShaderProgram::link: Program is not associated with current context."); + GLuint program = d->programGuard.id(); + if (!program) return false; - } -#endif - if (d->hasPartialShaders) { // Compile the partial vertex and fragment shaders. QByteArray vertexSource; @@ -1244,7 +1174,7 @@ bool QGLShaderProgram::link() } if (vertexSource.isEmpty()) { if (d->vertexShader) { - glDetachShader(d->program, d->vertexShader->d->shader); + glDetachShader(program, d->vertexShader->d->shaderGuard.id()); delete d->vertexShader; d->vertexShader = 0; } @@ -1257,11 +1187,11 @@ bool QGLShaderProgram::link() d->log = d->vertexShader->log(); return false; } - glAttachShader(d->program, d->vertexShader->d->shader); + glAttachShader(program, d->vertexShader->d->shaderGuard.id()); } if (fragmentSource.isEmpty()) { if (d->fragmentShader) { - glDetachShader(d->program, d->fragmentShader->d->shader); + glDetachShader(program, d->fragmentShader->d->shaderGuard.id()); delete d->fragmentShader; d->fragmentShader = 0; } @@ -1274,20 +1204,20 @@ bool QGLShaderProgram::link() d->log = d->fragmentShader->log(); return false; } - glAttachShader(d->program, d->fragmentShader->d->shader); + glAttachShader(program, d->fragmentShader->d->shaderGuard.id()); } } - glLinkProgram(d->program); + glLinkProgram(program); GLint value = 0; - glGetProgramiv(d->program, GL_LINK_STATUS, &value); + glGetProgramiv(program, GL_LINK_STATUS, &value); d->linked = (value != 0); value = 0; - glGetProgramiv(d->program, GL_INFO_LOG_LENGTH, &value); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value); d->log = QString(); if (value > 1) { char *logbuf = new char [value]; GLint len; - glGetProgramInfoLog(d->program, value, &len, logbuf); + glGetProgramInfoLog(program, value, &len, logbuf); d->log = QString::fromLatin1(logbuf); QString name = objectName(); if (name.isEmpty()) @@ -1330,21 +1260,18 @@ QString QGLShaderProgram::log() const */ bool QGLShaderProgram::enable() { - if (!d->program) + GLuint program = d->programGuard.id(); + if (!program) return false; if (!d->linked && !link()) return false; - QGLContextGroup *ctx = d->ctx; -#ifndef QT_NO_DEBUG - if (!qt_check_sharing_with_current_context(ctx)) { - qWarning("QGLShaderProgram::enable: Program is not associated with current context."); - return false; - } -#endif - glUseProgram(d->program); + glUseProgram(program); return true; } +#undef ctx +#define ctx QGLContext::currentContext() + /*! Disables the active shader program in the current QGLContext. This is equivalent to calling \c{glUseProgram(0)}. @@ -1353,7 +1280,6 @@ bool QGLShaderProgram::enable() */ void QGLShaderProgram::disable() { - const QGLContext *ctx = QGLContext::currentContext(); #if defined(QT_OPENGL_ES_2) glUseProgram(0); #else @@ -1362,7 +1288,8 @@ void QGLShaderProgram::disable() #endif } -#define ctx d->ctx +#undef ctx +#define ctx d->programGuard.context() /*! Returns the OpenGL identifier associated with this shader program. @@ -1371,7 +1298,7 @@ void QGLShaderProgram::disable() */ GLuint QGLShaderProgram::programId() const { - return d->program; + return d->programGuard.id(); } /*! @@ -1384,7 +1311,7 @@ GLuint QGLShaderProgram::programId() const */ void QGLShaderProgram::bindAttributeLocation(const char *name, int location) { - glBindAttribLocation(d->program, location, name); + glBindAttribLocation(d->programGuard.id(), location, name); } /*! @@ -1399,7 +1326,7 @@ void QGLShaderProgram::bindAttributeLocation(const char *name, int location) */ void QGLShaderProgram::bindAttributeLocation(const QByteArray& name, int location) { - glBindAttribLocation(d->program, location, name.constData()); + glBindAttribLocation(d->programGuard.id(), location, name.constData()); } /*! @@ -1414,7 +1341,7 @@ void QGLShaderProgram::bindAttributeLocation(const QByteArray& name, int locatio */ void QGLShaderProgram::bindAttributeLocation(const QString& name, int location) { - glBindAttribLocation(d->program, location, name.toLatin1().constData()); + glBindAttribLocation(d->programGuard.id(), location, name.toLatin1().constData()); } /*! @@ -1427,7 +1354,7 @@ void QGLShaderProgram::bindAttributeLocation(const QString& name, int location) int QGLShaderProgram::attributeLocation(const char *name) const { if (d->linked) { - return glGetAttribLocation(d->program, name); + return glGetAttribLocation(d->programGuard.id(), name); } else { qWarning() << "QGLShaderProgram::attributeLocation(" << name << "): shader program is not linked"; @@ -1887,7 +1814,7 @@ void QGLShaderProgram::disableAttributeArray(const char *name) int QGLShaderProgram::uniformLocation(const char *name) const { if (d->linked) { - return glGetUniformLocation(d->program, name); + return glGetUniformLocation(d->programGuard.id(), name); } else { qWarning() << "QGLShaderProgram::uniformLocation(" << name << "): shader program is not linked"; |