summaryrefslogtreecommitdiffstats
path: root/src/opengl/qglshaderprogram.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl/qglshaderprogram.cpp')
-rw-r--r--src/opengl/qglshaderprogram.cpp307
1 files changed, 117 insertions, 190 deletions
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";