summaryrefslogtreecommitdiffstats
path: root/src/gui/opengl
diff options
context:
space:
mode:
authorSamuel Rødal <samuel.rodal@nokia.com>2012-02-14 19:43:46 +0100
committerQt by Nokia <qt-info@nokia.com>2012-02-15 17:01:50 +0100
commitb36ece3ff4ee516eab8f0f34c8e7f54d2fcee311 (patch)
tree432b03015991a752012d781558020751708b12d6 /src/gui/opengl
parent0f0d8a5a8fecf545cdf58ab50d05253ffd20e90b (diff)
Added support for resetting QOpenGLFramebufferObject attachments.
As the documentation says, this can be useful to free or recreate attachments when needed. For example, it might be useful to free stencil and depth attachments to free up resources when not rendering to the framebuffer object. Change-Id: Ib267024fdd380a788c256eb8fb86e0f8832329e0 Reviewed-by: Kim M. Kalland <kim.kalland@nokia.com>
Diffstat (limited to 'src/gui/opengl')
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp103
-rw-r--r--src/gui/opengl/qopenglframebufferobject.h2
-rw-r--r--src/gui/opengl/qopenglframebufferobject_p.h4
3 files changed, 82 insertions, 27 deletions
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index 5e22554303..aac6ea0558 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -313,9 +313,8 @@ bool QOpenGLFramebufferObjectFormat::operator!=(const QOpenGLFramebufferObjectFo
return !(*this == other);
}
-bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus() const
+bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus(QOpenGLContext *ctx) const
{
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (!ctx)
return false; // Context no longer exists.
GLenum status = ctx->functions()->glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -402,8 +401,6 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
GLuint texture = 0;
GLuint color_buffer = 0;
- GLuint depth_buffer = 0;
- GLuint stencil_buffer = 0;
QT_CHECK_GLERROR();
// init texture
@@ -432,7 +429,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
target, texture, 0);
QT_CHECK_GLERROR();
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
glBindTexture(target, 0);
color_buffer = 0;
@@ -458,12 +455,57 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
GL_RENDERBUFFER, color_buffer);
QT_CHECK_GLERROR();
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (valid)
funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
}
+ format.setTextureTarget(target);
+ format.setSamples(int(samples));
+ format.setInternalTextureFormat(internal_format);
+ format.setMipmap(mipmap);
+
+ initAttachments(ctx, attachment);
+
+ funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo);
+ if (valid) {
+ fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
+ if (color_buffer)
+ color_buffer_guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
+ else
+ texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
+ } else {
+ if (color_buffer)
+ funcs.glDeleteRenderbuffers(1, &color_buffer);
+ else
+ glDeleteTextures(1, &texture);
+ funcs.glDeleteFramebuffers(1, &fbo);
+ }
+ QT_CHECK_GLERROR();
+}
+
+void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment)
+{
+ int samples = format.samples();
+
+ // free existing attachments
+ if (depth_buffer_guard) {
+ funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+ depth_buffer_guard->free();
+ }
+ if (stencil_buffer_guard) {
+ funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+ if (stencil_buffer_guard != depth_buffer_guard)
+ stencil_buffer_guard->free();
+ }
+
+ depth_buffer_guard = 0;
+ stencil_buffer_guard = 0;
+
+ GLuint depth_buffer = 0;
+ GLuint stencil_buffer = 0;
+
// In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a
// separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer
// might not be supported while separate buffers are, according to QTBUG-12861.
@@ -488,7 +530,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, stencil_buffer);
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (!valid) {
funcs.glDeleteRenderbuffers(1, &depth_buffer);
stencil_buffer = depth_buffer = 0;
@@ -529,7 +571,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
}
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depth_buffer);
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (!valid) {
funcs.glDeleteRenderbuffers(1, &depth_buffer);
depth_buffer = 0;
@@ -559,7 +601,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
}
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, stencil_buffer);
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (!valid) {
funcs.glDeleteRenderbuffers(1, &stencil_buffer);
stencil_buffer = 0;
@@ -567,7 +609,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
}
// The FBO might have become valid after removing the depth or stencil buffer.
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (depth_buffer && stencil_buffer) {
fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil;
@@ -577,13 +619,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
fbo_attachment = QOpenGLFramebufferObject::NoAttachment;
}
- funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo);
if (valid) {
- fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
- if (color_buffer)
- color_buffer_guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
- else
- texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
if (depth_buffer)
depth_buffer_guard = new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
if (stencil_buffer) {
@@ -593,23 +629,14 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
stencil_buffer_guard = new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
}
} else {
- if (color_buffer)
- funcs.glDeleteRenderbuffers(1, &color_buffer);
- else
- glDeleteTextures(1, &texture);
if (depth_buffer)
funcs.glDeleteRenderbuffers(1, &depth_buffer);
if (stencil_buffer && depth_buffer != stencil_buffer)
funcs.glDeleteRenderbuffers(1, &stencil_buffer);
- funcs.glDeleteFramebuffers(1, &fbo);
}
QT_CHECK_GLERROR();
- format.setTextureTarget(target);
- format.setSamples(int(samples));
format.setAttachment(fbo_attachment);
- format.setInternalTextureFormat(internal_format);
- format.setMipmap(mipmap);
}
/*!
@@ -861,7 +888,7 @@ bool QOpenGLFramebufferObject::bind()
qWarning("QOpenGLFramebufferObject::bind() called from incompatible context");
#endif
d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
- d->valid = d->checkFramebufferStatus();
+ d->valid = d->checkFramebufferStatus(current);
if (d->valid && current)
current->d_func()->current_fbo = d->fbo();
return d->valid;
@@ -1108,6 +1135,30 @@ QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObject::attachment() cons
}
/*!
+ Sets the attachments of the framebuffer object.
+
+ This can be used to free or reattach the depth and stencil buffer
+ attachments as needed.
+ */
+void QOpenGLFramebufferObject::setAttachment(QOpenGLFramebufferObject::Attachment attachment)
+{
+ Q_D(QOpenGLFramebufferObject);
+ if (attachment == d->fbo_attachment || !isValid())
+ return;
+ QOpenGLContext *current = QOpenGLContext::currentContext();
+ if (!current)
+ return;
+#ifdef QT_DEBUG
+ if (current->shareGroup() != d->fbo_guard->group())
+ qWarning("QOpenGLFramebufferObject::setAttachment() called from incompatible context");
+#endif
+ d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
+ d->initAttachments(current, attachment);
+ if (current->d_func()->current_fbo != d->fbo())
+ d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_func()->current_fbo);
+}
+
+/*!
Returns true if the framebuffer object is currently bound to a context,
otherwise false is returned.
*/
diff --git a/src/gui/opengl/qopenglframebufferobject.h b/src/gui/opengl/qopenglframebufferobject.h
index 0b2ead1cbb..63260f1940 100644
--- a/src/gui/opengl/qopenglframebufferobject.h
+++ b/src/gui/opengl/qopenglframebufferobject.h
@@ -101,6 +101,8 @@ public:
QImage toImage() const;
Attachment attachment() const;
+ void setAttachment(Attachment attachment);
+
GLuint handle() const;
static bool bindDefault();
diff --git a/src/gui/opengl/qopenglframebufferobject_p.h b/src/gui/opengl/qopenglframebufferobject_p.h
index 78d9d93ffe..23cab8f0af 100644
--- a/src/gui/opengl/qopenglframebufferobject_p.h
+++ b/src/gui/opengl/qopenglframebufferobject_p.h
@@ -120,7 +120,9 @@ public:
QOpenGLFramebufferObject::Attachment attachment,
GLenum internal_format, GLenum texture_target,
GLint samples = 0, bool mipmap = false);
- bool checkFramebufferStatus() const;
+ void initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment);
+
+ bool checkFramebufferStatus(QOpenGLContext *ctx) const;
QOpenGLSharedResourceGuard *fbo_guard;
QOpenGLSharedResourceGuard *texture_guard;
QOpenGLSharedResourceGuard *depth_buffer_guard;