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);
GLuint texture = 0;
GLuint color_buffer = 0;
- GLuint depth_buffer = 0;
- GLuint stencil_buffer = 0;
QT_CHECK_GLERROR();
// init texture
target, texture, 0);
QT_CHECK_GLERROR();
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
glBindTexture(target, 0);
color_buffer = 0;
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.
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;
}
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;
}
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;
}
// 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;
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) {
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);
}
/*!
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;
}
/*!
+ 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.
*/