summaryrefslogtreecommitdiffstats
path: root/src/gui/opengl/qopenglframebufferobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/opengl/qopenglframebufferobject.cpp')
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp48
1 files changed, 37 insertions, 11 deletions
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index a6feda8732..231e475111 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -1119,6 +1119,14 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
Will try to return a premultiplied ARBG32 or RGB32 image. Since 5.2 it will fall back to
a premultiplied RGBA8888 or RGBx8888 image when reading to ARGB32 is not supported.
+
+ For multisampled framebuffer objects the samples are resolved using the
+ \c{GL_EXT_framebuffer_blit} extension. If the extension is not available, the contents
+ of the returned image is undefined.
+
+ For singlesampled framebuffers the contents is retrieved via \c glReadPixels. This is
+ a potentially expensive and inefficient operation. Therefore it is recommended that
+ this function is used as seldom as possible.
*/
QImage QOpenGLFramebufferObject::toImage() const
{
@@ -1126,6 +1134,19 @@ QImage QOpenGLFramebufferObject::toImage() const
if (!d->valid)
return QImage();
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (!ctx) {
+ qWarning("QOpenGLFramebufferObject::toImage() called without a current context");
+ return QImage();
+ }
+
+ GLuint prevFbo = 0;
+ ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
+
+ if (prevFbo != d->fbo())
+ const_cast<QOpenGLFramebufferObject *>(this)->bind();
+
+ QImage image;
// qt_gl_read_framebuffer doesn't work on a multisample FBO
if (format().samples() != 0) {
QOpenGLFramebufferObject temp(size(), QOpenGLFramebufferObjectFormat());
@@ -1133,15 +1154,13 @@ QImage QOpenGLFramebufferObject::toImage() const
QRect rect(QPoint(0, 0), size());
blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect);
- return temp.toImage();
+ image = temp.toImage();
+ } else {
+ image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
}
- bool wasBound = isBound();
- if (!wasBound)
- const_cast<QOpenGLFramebufferObject *>(this)->bind();
- QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
- if (!wasBound)
- const_cast<QOpenGLFramebufferObject *>(this)->release();
+ if (prevFbo != d->fbo())
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
return image;
}
@@ -1213,6 +1232,8 @@ QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObject::attachment() cons
This can be used to free or reattach the depth and stencil buffer
attachments as needed.
+
+ \note This function alters the current framebuffer binding.
*/
void QOpenGLFramebufferObject::setAttachment(QOpenGLFramebufferObject::Attachment attachment)
{
@@ -1296,6 +1317,9 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
If \a source or \a target is 0, the default framebuffer will be used
instead of a framebuffer object as source or target respectively.
+ This function will have no effect unless hasOpenGLFramebufferBlit() returns
+ true.
+
The \a buffers parameter should be a mask consisting of any combination of
\c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
\c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both
@@ -1312,10 +1336,7 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
have different sizes. The sizes must also be the same if any of the
framebuffer objects are multisample framebuffers.
- Note that the scissor test will restrict the blit area if enabled.
-
- This function will have no effect unless hasOpenGLFramebufferBlit() returns
- true.
+ \note The scissor test will restrict the blit area if enabled.
\sa hasOpenGLFramebufferBlit()
*/
@@ -1332,6 +1353,9 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
if (!extensions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit))
return;
+ GLuint prevFbo = 0;
+ ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
+
const int sx0 = sourceRect.left();
const int sx1 = sourceRect.left() + sourceRect.width();
const int sy0 = sourceRect.top();
@@ -1348,6 +1372,8 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1,
tx0, ty0, tx1, ty1,
buffers, filter);
+
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); // sets both READ and DRAW
}
QT_END_NAMESPACE