source: trunk/src/opengl/qglframebufferobject.cpp@ 616

Last change on this file since 616 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 41.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qglframebufferobject.h"
43#include "qglframebufferobject_p.h"
44
45#include <qdebug.h>
46#include <private/qgl_p.h>
47#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
48#include <private/qpaintengineex_opengl2_p.h>
49#endif
50
51#ifndef QT_OPENGL_ES_2
52#include <private/qpaintengine_opengl_p.h>
53#endif
54
55#include <qglframebufferobject.h>
56#include <qlibrary.h>
57#include <qimage.h>
58
59#ifdef QT_OPENGL_ES_1_CL
60#include "qgl_cl_p.h"
61#endif
62
63QT_BEGIN_NAMESPACE
64
65extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
66
67#define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context();
68#define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context();
69
70#ifndef QT_NO_DEBUG
71#define QT_RESET_GLERROR() \
72{ \
73 while (glGetError() != GL_NO_ERROR) {} \
74}
75#define QT_CHECK_GLERROR() \
76{ \
77 GLenum err = glGetError(); \
78 if (err != GL_NO_ERROR) { \
79 qDebug("[%s line %d] GL Error: %d", \
80 __FILE__, __LINE__, (int)err); \
81 } \
82}
83#else
84#define QT_RESET_GLERROR() {}
85#define QT_CHECK_GLERROR() {}
86#endif
87
88/*!
89 \class QGLFramebufferObjectFormat
90 \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL
91 framebuffer object.
92
93 \since 4.6
94
95 \ingroup painting-3D
96
97 A framebuffer object has several characteristics:
98 \list
99 \i \link setSamples() Number of samples per pixels.\endlink
100 \i \link setAttachment() Depth and/or stencil attachments.\endlink
101 \i \link setTextureTarget() Texture target.\endlink
102 \i \link setInternalTextureFormat() Internal texture format.\endlink
103 \endlist
104
105 Note that the desired attachments or number of samples per pixels might not
106 be supported by the hardware driver. Call QGLFramebufferObject::format()
107 after creating a QGLFramebufferObject to find the exact format that was
108 used to create the frame buffer object.
109
110 \sa QGLFramebufferObject
111*/
112
113/*!
114 \internal
115*/
116void QGLFramebufferObjectFormat::detach()
117{
118 if (d->ref != 1) {
119 QGLFramebufferObjectFormatPrivate *newd
120 = new QGLFramebufferObjectFormatPrivate(d);
121 if (!d->ref.deref())
122 delete d;
123 d = newd;
124 }
125}
126
127/*!
128 Creates a QGLFramebufferObjectFormat object for specifying
129 the format of an OpenGL framebuffer object.
130
131 By default the format specifies a non-multisample framebuffer object with no
132 attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8.
133 On OpenGL/ES systems, the default internal format is \c GL_RGBA.
134
135 \sa samples(), attachment(), target(), internalTextureFormat()
136*/
137
138QGLFramebufferObjectFormat::QGLFramebufferObjectFormat()
139{
140 d = new QGLFramebufferObjectFormatPrivate;
141}
142
143/*!
144 Constructs a copy of \a other.
145*/
146
147QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other)
148{
149 d = other.d;
150 d->ref.ref();
151}
152
153/*!
154 Assigns \a other to this object.
155*/
156
157QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other)
158{
159 if (d != other.d) {
160 other.d->ref.ref();
161 if (!d->ref.deref())
162 delete d;
163 d = other.d;
164 }
165 return *this;
166}
167
168/*!
169 Destroys the QGLFramebufferObjectFormat.
170*/
171QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
172{
173 if (!d->ref.deref())
174 delete d;
175}
176
177/*!
178 Sets the number of samples per pixel for a multisample framebuffer object
179 to \a samples. The default sample count of 0 represents a regular
180 non-multisample framebuffer object.
181
182 If the desired amount of samples per pixel is not supported by the hardware
183 then the maximum number of samples per pixel will be used. Note that
184 multisample framebuffer objects can not be bound as textures. Also, the
185 \c{GL_EXT_framebuffer_multisample} extension is required to create a
186 framebuffer with more than one sample per pixel.
187
188 \sa samples()
189*/
190void QGLFramebufferObjectFormat::setSamples(int samples)
191{
192 detach();
193 d->samples = samples;
194}
195
196/*!
197 Returns the number of samples per pixel if a framebuffer object
198 is a multisample framebuffer object. Otherwise, returns 0.
199 The default value is 0.
200
201 \sa setSamples()
202*/
203int QGLFramebufferObjectFormat::samples() const
204{
205 return d->samples;
206}
207
208/*!
209 Sets the attachment configuration of a framebuffer object to \a attachment.
210
211 \sa attachment()
212*/
213void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment)
214{
215 detach();
216 d->attachment = attachment;
217}
218
219/*!
220 Returns the configuration of the depth and stencil buffers attached to
221 a framebuffer object. The default is QGLFramebufferObject::NoAttachment.
222
223 \sa setAttachment()
224*/
225QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const
226{
227 return d->attachment;
228}
229
230/*!
231 Sets the texture target of the texture attached to a framebuffer object to
232 \a target. Ignored for multisample framebuffer objects.
233
234 \sa textureTarget(), samples()
235*/
236void QGLFramebufferObjectFormat::setTextureTarget(GLenum target)
237{
238 detach();
239 d->target = target;
240}
241
242/*!
243 Returns the texture target of the texture attached to a framebuffer object.
244 Ignored for multisample framebuffer objects. The default is
245 \c GL_TEXTURE_2D.
246
247 \sa setTextureTarget(), samples()
248*/
249GLenum QGLFramebufferObjectFormat::textureTarget() const
250{
251 return d->target;
252}
253
254/*!
255 Sets the internal format of a framebuffer object's texture or
256 multisample framebuffer object's color buffer to
257 \a internalTextureFormat.
258
259 \sa internalTextureFormat()
260*/
261void QGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat)
262{
263 detach();
264 d->internal_format = internalTextureFormat;
265}
266
267/*!
268 Returns the internal format of a framebuffer object's texture or
269 multisample framebuffer object's color buffer. The default is
270 \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on
271 OpenGL/ES systems.
272
273 \sa setInternalTextureFormat()
274*/
275GLenum QGLFramebufferObjectFormat::internalTextureFormat() const
276{
277 return d->internal_format;
278}
279
280#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
281/*! \internal */
282void QGLFramebufferObjectFormat::setTextureTarget(QMacCompatGLenum target)
283{
284 detach();
285 d->target = target;
286}
287
288/*! \internal */
289void QGLFramebufferObjectFormat::setInternalTextureFormat(QMacCompatGLenum internalTextureFormat)
290{
291 detach();
292 d->internal_format = internalTextureFormat;
293}
294#endif
295
296/*!
297 Returns true if all the options of this framebuffer object format
298 are the same as \a other; otherwise returns false.
299*/
300bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const
301{
302 if (d == other.d)
303 return true;
304 else
305 return d->equals(other.d);
306}
307
308/*!
309 Returns false if all the options of this framebuffer object format
310 are the same as \a other; otherwise returns true.
311*/
312bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const
313{
314 return !(*this == other);
315}
316
317void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
318 QGLFramebufferObject::Attachment attachment)
319{
320 fbo = f;
321 m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed
322
323 // The context that the fbo was created in may not have depth
324 // and stencil buffers, but the fbo itself might.
325 fboFormat = QGLContext::currentContext()->format();
326 if (attachment == QGLFramebufferObject::CombinedDepthStencil) {
327 fboFormat.setDepth(true);
328 fboFormat.setStencil(true);
329 } else if (attachment == QGLFramebufferObject::Depth) {
330 fboFormat.setDepth(true);
331 }
332}
333
334QGLContext *QGLFBOGLPaintDevice::context() const
335{
336 QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
337 QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
338
339 if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
340 return currentContext;
341 else
342 return fboContext;
343}
344
345bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
346{
347 QGL_FUNCP_CONTEXT;
348 if (!ctx)
349 return false; // Context no longer exists.
350 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
351 switch(status) {
352 case GL_NO_ERROR:
353 case GL_FRAMEBUFFER_COMPLETE_EXT:
354 return true;
355 break;
356 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
357 qDebug("QGLFramebufferObject: Unsupported framebuffer format.");
358 break;
359 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
360 qDebug("QGLFramebufferObject: Framebuffer incomplete attachment.");
361 break;
362 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
363 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing attachment.");
364 break;
365#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
366 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
367 qDebug("QGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
368 break;
369#endif
370 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
371 qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
372 break;
373 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
374 qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
375 break;
376 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
377 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
378 break;
379 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
380 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
381 break;
382 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
383 qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
384 break;
385 default:
386 qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
387 break;
388 }
389 return false;
390}
391
392void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
393 QGLFramebufferObject::Attachment attachment,
394 GLenum texture_target, GLenum internal_format, GLint samples)
395{
396 QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
397 fbo_guard.setContext(ctx);
398
399 bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
400 if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
401 return;
402
403 size = sz;
404 target = texture_target;
405 // texture dimensions
406
407 QT_RESET_GLERROR(); // reset error state
408 GLuint fbo = 0;
409 glGenFramebuffers(1, &fbo);
410 glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
411 fbo_guard.setId(fbo);
412
413 glDevice.setFBO(q, attachment);
414
415 QT_CHECK_GLERROR();
416 // init texture
417 if (samples == 0) {
418 glGenTextures(1, &texture);
419 glBindTexture(target, texture);
420 glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
421 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
422#ifndef QT_OPENGL_ES
423 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
424 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
425 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
426 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
427#else
428 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
429 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
430 glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
431 glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
432#endif
433 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
434 target, texture, 0);
435
436 QT_CHECK_GLERROR();
437 valid = checkFramebufferStatus();
438 glBindTexture(target, 0);
439
440 color_buffer = 0;
441 } else {
442 GLint maxSamples;
443 glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
444
445 samples = qBound(1, int(samples), int(maxSamples));
446
447 glGenRenderbuffers(1, &color_buffer);
448 glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_buffer);
449 if (glRenderbufferStorageMultisampleEXT) {
450 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
451 internal_format, size.width(), size.height());
452 } else {
453 samples = 0;
454 glRenderbufferStorage(GL_RENDERBUFFER_EXT, internal_format,
455 size.width(), size.height());
456 }
457
458 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
459 GL_RENDERBUFFER_EXT, color_buffer);
460
461 QT_CHECK_GLERROR();
462 valid = checkFramebufferStatus();
463
464 if (valid)
465 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples);
466 }
467
468 if (attachment == QGLFramebufferObject::CombinedDepthStencil
469 && (QGLExtensions::glExtensions & QGLExtensions::PackedDepthStencil)) {
470 // depth and stencil buffer needs another extension
471 glGenRenderbuffers(1, &depth_stencil_buffer);
472 Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
473 glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
474 Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
475 if (samples != 0 && glRenderbufferStorageMultisampleEXT)
476 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
477 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
478 else
479 glRenderbufferStorage(GL_RENDERBUFFER_EXT,
480 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
481
482 GLint i = 0;
483 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
484 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
485 GL_RENDERBUFFER_EXT, depth_stencil_buffer);
486 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
487 GL_RENDERBUFFER_EXT, depth_stencil_buffer);
488 fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
489
490 valid = checkFramebufferStatus();
491 if (!valid)
492 glDeleteRenderbuffers(1, &depth_stencil_buffer);
493 } else if (attachment == QGLFramebufferObject::Depth
494 || attachment == QGLFramebufferObject::CombinedDepthStencil)
495 {
496 glGenRenderbuffers(1, &depth_stencil_buffer);
497 Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
498 glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
499 Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
500 if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
501#ifdef QT_OPENGL_ES
502#define GL_DEPTH_COMPONENT16 0x81A5
503 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
504 GL_DEPTH_COMPONENT16, size.width(), size.height());
505#else
506 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
507 GL_DEPTH_COMPONENT, size.width(), size.height());
508#endif
509 } else {
510#ifdef QT_OPENGL_ES
511#define GL_DEPTH_COMPONENT16 0x81A5
512 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
513#else
514 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
515#endif
516 }
517 GLint i = 0;
518 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
519 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
520 GL_RENDERBUFFER_EXT, depth_stencil_buffer);
521 fbo_attachment = QGLFramebufferObject::Depth;
522 valid = checkFramebufferStatus();
523 if (!valid)
524 glDeleteRenderbuffers(1, &depth_stencil_buffer);
525 } else {
526 fbo_attachment = QGLFramebufferObject::NoAttachment;
527 }
528
529 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
530 if (!valid) {
531 if (color_buffer)
532 glDeleteRenderbuffers(1, &color_buffer);
533 else
534 glDeleteTextures(1, &texture);
535 glDeleteFramebuffers(1, &fbo);
536 fbo_guard.setId(0);
537 }
538 QT_CHECK_GLERROR();
539
540 format.setTextureTarget(target);
541 format.setSamples(int(samples));
542 format.setAttachment(fbo_attachment);
543 format.setInternalTextureFormat(internal_format);
544}
545
546/*!
547 \class QGLFramebufferObject
548 \brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
549 \since 4.2
550
551 \ingroup painting-3D
552
553 The QGLFramebufferObject class encapsulates an OpenGL framebuffer
554 object, defined by the \c{GL_EXT_framebuffer_object} extension. In
555 addition it provides a rendering surface that can be painted on
556 with a QPainter, rendered to using native GL calls, or both. This
557 surface can be bound and used as a regular texture in your own GL
558 drawing code. By default, the QGLFramebufferObject class
559 generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target),
560 which is used as the internal rendering target.
561
562 \bold{It is important to have a current GL context when creating a
563 QGLFramebufferObject, otherwise initialization will fail.}
564
565 OpenGL framebuffer objects and pbuffers (see
566 \l{QGLPixelBuffer}{QGLPixelBuffer}) can both be used to render to
567 offscreen surfaces, but there are a number of advantages with
568 using framebuffer objects instead of pbuffers:
569
570 \list 1
571 \o A framebuffer object does not require a separate rendering
572 context, so no context switching will occur when switching
573 rendering targets. There is an overhead involved in switching
574 targets, but in general it is cheaper than a context switch to a
575 pbuffer.
576
577 \o Rendering to dynamic textures (i.e. render-to-texture
578 functionality) works on all platforms. No need to do explicit copy
579 calls from a render buffer into a texture, as was necessary on
580 systems that did not support the \c{render_texture} extension.
581
582 \o It is possible to attach several rendering buffers (or texture
583 objects) to the same framebuffer object, and render to all of them
584 without doing a context switch.
585
586 \o The OpenGL framebuffer extension is a pure GL extension with no
587 system dependant WGL, CGL, or GLX parts. This makes using
588 framebuffer objects more portable.
589 \endlist
590
591 When using a QPainter to paint to a QGLFramebufferObject you should take
592 care that the QGLFramebufferObject is created with the CombinedDepthStencil
593 attachment for QPainter to be able to render correctly.
594 Note that you need to create a QGLFramebufferObject with more than one
595 sample per pixel for primitives to be antialiased when drawing using a
596 QPainter. To create a multisample framebuffer object you should use one of
597 the constructors that take a QGLFramebufferObject parameter, and set the
598 QGLFramebufferObject::samples() property to a non-zero value.
599
600 When painting to a QGLFramebufferObject using QPainter, the state of
601 the current GL context will be altered by the paint engine to reflect
602 its needs. Applications should not rely upon the GL state being reset
603 to its original conditions, particularly the current shader program,
604 GL viewport, texture units, and drawing modes.
605
606 For multisample framebuffer objects a color render buffer is created,
607 otherwise a texture with the specified texture target is created.
608 The color render buffer or texture will have the specified internal
609 format, and will be bound to the \c GL_COLOR_ATTACHMENT0
610 attachment in the framebuffer object.
611
612 If you want to use a framebuffer object with multisampling enabled
613 as a texture, you first need to copy from it to a regular framebuffer
614 object using QGLContext::blitFramebuffer().
615
616 \sa {Framebuffer Object Example}
617*/
618
619
620/*!
621 \enum QGLFramebufferObject::Attachment
622 \since 4.3
623
624 This enum type is used to configure the depth and stencil buffers
625 attached to the framebuffer object when it is created.
626
627 \value NoAttachment No attachment is added to the framebuffer object. Note that the
628 OpenGL depth and stencil tests won't work when rendering to a
629 framebuffer object without any depth or stencil buffers.
630 This is the default value.
631
632 \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present,
633 a combined depth and stencil buffer is attached.
634 If the extension is not present, only a depth buffer is attached.
635
636 \value Depth A depth buffer is attached to the framebuffer object.
637
638 \sa attachment()
639*/
640
641
642/*! \fn QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
643
644 Constructs an OpenGL framebuffer object and binds a 2D GL texture
645 to the buffer of the size \a size. The texture is bound to the
646 \c GL_COLOR_ATTACHMENT0 target in the framebuffer object.
647
648 The \a target parameter is used to specify the GL texture
649 target. The default target is \c GL_TEXTURE_2D. Keep in mind that
650 \c GL_TEXTURE_2D textures must have a power of 2 width and height
651 (e.g. 256x512), unless you are using OpenGL 2.0 or higher.
652
653 By default, no depth and stencil buffers are attached. This behavior
654 can be toggled using one of the overloaded constructors.
655
656 The default internal texture format is \c GL_RGBA8 for desktop
657 OpenGL, and \c GL_RGBA for OpenGL/ES.
658
659 It is important that you have a current GL context set when
660 creating the QGLFramebufferObject, otherwise the initialization
661 will fail.
662
663 \sa size(), texture(), attachment()
664*/
665
666QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
667 : d_ptr(new QGLFramebufferObjectPrivate)
668{
669 Q_D(QGLFramebufferObject);
670 d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
671}
672
673#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
674/*! \internal */
675QGLFramebufferObject::QGLFramebufferObject(const QSize &size, QMacCompatGLenum target)
676 : d_ptr(new QGLFramebufferObjectPrivate)
677{
678 Q_D(QGLFramebufferObject);
679 d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
680}
681#endif
682
683/*! \overload
684
685 Constructs an OpenGL framebuffer object and binds a 2D GL texture
686 to the buffer of the given \a width and \a height.
687
688 \sa size(), texture()
689*/
690QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
691 : d_ptr(new QGLFramebufferObjectPrivate)
692{
693 Q_D(QGLFramebufferObject);
694 d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
695}
696
697/*! \overload
698
699 Constructs an OpenGL framebuffer object of the given \a size based on the
700 supplied \a format.
701*/
702
703QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format)
704 : d_ptr(new QGLFramebufferObjectPrivate)
705{
706 Q_D(QGLFramebufferObject);
707 d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
708 format.samples());
709}
710
711/*! \overload
712
713 Constructs an OpenGL framebuffer object of the given \a width and \a height
714 based on the supplied \a format.
715*/
716
717QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format)
718 : d_ptr(new QGLFramebufferObjectPrivate)
719{
720 Q_D(QGLFramebufferObject);
721 d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
722 format.internalTextureFormat(), format.samples());
723}
724
725#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
726/*! \internal */
727QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLenum target)
728 : d_ptr(new QGLFramebufferObjectPrivate)
729{
730 Q_D(QGLFramebufferObject);
731 d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
732}
733#endif
734
735/*! \overload
736
737 Constructs an OpenGL framebuffer object and binds a texture to the
738 buffer of the given \a width and \a height.
739
740 The \a attachment parameter describes the depth/stencil buffer
741 configuration, \a target the texture target and \a internal_format
742 the internal texture format. The default texture target is \c
743 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
744 for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
745
746 \sa size(), texture(), attachment()
747*/
748QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
749 GLenum target, GLenum internal_format)
750 : d_ptr(new QGLFramebufferObjectPrivate)
751{
752 Q_D(QGLFramebufferObject);
753 d->init(this, QSize(width, height), attachment, target, internal_format);
754}
755
756#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
757/*! \internal */
758QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
759 QMacCompatGLenum target, QMacCompatGLenum internal_format)
760 : d_ptr(new QGLFramebufferObjectPrivate)
761{
762 Q_D(QGLFramebufferObject);
763 d->init(this, QSize(width, height), attachment, target, internal_format);
764}
765#endif
766
767/*! \overload
768
769 Constructs an OpenGL framebuffer object and binds a texture to the
770 buffer of the given \a size.
771
772 The \a attachment parameter describes the depth/stencil buffer
773 configuration, \a target the texture target and \a internal_format
774 the internal texture format. The default texture target is \c
775 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
776 for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
777
778 \sa size(), texture(), attachment()
779*/
780QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
781 GLenum target, GLenum internal_format)
782 : d_ptr(new QGLFramebufferObjectPrivate)
783{
784 Q_D(QGLFramebufferObject);
785 d->init(this, size, attachment, target, internal_format);
786}
787
788#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
789/*! \internal */
790QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
791 QMacCompatGLenum target, QMacCompatGLenum internal_format)
792 : d_ptr(new QGLFramebufferObjectPrivate)
793{
794 Q_D(QGLFramebufferObject);
795 d->init(this, size, attachment, target, internal_format);
796}
797#endif
798
799/*!
800 \fn QGLFramebufferObject::~QGLFramebufferObject()
801
802 Destroys the framebuffer object and frees any allocated resources.
803*/
804QGLFramebufferObject::~QGLFramebufferObject()
805{
806 Q_D(QGLFramebufferObject);
807 QGL_FUNC_CONTEXT;
808
809 delete d->engine;
810
811 if (isValid() && ctx) {
812 QGLShareContextScope scope(ctx);
813 if (d->texture)
814 glDeleteTextures(1, &d->texture);
815 if (d->color_buffer)
816 glDeleteRenderbuffers(1, &d->color_buffer);
817 if (d->depth_stencil_buffer)
818 glDeleteRenderbuffers(1, &d->depth_stencil_buffer);
819 GLuint fbo = d->fbo();
820 glDeleteFramebuffers(1, &fbo);
821 }
822}
823
824/*!
825 \fn bool QGLFramebufferObject::isValid() const
826
827 Returns true if the framebuffer object is valid.
828
829 The framebuffer can become invalid if the initialization process
830 fails, the user attaches an invalid buffer to the framebuffer
831 object, or a non-power of two width/height is specified as the
832 texture size if the texture target is \c{GL_TEXTURE_2D}.
833 The non-power of two limitation does not apply if the OpenGL version
834 is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension
835 is present.
836
837 The framebuffer can also become invalid if the QGLContext that
838 the framebuffer was created within is destroyed and there are
839 no other shared contexts that can take over ownership of the
840 framebuffer.
841*/
842bool QGLFramebufferObject::isValid() const
843{
844 Q_D(const QGLFramebufferObject);
845 return d->valid && d->fbo_guard.context();
846}
847
848/*!
849 \fn bool QGLFramebufferObject::bind()
850
851 Switches rendering from the default, windowing system provided
852 framebuffer to this framebuffer object.
853 Returns true upon success, false otherwise.
854
855 \sa release()
856*/
857bool QGLFramebufferObject::bind()
858{
859 if (!isValid())
860 return false;
861 Q_D(QGLFramebufferObject);
862 QGL_FUNC_CONTEXT;
863 if (!ctx)
864 return false; // Context no longer exists.
865 const QGLContext *current = QGLContext::currentContext();
866#ifdef QT_DEBUG
867 if (!current ||
868 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
869 {
870 qWarning("QGLFramebufferObject::bind() called from incompatible context");
871 }
872#endif
873 glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo());
874 d->valid = d->checkFramebufferStatus();
875 if (d->valid && current)
876 current->d_ptr->current_fbo = d->fbo();
877 return d->valid;
878}
879
880/*!
881 \fn bool QGLFramebufferObject::release()
882
883 Switches rendering back to the default, windowing system provided
884 framebuffer.
885 Returns true upon success, false otherwise.
886
887 \sa bind()
888*/
889bool QGLFramebufferObject::release()
890{
891 if (!isValid())
892 return false;
893 QGL_FUNC_CONTEXT;
894 if (!ctx)
895 return false; // Context no longer exists.
896
897 const QGLContext *current = QGLContext::currentContext();
898
899#ifdef QT_DEBUG
900 if (!current ||
901 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
902 {
903 qWarning("QGLFramebufferObject::release() called from incompatible context");
904 }
905#endif
906
907 if (current) {
908 current->d_ptr->current_fbo = current->d_ptr->default_fbo;
909 glBindFramebuffer(GL_FRAMEBUFFER_EXT, current->d_ptr->default_fbo);
910 }
911
912 return true;
913}
914
915/*!
916 \fn GLuint QGLFramebufferObject::texture() const
917
918 Returns the texture id for the texture attached as the default
919 rendering target in this framebuffer object. This texture id can
920 be bound as a normal texture in your own GL code.
921
922 If a multisample framebuffer object is used then the value returned
923 from this function will be invalid.
924*/
925GLuint QGLFramebufferObject::texture() const
926{
927 Q_D(const QGLFramebufferObject);
928 return d->texture;
929}
930
931/*!
932 \fn QSize QGLFramebufferObject::size() const
933
934 Returns the size of the texture attached to this framebuffer
935 object.
936*/
937QSize QGLFramebufferObject::size() const
938{
939 Q_D(const QGLFramebufferObject);
940 return d->size;
941}
942
943/*!
944 Returns the format of this framebuffer object.
945*/
946QGLFramebufferObjectFormat QGLFramebufferObject::format() const
947{
948 Q_D(const QGLFramebufferObject);
949 return d->format;
950}
951
952/*!
953 \fn QImage QGLFramebufferObject::toImage() const
954
955 Returns the contents of this framebuffer object as a QImage.
956*/
957QImage QGLFramebufferObject::toImage() const
958{
959 Q_D(const QGLFramebufferObject);
960 if (!d->valid)
961 return QImage();
962
963 // qt_gl_read_framebuffer doesn't work on a multisample FBO
964 if (format().samples() != 0) {
965 QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
966
967 QRect rect(QPoint(0, 0), size());
968 blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
969
970 return temp.toImage();
971 }
972
973 bool wasBound = isBound();
974 if (!wasBound)
975 const_cast<QGLFramebufferObject *>(this)->bind();
976 QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
977 if (!wasBound)
978 const_cast<QGLFramebufferObject *>(this)->release();
979
980 return image;
981}
982
983#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
984Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
985#endif
986
987#ifndef QT_OPENGL_ES_2
988Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
989#endif
990
991/*! \reimp */
992QPaintEngine *QGLFramebufferObject::paintEngine() const
993{
994 Q_D(const QGLFramebufferObject);
995 if (d->engine)
996 return d->engine;
997
998#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
999#if !defined (QT_OPENGL_ES_2)
1000 if (qt_gl_preferGL2Engine()) {
1001#endif
1002 QPaintEngine *engine = qt_buffer_2_engine();
1003 if (engine->isActive() && engine->paintDevice() != this) {
1004 d->engine = new QGL2PaintEngineEx;
1005 return d->engine;
1006 }
1007 return engine;
1008#if !defined (QT_OPENGL_ES_2)
1009 }
1010#endif
1011#endif
1012
1013#if !defined(QT_OPENGL_ES_2)
1014 QPaintEngine *engine = qt_buffer_engine();
1015 if (engine->isActive() && engine->paintDevice() != this) {
1016 d->engine = new QOpenGLPaintEngine;
1017 return d->engine;
1018 }
1019 return engine;
1020#endif
1021}
1022
1023/*!
1024 \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1025
1026 Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension
1027 is present on this system; otherwise returns false.
1028*/
1029bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1030{
1031 QGLExtensions::init();
1032 return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
1033}
1034
1035/*!
1036 \since 4.4
1037
1038 Draws the given texture, \a textureId, to the given target rectangle,
1039 \a target, in OpenGL model space. The \a textureTarget should be a 2D
1040 texture target.
1041
1042 The framebuffer object should be bound when calling this function.
1043
1044 Equivalent to the corresponding QGLContext::drawTexture().
1045*/
1046void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
1047{
1048 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
1049}
1050
1051#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
1052/*! \internal */
1053void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
1054{
1055 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
1056}
1057#endif
1058
1059/*!
1060 \since 4.4
1061
1062 Draws the given texture, \a textureId, at the given \a point in OpenGL
1063 model space. The \a textureTarget should be a 2D texture target.
1064
1065 The framebuffer object should be bound when calling this function.
1066
1067 Equivalent to the corresponding QGLContext::drawTexture().
1068*/
1069void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
1070{
1071 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
1072}
1073
1074#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
1075/*! \internal */
1076void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
1077{
1078 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
1079}
1080#endif
1081
1082extern int qt_defaultDpiX();
1083extern int qt_defaultDpiY();
1084
1085/*! \reimp */
1086int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
1087{
1088 Q_D(const QGLFramebufferObject);
1089
1090 float dpmx = qt_defaultDpiX()*100./2.54;
1091 float dpmy = qt_defaultDpiY()*100./2.54;
1092 int w = d->size.width();
1093 int h = d->size.height();
1094 switch (metric) {
1095 case PdmWidth:
1096 return w;
1097
1098 case PdmHeight:
1099 return h;
1100
1101 case PdmWidthMM:
1102 return qRound(w * 1000 / dpmx);
1103
1104 case PdmHeightMM:
1105 return qRound(h * 1000 / dpmy);
1106
1107 case PdmNumColors:
1108 return 0;
1109
1110 case PdmDepth:
1111 return 32;//d->depth;
1112
1113 case PdmDpiX:
1114 return qRound(dpmx * 0.0254);
1115
1116 case PdmDpiY:
1117 return qRound(dpmy * 0.0254);
1118
1119 case PdmPhysicalDpiX:
1120 return qRound(dpmx * 0.0254);
1121
1122 case PdmPhysicalDpiY:
1123 return qRound(dpmy * 0.0254);
1124
1125 default:
1126 qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
1127 break;
1128 }
1129 return 0;
1130}
1131
1132/*!
1133 \fn GLuint QGLFramebufferObject::handle() const
1134
1135 Returns the GL framebuffer object handle for this framebuffer
1136 object (returned by the \c{glGenFrameBuffersEXT()} function). This
1137 handle can be used to attach new images or buffers to the
1138 framebuffer. The user is responsible for cleaning up and
1139 destroying these objects.
1140*/
1141GLuint QGLFramebufferObject::handle() const
1142{
1143 Q_D(const QGLFramebufferObject);
1144 return d->fbo();
1145}
1146
1147/*! \fn int QGLFramebufferObject::devType() const
1148 \internal
1149*/
1150
1151
1152/*!
1153 Returns the status of the depth and stencil buffers attached to
1154 this framebuffer object.
1155*/
1156
1157QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
1158{
1159 Q_D(const QGLFramebufferObject);
1160 if (d->valid)
1161 return d->fbo_attachment;
1162 return NoAttachment;
1163}
1164
1165/*!
1166 \since 4.5
1167
1168 Returns true if the framebuffer object is currently bound to a context,
1169 otherwise false is returned.
1170*/
1171
1172bool QGLFramebufferObject::isBound() const
1173{
1174 Q_D(const QGLFramebufferObject);
1175 const QGLContext *current = QGLContext::currentContext();
1176 return current ? current->d_ptr->current_fbo == d->fbo() : false;
1177}
1178
1179/*!
1180 \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1181
1182 \since 4.6
1183
1184 Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
1185 is present on this system; otherwise returns false.
1186
1187 \sa blitFramebuffer()
1188*/
1189bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1190{
1191 QGLExtensions::init();
1192 return (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit);
1193}
1194
1195/*!
1196 \since 4.6
1197
1198 Blits from the \a sourceRect rectangle in the \a source framebuffer
1199 object to the \a targetRect rectangle in the \a target framebuffer object.
1200
1201 If \a source or \a target is 0, the default framebuffer will be used
1202 instead of a framebuffer object as source or target respectively.
1203
1204 The \a buffers parameter should be a mask consisting of any combination of
1205 \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
1206 \c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both
1207 in the source and target buffers is ignored.
1208
1209 The \a sourceRect and \a targetRect rectangles may have different sizes;
1210 in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or
1211 \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to
1212 \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest
1213 interpolation should be used when scaling is performed.
1214
1215 If \a source equals \a target a copy is performed within the same buffer.
1216 Results are undefined if the source and target rectangles overlap and
1217 have different sizes. The sizes must also be the same if any of the
1218 framebuffer objects are multisample framebuffers.
1219
1220 Note that the scissor test will restrict the blit area if enabled.
1221
1222 This function will have no effect unless hasOpenGLFramebufferBlit() returns
1223 true.
1224
1225 \sa hasOpenGLFramebufferBlit()
1226*/
1227void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
1228 QGLFramebufferObject *source, const QRect &sourceRect,
1229 GLbitfield buffers,
1230 GLenum filter)
1231{
1232 if (!(QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit))
1233 return;
1234
1235 const QGLContext *ctx = QGLContext::currentContext();
1236 if (!ctx)
1237 return;
1238
1239 const int height = ctx->device()->height();
1240
1241 const int sh = source ? source->height() : height;
1242 const int th = target ? target->height() : height;
1243
1244 const int sx0 = sourceRect.left();
1245 const int sx1 = sourceRect.left() + sourceRect.width();
1246 const int sy0 = sh - (sourceRect.top() + sourceRect.height());
1247 const int sy1 = sh - sourceRect.top();
1248
1249 const int tx0 = targetRect.left();
1250 const int tx1 = targetRect.left() + targetRect.width();
1251 const int ty0 = th - (targetRect.top() + targetRect.height());
1252 const int ty1 = th - targetRect.top();
1253
1254 glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0);
1255 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0);
1256
1257 glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
1258 tx0, ty0, tx1, ty1,
1259 buffers, filter);
1260
1261 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
1262}
1263
1264QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.