1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the QtOpenGL module of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
23 | ** In addition, as a special exception, Nokia gives you certain
|
---|
24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
26 | ** package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "qglframebufferobject.h"
|
---|
43 |
|
---|
44 | #include <qdebug.h>
|
---|
45 | #include <private/qgl_p.h>
|
---|
46 | #include <private/qpaintengine_opengl_p.h>
|
---|
47 | #include <qglframebufferobject.h>
|
---|
48 | #include <qlibrary.h>
|
---|
49 | #include <qimage.h>
|
---|
50 |
|
---|
51 | QT_BEGIN_NAMESPACE
|
---|
52 |
|
---|
53 | extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
|
---|
54 |
|
---|
55 | #define QGL_FUNC_CONTEXT QGLContext *ctx = d_ptr->ctx;
|
---|
56 |
|
---|
57 | #define QT_CHECK_GLERROR() \
|
---|
58 | { \
|
---|
59 | GLenum err = glGetError(); \
|
---|
60 | if (err != GL_NO_ERROR) { \
|
---|
61 | qDebug("[%s line %d] GL Error: %d", \
|
---|
62 | __FILE__, __LINE__, (int)err); \
|
---|
63 | } \
|
---|
64 | }
|
---|
65 |
|
---|
66 | class QGLFramebufferObjectPrivate
|
---|
67 | {
|
---|
68 | public:
|
---|
69 | QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), bound(false), ctx(0) {}
|
---|
70 | ~QGLFramebufferObjectPrivate() {}
|
---|
71 |
|
---|
72 | void init(const QSize& sz, QGLFramebufferObject::Attachment attachment,
|
---|
73 | GLenum internal_format, GLenum texture_target);
|
---|
74 | bool checkFramebufferStatus() const;
|
---|
75 | GLuint texture;
|
---|
76 | GLuint fbo;
|
---|
77 | GLuint depth_stencil_buffer;
|
---|
78 | GLenum target;
|
---|
79 | QSize size;
|
---|
80 | uint valid : 1;
|
---|
81 | uint bound : 1;
|
---|
82 | QGLFramebufferObject::Attachment fbo_attachment;
|
---|
83 | QGLContext *ctx; // for Windows extension ptrs
|
---|
84 | };
|
---|
85 |
|
---|
86 | bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
|
---|
87 | {
|
---|
88 | GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
---|
89 | switch(status) {
|
---|
90 | case GL_NO_ERROR:
|
---|
91 | case GL_FRAMEBUFFER_COMPLETE_EXT:
|
---|
92 | return true;
|
---|
93 | break;
|
---|
94 | case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
---|
95 | qDebug("QGLFramebufferObject: Unsupported framebuffer format.");
|
---|
96 | break;
|
---|
97 | case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
---|
98 | qDebug("QGLFramebufferObject: Framebuffer incomplete attachment.");
|
---|
99 | break;
|
---|
100 | case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
|
---|
101 | qDebug("QGLFramebufferObject: Framebuffer incomplete, missing attachment.");
|
---|
102 | break;
|
---|
103 | #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
|
---|
104 | case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
|
---|
105 | qDebug("QGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
|
---|
106 | break;
|
---|
107 | #endif
|
---|
108 | case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
|
---|
109 | qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
|
---|
110 | break;
|
---|
111 | case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
|
---|
112 | qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
|
---|
113 | break;
|
---|
114 | case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
|
---|
115 | qDebug("QGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
|
---|
116 | break;
|
---|
117 | case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
|
---|
118 | qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
|
---|
119 | break;
|
---|
120 | default:
|
---|
121 | qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
|
---|
122 | break;
|
---|
123 | }
|
---|
124 | return false;
|
---|
125 | }
|
---|
126 |
|
---|
127 | void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::Attachment attachment,
|
---|
128 | GLenum texture_target, GLenum internal_format)
|
---|
129 | {
|
---|
130 | ctx = const_cast<QGLContext *>(QGLContext::currentContext());
|
---|
131 | bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
|
---|
132 | if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
|
---|
133 | return;
|
---|
134 |
|
---|
135 | size = sz;
|
---|
136 | target = texture_target;
|
---|
137 | // texture dimensions
|
---|
138 |
|
---|
139 | while (glGetError() != GL_NO_ERROR) {} // reset error state
|
---|
140 | glGenFramebuffersEXT(1, &fbo);
|
---|
141 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
|
---|
142 |
|
---|
143 | QT_CHECK_GLERROR();
|
---|
144 | // init texture
|
---|
145 | glGenTextures(1, &texture);
|
---|
146 | glBindTexture(target, texture);
|
---|
147 | glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
|
---|
148 | GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
---|
149 | #ifndef QT_OPENGL_ES
|
---|
150 | glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
---|
151 | glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
---|
152 | glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
---|
153 | glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
---|
154 | #else
|
---|
155 | glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
---|
156 | glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
---|
157 | glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
---|
158 | glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
---|
159 | #endif
|
---|
160 | glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
---|
161 | target, texture, 0);
|
---|
162 |
|
---|
163 | QT_CHECK_GLERROR();
|
---|
164 | valid = checkFramebufferStatus();
|
---|
165 |
|
---|
166 | if (attachment == QGLFramebufferObject::CombinedDepthStencil
|
---|
167 | && (QGLExtensions::glExtensions & QGLExtensions::PackedDepthStencil)) {
|
---|
168 | // depth and stencil buffer needs another extension
|
---|
169 | glGenRenderbuffersEXT(1, &depth_stencil_buffer);
|
---|
170 | Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer));
|
---|
171 | glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
|
---|
172 | Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer));
|
---|
173 | glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
|
---|
174 | GLint i = 0;
|
---|
175 | glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
|
---|
176 | glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
---|
177 | GL_RENDERBUFFER_EXT, depth_stencil_buffer);
|
---|
178 | glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
|
---|
179 | GL_RENDERBUFFER_EXT, depth_stencil_buffer);
|
---|
180 | fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
|
---|
181 | valid = checkFramebufferStatus();
|
---|
182 | if (!valid)
|
---|
183 | glDeleteRenderbuffersEXT(1, &depth_stencil_buffer);
|
---|
184 | } else if (attachment == QGLFramebufferObject::Depth
|
---|
185 | || attachment == QGLFramebufferObject::CombinedDepthStencil)
|
---|
186 | {
|
---|
187 | glGenRenderbuffersEXT(1, &depth_stencil_buffer);
|
---|
188 | Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer));
|
---|
189 | glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
|
---|
190 | Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer));
|
---|
191 | #ifdef QT_OPENGL_ES
|
---|
192 | #define GL_DEPTH_COMPONENT16 0x81A5
|
---|
193 | glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
|
---|
194 | #else
|
---|
195 | glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
|
---|
196 | #endif
|
---|
197 | GLint i = 0;
|
---|
198 | glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
|
---|
199 | glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
---|
200 | GL_RENDERBUFFER_EXT, depth_stencil_buffer);
|
---|
201 | fbo_attachment = QGLFramebufferObject::Depth;
|
---|
202 | valid = checkFramebufferStatus();
|
---|
203 | if (!valid)
|
---|
204 | glDeleteRenderbuffersEXT(1, &depth_stencil_buffer);
|
---|
205 | } else {
|
---|
206 | fbo_attachment = QGLFramebufferObject::NoAttachment;
|
---|
207 | }
|
---|
208 |
|
---|
209 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
---|
210 | if (!valid) {
|
---|
211 | glDeleteTextures(1, &texture);
|
---|
212 | glDeleteFramebuffersEXT(1, &fbo);
|
---|
213 | }
|
---|
214 | QT_CHECK_GLERROR();
|
---|
215 | }
|
---|
216 |
|
---|
217 | /*!
|
---|
218 | \class QGLFramebufferObject
|
---|
219 | \brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
|
---|
220 | \since 4.2
|
---|
221 |
|
---|
222 | \ingroup multimedia
|
---|
223 |
|
---|
224 | The QGLFramebufferObject class encapsulates an OpenGL framebuffer
|
---|
225 | object, defined by the \c{GL_EXT_framebuffer_object} extension. In
|
---|
226 | addition it provides a rendering surface that can be painted on
|
---|
227 | with a QPainter, rendered to using native GL calls, or both. This
|
---|
228 | surface can be bound and used as a regular texture in your own GL
|
---|
229 | drawing code. By default, the QGLFramebufferObject class
|
---|
230 | generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target),
|
---|
231 | which is used as the internal rendering target.
|
---|
232 |
|
---|
233 | \bold{It is important to have a current GL context when creating a
|
---|
234 | QGLFramebufferObject, otherwise initialization will fail.}
|
---|
235 |
|
---|
236 | OpenGL framebuffer objects and pbuffers (see
|
---|
237 | \l{QGLPixelBuffer}{QGLPixelBuffer}) can both be used to render to
|
---|
238 | offscreen surfaces, but there are a number of advantages with
|
---|
239 | using framebuffer objects instead of pbuffers:
|
---|
240 |
|
---|
241 | \list 1
|
---|
242 | \o A framebuffer object does not require a separate rendering
|
---|
243 | context, so no context switching will occur when switching
|
---|
244 | rendering targets. There is an overhead involved in switching
|
---|
245 | targets, but in general it is cheaper than a context switch to a
|
---|
246 | pbuffer.
|
---|
247 |
|
---|
248 | \o Rendering to dynamic textures (i.e. render-to-texture
|
---|
249 | functionality) works on all platforms. No need to do explicit copy
|
---|
250 | calls from a render buffer into a texture, as was necessary on
|
---|
251 | systems that did not support the \c{render_texture} extension.
|
---|
252 |
|
---|
253 | \o It is possible to attach several rendering buffers (or texture
|
---|
254 | objects) to the same framebuffer object, and render to all of them
|
---|
255 | without doing a context switch.
|
---|
256 |
|
---|
257 | \o The OpenGL framebuffer extension is a pure GL extension with no
|
---|
258 | system dependant WGL, CGL, or GLX parts. This makes using
|
---|
259 | framebuffer objects more portable.
|
---|
260 | \endlist
|
---|
261 |
|
---|
262 | Note that primitives drawn to a QGLFramebufferObject with QPainter
|
---|
263 | will only be antialiased if the QPainter::HighQualityAntialiasing
|
---|
264 | render hint is set. This is because there is currently no support
|
---|
265 | for the \c{GL_EXT_framebuffer_multisample} extension, which is
|
---|
266 | required to do multisample based antialiasing. Also note that the
|
---|
267 | QPainter::HighQualityAntialiasing render hint requires the
|
---|
268 | \c{GL_ARB_fragment_program} extension to work in OpenGL.
|
---|
269 |
|
---|
270 | \sa {Framebuffer Object Example}
|
---|
271 | */
|
---|
272 |
|
---|
273 |
|
---|
274 | /*!
|
---|
275 | \enum QGLFramebufferObject::Attachment
|
---|
276 | \since 4.3
|
---|
277 |
|
---|
278 | This enum type is used to configure the depth and stencil buffers
|
---|
279 | attached to the framebuffer object when it is created.
|
---|
280 |
|
---|
281 | \value NoAttachment No attachment is added to the framebuffer object. Note that the
|
---|
282 | OpenGL depth and stencil tests won't work when rendering to a
|
---|
283 | framebuffer object without any depth or stencil buffers.
|
---|
284 | This is the default value.
|
---|
285 |
|
---|
286 | \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present,
|
---|
287 | a combined depth and stencil buffer is attached.
|
---|
288 | If the extension is not present, only a depth buffer is attached.
|
---|
289 |
|
---|
290 | \value Depth A depth buffer is attached to the framebuffer object.
|
---|
291 |
|
---|
292 | \sa attachment()
|
---|
293 | */
|
---|
294 |
|
---|
295 |
|
---|
296 | /*! \fn QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
|
---|
297 |
|
---|
298 | Constructs an OpenGL framebuffer object and binds a 2D GL texture
|
---|
299 | to the buffer of the size \a size. The texture is bound to the
|
---|
300 | \c GL_COLOR_ATTACHMENT0 target in the framebuffer object.
|
---|
301 |
|
---|
302 | The \a target parameter is used to specify the GL texture
|
---|
303 | target. The default target is \c GL_TEXTURE_2D. Keep in mind that
|
---|
304 | \c GL_TEXTURE_2D textures must have a power of 2 width and height
|
---|
305 | (e.g. 256x512), unless you are using OpenGL 2.0 or higher.
|
---|
306 |
|
---|
307 | By default, no depth and stencil buffers are attached. This behavior
|
---|
308 | can be toggled using one of the overloaded constructors.
|
---|
309 |
|
---|
310 | The default internal texture format is \c GL_RGBA8.
|
---|
311 |
|
---|
312 | It is important that you have a current GL context set when
|
---|
313 | creating the QGLFramebufferObject, otherwise the initialization
|
---|
314 | will fail.
|
---|
315 |
|
---|
316 | \sa size(), texture(), attachment()
|
---|
317 | */
|
---|
318 |
|
---|
319 | #ifndef QT_OPENGL_ES
|
---|
320 | #define DEFAULT_FORMAT GL_RGBA8
|
---|
321 | #else
|
---|
322 | #define DEFAULT_FORMAT GL_RGBA
|
---|
323 | #endif
|
---|
324 |
|
---|
325 | QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
|
---|
326 | : d_ptr(new QGLFramebufferObjectPrivate)
|
---|
327 | {
|
---|
328 | Q_D(QGLFramebufferObject);
|
---|
329 | d->init(size, NoAttachment, target, DEFAULT_FORMAT);
|
---|
330 | }
|
---|
331 |
|
---|
332 | #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
|
---|
333 | /*! \internal */
|
---|
334 | QGLFramebufferObject::QGLFramebufferObject(const QSize &size, QMacCompatGLenum target)
|
---|
335 | : d_ptr(new QGLFramebufferObjectPrivate)
|
---|
336 | {
|
---|
337 | Q_D(QGLFramebufferObject);
|
---|
338 | d->init(size, NoAttachment, target, DEFAULT_FORMAT);
|
---|
339 | }
|
---|
340 | #endif
|
---|
341 |
|
---|
342 | /*! \overload
|
---|
343 |
|
---|
344 | Constructs an OpenGL framebuffer object and binds a 2D GL texture
|
---|
345 | to the buffer of the given \a width and \a height.
|
---|
346 |
|
---|
347 | \sa size(), texture()
|
---|
348 | */
|
---|
349 | QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
|
---|
350 | : d_ptr(new QGLFramebufferObjectPrivate)
|
---|
351 | {
|
---|
352 | Q_D(QGLFramebufferObject);
|
---|
353 | d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
|
---|
354 | }
|
---|
355 |
|
---|
356 | #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
|
---|
357 | /*! \internal */
|
---|
358 | QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLenum target)
|
---|
359 | : d_ptr(new QGLFramebufferObjectPrivate)
|
---|
360 | {
|
---|
361 | Q_D(QGLFramebufferObject);
|
---|
362 | d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
|
---|
363 | }
|
---|
364 | #endif
|
---|
365 |
|
---|
366 | /*! \overload
|
---|
367 |
|
---|
368 | Constructs an OpenGL framebuffer object and binds a texture to the
|
---|
369 | buffer of the given \a width and \a height.
|
---|
370 |
|
---|
371 | The \a attachment parameter describes the depth/stencil buffer
|
---|
372 | configuration, \a target the texture target and \a internal_format
|
---|
373 | the internal texture format. The default texture target is \c
|
---|
374 | GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8.
|
---|
375 |
|
---|
376 | \sa size(), texture(), attachment()
|
---|
377 | */
|
---|
378 | QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
|
---|
379 | GLenum target, GLenum internal_format)
|
---|
380 | : d_ptr(new QGLFramebufferObjectPrivate)
|
---|
381 | {
|
---|
382 | Q_D(QGLFramebufferObject);
|
---|
383 | d->init(QSize(width, height), attachment, target, internal_format);
|
---|
384 | }
|
---|
385 |
|
---|
386 | #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
|
---|
387 | /*! \internal */
|
---|
388 | QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
|
---|
389 | QMacCompatGLenum target, QMacCompatGLenum internal_format)
|
---|
390 | : d_ptr(new QGLFramebufferObjectPrivate)
|
---|
391 | {
|
---|
392 | Q_D(QGLFramebufferObject);
|
---|
393 | d->init(QSize(width, height), attachment, target, internal_format);
|
---|
394 | }
|
---|
395 | #endif
|
---|
396 |
|
---|
397 | /*! \overload
|
---|
398 |
|
---|
399 | Constructs an OpenGL framebuffer object and binds a texture to the
|
---|
400 | buffer of the given \a size.
|
---|
401 |
|
---|
402 | The \a attachment parameter describes the depth/stencil buffer
|
---|
403 | configuration, \a target the texture target and \a internal_format
|
---|
404 | the internal texture format. The default texture target is \c
|
---|
405 | GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8.
|
---|
406 |
|
---|
407 | \sa size(), texture(), attachment()
|
---|
408 | */
|
---|
409 | QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
|
---|
410 | GLenum target, GLenum internal_format)
|
---|
411 | : d_ptr(new QGLFramebufferObjectPrivate)
|
---|
412 | {
|
---|
413 | Q_D(QGLFramebufferObject);
|
---|
414 | d->init(size, attachment, target, internal_format);
|
---|
415 | }
|
---|
416 |
|
---|
417 | #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
|
---|
418 | /*! \internal */
|
---|
419 | QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
|
---|
420 | QMacCompatGLenum target, QMacCompatGLenum internal_format)
|
---|
421 | : d_ptr(new QGLFramebufferObjectPrivate)
|
---|
422 | {
|
---|
423 | Q_D(QGLFramebufferObject);
|
---|
424 | d->init(size, attachment, target, internal_format);
|
---|
425 | }
|
---|
426 | #endif
|
---|
427 |
|
---|
428 | /*!
|
---|
429 | \fn QGLFramebufferObject::~QGLFramebufferObject()
|
---|
430 |
|
---|
431 | Destroys the framebuffer object and frees any allocated resources.
|
---|
432 | */
|
---|
433 | QGLFramebufferObject::~QGLFramebufferObject()
|
---|
434 | {
|
---|
435 | Q_D(QGLFramebufferObject);
|
---|
436 | QGL_FUNC_CONTEXT;
|
---|
437 |
|
---|
438 | if (isValid()
|
---|
439 | && (d->ctx == QGLContext::currentContext()
|
---|
440 | || qgl_share_reg()->checkSharing(d->ctx, QGLContext::currentContext())))
|
---|
441 | {
|
---|
442 | glDeleteTextures(1, &d->texture);
|
---|
443 | if (d->depth_stencil_buffer)
|
---|
444 | glDeleteRenderbuffersEXT(1, &d->depth_stencil_buffer);
|
---|
445 | glDeleteFramebuffersEXT(1, &d->fbo);
|
---|
446 | }
|
---|
447 | delete d_ptr;
|
---|
448 | }
|
---|
449 |
|
---|
450 | /*!
|
---|
451 | \fn bool QGLFramebufferObject::isValid() const
|
---|
452 |
|
---|
453 | Returns true if the framebuffer object is valid.
|
---|
454 |
|
---|
455 | The framebuffer can become invalid if the initialization process
|
---|
456 | fails, the user attaches an invalid buffer to the framebuffer
|
---|
457 | object, or a non-power of 2 width/height is specified as the
|
---|
458 | texture size if the texture target is \c{GL_TEXTURE_2D}.
|
---|
459 | */
|
---|
460 | bool QGLFramebufferObject::isValid() const
|
---|
461 | {
|
---|
462 | Q_D(const QGLFramebufferObject);
|
---|
463 | return d->valid;
|
---|
464 | }
|
---|
465 |
|
---|
466 | /*!
|
---|
467 | \fn bool QGLFramebufferObject::bind()
|
---|
468 |
|
---|
469 | Switches rendering from the default, windowing system provided
|
---|
470 | framebuffer to this framebuffer object.
|
---|
471 | Returns true upon success, false otherwise.
|
---|
472 | */
|
---|
473 | bool QGLFramebufferObject::bind()
|
---|
474 | {
|
---|
475 | if (!isValid())
|
---|
476 | return false;
|
---|
477 | Q_D(QGLFramebufferObject);
|
---|
478 | QGL_FUNC_CONTEXT;
|
---|
479 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->fbo);
|
---|
480 | d->bound = d->valid = d->checkFramebufferStatus();
|
---|
481 | return d->valid;
|
---|
482 | }
|
---|
483 |
|
---|
484 | /*!
|
---|
485 | \fn bool QGLFramebufferObject::release()
|
---|
486 |
|
---|
487 | Switches rendering back to the default, windowing system provided
|
---|
488 | framebuffer.
|
---|
489 | Returns true upon success, false otherwise.
|
---|
490 | */
|
---|
491 | bool QGLFramebufferObject::release()
|
---|
492 | {
|
---|
493 | if (!isValid())
|
---|
494 | return false;
|
---|
495 | Q_D(QGLFramebufferObject);
|
---|
496 | QGL_FUNC_CONTEXT;
|
---|
497 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
---|
498 | d->valid = d->checkFramebufferStatus();
|
---|
499 | d->bound = false;
|
---|
500 | return d->valid;
|
---|
501 | }
|
---|
502 |
|
---|
503 | /*!
|
---|
504 | \fn GLuint QGLFramebufferObject::texture() const
|
---|
505 |
|
---|
506 | Returns the texture id for the texture attached as the default
|
---|
507 | rendering target in this framebuffer object. This texture id can
|
---|
508 | be bound as a normal texture in your own GL code.
|
---|
509 | */
|
---|
510 | GLuint QGLFramebufferObject::texture() const
|
---|
511 | {
|
---|
512 | Q_D(const QGLFramebufferObject);
|
---|
513 | return d->texture;
|
---|
514 | }
|
---|
515 |
|
---|
516 | /*!
|
---|
517 | \fn QSize QGLFramebufferObject::size() const
|
---|
518 |
|
---|
519 | Returns the size of the texture attached to this framebuffer
|
---|
520 | object.
|
---|
521 | */
|
---|
522 | QSize QGLFramebufferObject::size() const
|
---|
523 | {
|
---|
524 | Q_D(const QGLFramebufferObject);
|
---|
525 | return d->size;
|
---|
526 | }
|
---|
527 |
|
---|
528 | /*!
|
---|
529 | \fn QImage QGLFramebufferObject::toImage() const
|
---|
530 |
|
---|
531 | Returns the contents of this framebuffer object as a QImage.
|
---|
532 | */
|
---|
533 | QImage QGLFramebufferObject::toImage() const
|
---|
534 | {
|
---|
535 | Q_D(const QGLFramebufferObject);
|
---|
536 | if (!d->valid)
|
---|
537 | return QImage();
|
---|
538 |
|
---|
539 | const_cast<QGLFramebufferObject *>(this)->bind();
|
---|
540 | QImage image = qt_gl_read_framebuffer(d->size, d->ctx->format().alpha(), true);
|
---|
541 | const_cast<QGLFramebufferObject *>(this)->release();
|
---|
542 |
|
---|
543 | return image;
|
---|
544 | }
|
---|
545 |
|
---|
546 | #if !defined(QT_OPENGL_ES_2)
|
---|
547 | Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine)
|
---|
548 | #endif
|
---|
549 |
|
---|
550 | /*! \reimp */
|
---|
551 | QPaintEngine *QGLFramebufferObject::paintEngine() const
|
---|
552 | {
|
---|
553 | #if !defined(QT_OPENGL_ES_2)
|
---|
554 | return qt_buffer_paintengine();
|
---|
555 | #else
|
---|
556 | return 0;
|
---|
557 | #endif
|
---|
558 | }
|
---|
559 |
|
---|
560 | /*!
|
---|
561 | \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
|
---|
562 |
|
---|
563 | Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension
|
---|
564 | is present on this system; otherwise returns false.
|
---|
565 | */
|
---|
566 | bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
|
---|
567 | {
|
---|
568 | QGLWidget dmy; // needed to detect and init the QGLExtensions object
|
---|
569 | return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
|
---|
570 | }
|
---|
571 |
|
---|
572 | /*!
|
---|
573 | \since 4.4
|
---|
574 |
|
---|
575 | Draws the given texture, \a textureId, to the given target rectangle,
|
---|
576 | \a target, in OpenGL model space. The \a textureTarget should be a 2D
|
---|
577 | texture target.
|
---|
578 |
|
---|
579 | The framebuffer object should be bound when calling this function.
|
---|
580 |
|
---|
581 | Equivalent to the corresponding QGLContext::drawTexture().
|
---|
582 | */
|
---|
583 | void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
|
---|
584 | {
|
---|
585 | Q_D(QGLFramebufferObject);
|
---|
586 | d->ctx->drawTexture(target, textureId, textureTarget);
|
---|
587 | }
|
---|
588 |
|
---|
589 | #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
|
---|
590 | /*! \internal */
|
---|
591 | void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
|
---|
592 | {
|
---|
593 | Q_D(QGLFramebufferObject);
|
---|
594 | d->ctx->drawTexture(target, textureId, textureTarget);
|
---|
595 | }
|
---|
596 | #endif
|
---|
597 |
|
---|
598 | /*!
|
---|
599 | \since 4.4
|
---|
600 |
|
---|
601 | Draws the given texture, \a textureId, at the given \a point in OpenGL
|
---|
602 | model space. The \a textureTarget should be a 2D texture target.
|
---|
603 |
|
---|
604 | The framebuffer object should be bound when calling this function.
|
---|
605 |
|
---|
606 | Equivalent to the corresponding QGLContext::drawTexture().
|
---|
607 | */
|
---|
608 | void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
|
---|
609 | {
|
---|
610 | Q_D(QGLFramebufferObject);
|
---|
611 | d->ctx->drawTexture(point, textureId, textureTarget);
|
---|
612 | }
|
---|
613 |
|
---|
614 | #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
|
---|
615 | /*! \internal */
|
---|
616 | void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
|
---|
617 | {
|
---|
618 | Q_D(QGLFramebufferObject);
|
---|
619 | d->ctx->drawTexture(point, textureId, textureTarget);
|
---|
620 | }
|
---|
621 | #endif
|
---|
622 |
|
---|
623 | extern int qt_defaultDpi();
|
---|
624 |
|
---|
625 | /*! \reimp */
|
---|
626 | int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
|
---|
627 | {
|
---|
628 | Q_D(const QGLFramebufferObject);
|
---|
629 |
|
---|
630 | float dpmx = qt_defaultDpi()*100./2.54;
|
---|
631 | float dpmy = qt_defaultDpi()*100./2.54;
|
---|
632 | int w = d->size.width();
|
---|
633 | int h = d->size.height();
|
---|
634 | switch (metric) {
|
---|
635 | case PdmWidth:
|
---|
636 | return w;
|
---|
637 |
|
---|
638 | case PdmHeight:
|
---|
639 | return h;
|
---|
640 |
|
---|
641 | case PdmWidthMM:
|
---|
642 | return qRound(w * 1000 / dpmx);
|
---|
643 |
|
---|
644 | case PdmHeightMM:
|
---|
645 | return qRound(h * 1000 / dpmy);
|
---|
646 |
|
---|
647 | case PdmNumColors:
|
---|
648 | return 0;
|
---|
649 |
|
---|
650 | case PdmDepth:
|
---|
651 | return 32;//d->depth;
|
---|
652 |
|
---|
653 | case PdmDpiX:
|
---|
654 | return (int)(dpmx * 0.0254);
|
---|
655 |
|
---|
656 | case PdmDpiY:
|
---|
657 | return (int)(dpmy * 0.0254);
|
---|
658 |
|
---|
659 | case PdmPhysicalDpiX:
|
---|
660 | return (int)(dpmx * 0.0254);
|
---|
661 |
|
---|
662 | case PdmPhysicalDpiY:
|
---|
663 | return (int)(dpmy * 0.0254);
|
---|
664 |
|
---|
665 | default:
|
---|
666 | qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
|
---|
667 | break;
|
---|
668 | }
|
---|
669 | return 0;
|
---|
670 | }
|
---|
671 |
|
---|
672 | /*!
|
---|
673 | \fn GLuint QGLFramebufferObject::handle() const
|
---|
674 |
|
---|
675 | Returns the GL framebuffer object handle for this framebuffer
|
---|
676 | object (returned by the \c{glGenFrameBuffersEXT()} function). This
|
---|
677 | handle can be used to attach new images or buffers to the
|
---|
678 | framebuffer. The user is responsible for cleaning up and
|
---|
679 | destroying these objects.
|
---|
680 | */
|
---|
681 | GLuint QGLFramebufferObject::handle() const
|
---|
682 | {
|
---|
683 | Q_D(const QGLFramebufferObject);
|
---|
684 | return d->fbo;
|
---|
685 | }
|
---|
686 |
|
---|
687 | /*! \fn int QGLFramebufferObject::devType() const
|
---|
688 |
|
---|
689 | \reimp
|
---|
690 | */
|
---|
691 |
|
---|
692 |
|
---|
693 | /*!
|
---|
694 | Returns the status of the depth and stencil buffers attached to
|
---|
695 | this framebuffer object.
|
---|
696 | */
|
---|
697 |
|
---|
698 | QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
|
---|
699 | {
|
---|
700 | Q_D(const QGLFramebufferObject);
|
---|
701 | if (d->valid)
|
---|
702 | return d->fbo_attachment;
|
---|
703 | return NoAttachment;
|
---|
704 | }
|
---|
705 |
|
---|
706 | /*!
|
---|
707 | \since 4.5
|
---|
708 |
|
---|
709 | Returns true if the framebuffer object is currently bound to a context,
|
---|
710 | otherwise false is returned.
|
---|
711 | */
|
---|
712 |
|
---|
713 | bool QGLFramebufferObject::isBound() const
|
---|
714 | {
|
---|
715 | Q_D(const QGLFramebufferObject);
|
---|
716 | return d->bound;
|
---|
717 | }
|
---|
718 |
|
---|
719 | QT_END_NAMESPACE
|
---|