summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@digia.com>2013-12-30 14:37:22 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-07 13:04:18 +0100
commitdcbb16a45212d263496df1e5875da6205e4f5f53 (patch)
tree8cddf5be14b99710b4632a9cce99385e588c6e49 /src/gui
parentb12b1ddf4880a5157b5edac05e0ef381e9148aae (diff)
Add takeTexture() to QOpenGLFramebufferObject
Add an API that allows to retrieve and detach the texture from the framebuffer object. The next bind() call will then create and attach a new texture. [ChangeLog][QtGui][QOpenGLFramebufferObject] Added takeTexture() for retrieving and detaching the texture from the framebuffer object. Task-number: QTBUG-35881 Change-Id: I2cca37f5872c1685b1238047f8b912e6534ab781 Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
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;