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>
This commit is contained in:
parent
0f0d8a5a8f
commit
b36ece3ff4
@ -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;
|
||||
@ -1107,6 +1134,30 @@ QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObject::attachment() cons
|
||||
return NoAttachment;
|
||||
}
|
||||
|
||||
/*!
|
||||
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.
|
||||
|
@ -101,6 +101,8 @@ public:
|
||||
QImage toImage() const;
|
||||
Attachment attachment() const;
|
||||
|
||||
void setAttachment(Attachment attachment);
|
||||
|
||||
GLuint handle() const;
|
||||
|
||||
static bool bindDefault();
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user