summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp136
-rw-r--r--src/gui/opengl/qopenglframebufferobject.h1
-rw-r--r--src/gui/opengl/qopenglframebufferobject_p.h1
3 files changed, 97 insertions, 41 deletions
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index c06ba40b47..d5de8b009a 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -446,42 +446,12 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
funcs.glGenFramebuffers(1, &fbo);
funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo);
- GLuint texture = 0;
GLuint color_buffer = 0;
QT_CHECK_GLERROR();
// init texture
if (samples == 0) {
- glGenTextures(1, &texture);
- glBindTexture(target, texture);
-
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- if (mipmap) {
- int width = size.width();
- int height = size.height();
- int level = 0;
- while (width > 1 || height > 1) {
- width = qMax(1, width >> 1);
- height = qMax(1, height >> 1);
- ++level;
- glTexImage2D(target, level, internal_format, width, height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- }
- }
- funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- target, texture, 0);
-
- QT_CHECK_GLERROR();
- valid = checkFramebufferStatus(ctx);
- glBindTexture(target, 0);
-
- color_buffer = 0;
+ initTexture(texture_target, internal_format, size, mipmap);
} else {
mipmap = false;
funcs.glGenRenderbuffers(1, &color_buffer);
@@ -492,8 +462,10 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
QT_CHECK_GLERROR();
valid = checkFramebufferStatus(ctx);
- if (valid)
+ if (valid) {
funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
+ color_buffer_guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
+ }
}
format.setTextureTarget(target);
@@ -506,20 +478,59 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
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);
+ if (color_buffer_guard) {
+ color_buffer_guard->free();
+ color_buffer_guard = 0;
+ } else if (texture_guard) {
+ texture_guard->free();
+ texture_guard = 0;
+ }
funcs.glDeleteFramebuffers(1, &fbo);
}
QT_CHECK_GLERROR();
}
+void QOpenGLFramebufferObjectPrivate::initTexture(GLenum target, GLenum internal_format,
+ const QSize &size, bool mipmap)
+{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ GLuint texture = 0;
+
+ glGenTextures(1, &texture);
+ glBindTexture(target, texture);
+
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ if (mipmap) {
+ int width = size.width();
+ int height = size.height();
+ int level = 0;
+ while (width > 1 || height > 1) {
+ width = qMax(1, width >> 1);
+ height = qMax(1, height >> 1);
+ ++level;
+ glTexImage2D(target, level, internal_format, width, height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ }
+ }
+ funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ target, texture, 0);
+
+ QT_CHECK_GLERROR();
+ glBindTexture(target, 0);
+ valid = checkFramebufferStatus(ctx);
+ if (valid)
+ texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
+ else
+ glDeleteTextures(1, &texture);
+}
+
void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment)
{
int samples = format.samples();
@@ -905,6 +916,10 @@ bool QOpenGLFramebufferObject::isValid() const
framebuffer to this framebuffer object.
Returns \c true upon success, false otherwise.
+ \note If takeTexture() was called, a new texture is created and associated
+ with the framebuffer object. This is potentially expensive and changes the
+ context state (the currently bound texture).
+
\sa release()
*/
bool QOpenGLFramebufferObject::bind()
@@ -920,7 +935,10 @@ bool QOpenGLFramebufferObject::bind()
qWarning("QOpenGLFramebufferObject::bind() called from incompatible context");
#endif
d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
- d->valid = d->checkFramebufferStatus(current);
+ if (d->texture_guard || d->format.samples() != 0)
+ d->valid = d->checkFramebufferStatus(current);
+ else
+ d->initTexture(d->format.textureTarget(), d->format.internalTextureFormat(), d->size, d->format.mipmap());
if (d->valid && current)
current->d_func()->current_fbo = d->fbo();
return d->valid;
@@ -967,6 +985,8 @@ bool QOpenGLFramebufferObject::release()
If a multisample framebuffer object is used then the value returned
from this function will be invalid.
+
+ \sa takeTexture()
*/
GLuint QOpenGLFramebufferObject::texture() const
{
@@ -975,6 +995,40 @@ GLuint QOpenGLFramebufferObject::texture() const
}
/*!
+ \fn GLuint QOpenGLFramebufferObject::takeTexture()
+
+ Returns the texture id for the texture attached to this framebuffer
+ object. The ownership of the texture is transferred to the caller.
+
+ If the framebuffer object is currently bound, an implicit release()
+ will be done. During the next call to bind() a new texture will be
+ created.
+
+ If a multisample framebuffer object is used, then there is no
+ texture and the return value from this function will be invalid.
+ Similarly, incomplete framebuffer objects will also return 0.
+
+ \since 5.3
+
+ \sa texture(), bind(), release()
+ */
+GLuint QOpenGLFramebufferObject::takeTexture()
+{
+ Q_D(QOpenGLFramebufferObject);
+ GLuint id = 0;
+ if (isValid() && d->texture_guard) {
+ QOpenGLContext *current = QOpenGLContext::currentContext();
+ if (current && current->shareGroup() == d->fbo_guard->group() && current->d_func()->current_fbo == d->fbo())
+ release();
+ id = d->texture_guard->id();
+ // Do not call free() on texture_guard, just null it out.
+ // This way the texture will not be deleted when the guard is destroyed.
+ d->texture_guard = 0;
+ }
+ return id;
+}
+
+/*!
\fn QSize QOpenGLFramebufferObject::size() const
Returns the size of the texture attached to this framebuffer
diff --git a/src/gui/opengl/qopenglframebufferobject.h b/src/gui/opengl/qopenglframebufferobject.h
index 215d3701ca..a431618f6d 100644
--- a/src/gui/opengl/qopenglframebufferobject.h
+++ b/src/gui/opengl/qopenglframebufferobject.h
@@ -97,6 +97,7 @@ public:
int height() const { return size().height(); }
GLuint texture() const;
+ GLuint takeTexture();
QSize size() const;
QImage toImage() const;
Attachment attachment() const;
diff --git a/src/gui/opengl/qopenglframebufferobject_p.h b/src/gui/opengl/qopenglframebufferobject_p.h
index c8c69c4b3e..1c7d2e1e5d 100644
--- a/src/gui/opengl/qopenglframebufferobject_p.h
+++ b/src/gui/opengl/qopenglframebufferobject_p.h
@@ -116,6 +116,7 @@ public:
QOpenGLFramebufferObject::Attachment attachment,
GLenum internal_format, GLenum texture_target,
GLint samples = 0, bool mipmap = false);
+ void initTexture(GLenum target, GLenum internal_format, const QSize &size, bool mipmap);
void initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment);
bool checkFramebufferStatus(QOpenGLContext *ctx) const;