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:
parent
10742cf894
commit
48ca7f6220
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user