Provide optimised version of QOpenGLFramebufferObject::blitFramebuffer

Profiling shows that the call to glGetIntegerv() in this function that
queries for the currently bound framebuffer is very expensive. It's
the top hit on the CPU when profiling a Qt3D application using a
Scene3D Qt Quick 2 item. The reason it is so expensive is that this
call forces the OpenGL driver to propagate the OpenGL state through
all of the queued commands in order to answer the query. It may
also induce a pipeline stall depending upon the driver implementation.

As this function gets called on the hot path every frame whenever using
a Scene3D item and may also be called in plain Qt Quick when using
ShaderEffect items; the layer property of QQuickItem; or when updating
the Qt Quick glyph cache texture on Core profile contexts, it is very
much worthy of optimization.

This commit adds an overload of the blitFramebuffer() call that allows
the caller to provide a policy that can either:

* keep the existing behavior of restoring the previous framebuffer
  binding,
* restore the default framebuffer, or
* don't restore anything and let the caller be responsible for it.

This will allow consumers such as Qt Quick and Qt 3D to use the
optimised code path. The existing overloads of blitFramebuffer()
retain the current behavior by calling with the policy to restore the
previous framebuffer binding.

Upon making this change, the cost of blitFramebuffer() is massively
reduced. A follow up commit will optimize this further.

Change-Id: I417abb7da916ae5088f6817e4eff8ea02c8c5803
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
This commit is contained in:
Sean Harmer 2016-02-13 14:07:14 +00:00
parent 10742cf894
commit 48ca7f6220
2 changed files with 83 additions and 3 deletions

View File

@ -1630,6 +1630,29 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
}
/*!
\enum QOpenGLFramebufferObject::FramebufferRestorePolicy
\since 5.7
This enum type is used to configure the behavior related to restoring
framebuffer bindings when calling blitFramebuffer().
\value DontRestoreFramebufferBinding Do not restore the previous framebuffer binding.
The caller is responsible for tracking and setting
the framebuffer binding as needed.
\value RestoreFramebufferBindingToDefault After the blit operation, bind the default
framebuffer.
\value RestoreFrameBufferBinding Restore the previously bound framebuffer. This is
potentially expensive because of the need to
query the currently bound framebuffer.
\sa blitFramebuffer()
*/
/*!
\since 5.7
Blits from the \a sourceRect rectangle in the \a source framebuffer
object to the \a targetRect rectangle in the \a target framebuffer object.
@ -1661,6 +1684,13 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
drawColorAttachmentIndex specify the index of the color attachments in the
source and destination framebuffers.
The \a restorePolicy determines if the framebuffer that was bound prior to
calling this function should be restored, or if the default framebuffer
should be bound before returning, of if the caller is responsible for
tracking and setting the bound framebuffer. Restoring the previous
framebuffer can be relatively expensive due to the call to \c{glGetIntegerv}
which on some OpenGL drivers may imply a pipeline stall.
\sa hasOpenGLFramebufferBlit()
*/
void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
@ -1668,7 +1698,8 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
GLbitfield buffers,
GLenum filter,
int readColorAttachmentIndex,
int drawColorAttachmentIndex)
int drawColorAttachmentIndex,
QOpenGLFramebufferObject::FramebufferRestorePolicy restorePolicy)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (!ctx)
@ -1679,7 +1710,8 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
return;
GLuint prevFbo = 0;
ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
if (restorePolicy == RestoreFrameBufferBinding)
ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
const int sx0 = sourceRect.left();
const int sx1 = sourceRect.left() + sourceRect.width();
@ -1711,7 +1743,41 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
if (extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets))
extensions.glReadBuffer(GL_COLOR_ATTACHMENT0);
ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); // sets both READ and DRAW
switch (restorePolicy) {
case RestoreFrameBufferBinding:
ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); // sets both READ and DRAW
break;
case RestoreFramebufferBindingToDefault:
ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); // sets both READ and DRAW
break;
case DontRestoreFramebufferBinding:
break;
}
}
/*!
\overload
Convenience overload to blit between two framebuffer objects and
to restore the previous framebuffer binding. Equivalent to calling
blitFramebuffer(target, targetRect, source, sourceRect, buffers, filter,
readColorAttachmentIndex, drawColorAttachmentIndex,
RestoreFrameBufferBinding).
*/
void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
QOpenGLFramebufferObject *source, const QRect &sourceRect,
GLbitfield buffers,
GLenum filter,
int readColorAttachmentIndex,
int drawColorAttachmentIndex)
{
blitFramebuffer(target, targetRect, source, sourceRect,
buffers, filter,
readColorAttachmentIndex,
drawColorAttachmentIndex,
RestoreFrameBufferBinding);
}
QT_END_NAMESPACE

View File

@ -114,6 +114,20 @@ public:
static bool hasOpenGLFramebufferObjects();
static bool hasOpenGLFramebufferBlit();
enum FramebufferRestorePolicy {
DontRestoreFramebufferBinding,
RestoreFramebufferBindingToDefault,
RestoreFrameBufferBinding
};
static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
QOpenGLFramebufferObject *source, const QRect &sourceRect,
GLbitfield buffers,
GLenum filter,
int readColorAttachmentIndex,
int drawColorAttachmentIndex,
FramebufferRestorePolicy restorePolicy);
static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
QOpenGLFramebufferObject *source, const QRect &sourceRect,
GLbitfield buffers,