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

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

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 41.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 GLenum format = f->format().internalTextureFormat();
334 reqAlpha = (format != GL_RGB
335#ifndef QT_OPENGL_ES
336 && format != GL_RGB5 && format != GL_RGB8
337#endif
338 );
339}
340
341QGLContext *QGLFBOGLPaintDevice::context() const
342{
343 QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
344 QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
345
346 if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
347 return currentContext;
348 else
349 return fboContext;
350}
351
352bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
353{
354 QGL_FUNCP_CONTEXT;
355 if (!ctx)
356 return false; // Context no longer exists.
357 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
358 switch(status) {
359 case GL_NO_ERROR:
360 case GL_FRAMEBUFFER_COMPLETE_EXT:
361 return true;
362 break;
363 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
364 qDebug("QGLFramebufferObject: Unsupported framebuffer format.");
365 break;
366 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
367 qDebug("QGLFramebufferObject: Framebuffer incomplete attachment.");
368 break;
369 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
370 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing attachment.");
371 break;
372#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
373 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
374 qDebug("QGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
375 break;
376#endif
377 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
378 qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
379 break;
380 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
381 qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
382 break;
383 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
384 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
385 break;
386 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
387 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
388 break;
389 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
390 qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
391 break;
392 default:
393 qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
394 break;
395 }
396 return false;
397}
398
399void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
400 QGLFramebufferObject::Attachment attachment,
401 GLenum texture_target, GLenum internal_format, GLint samples)
402{
403 QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
404 fbo_guard.setContext(ctx);
405
406 bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
407 if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
408 return;
409
410 size = sz;
411 target = texture_target;
412 // texture dimensions
413
414 QT_RESET_GLERROR(); // reset error state
415 GLuint fbo = 0;
416 glGenFramebuffers(1, &fbo);
417 glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
418 fbo_guard.setId(fbo);
419
420 glDevice.setFBO(q, attachment);
421
422 QT_CHECK_GLERROR();
423 // init texture
424 if (samples == 0) {
425 glGenTextures(1, &texture);
426 glBindTexture(target, texture);
427 glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
428 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
429#ifndef QT_OPENGL_ES
430 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
431 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
432 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
433 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
434#else
435 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
436 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
437 glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
438 glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
439#endif
440 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
441 target, texture, 0);
442
443 QT_CHECK_GLERROR();
444 valid = checkFramebufferStatus();
445 glBindTexture(target, 0);
446
447 color_buffer = 0;
448 } else {
449 GLint maxSamples;
450 glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
451
452 samples = qBound(1, int(samples), int(maxSamples));
453
454 glGenRenderbuffers(1, &color_buffer);
455 glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_buffer);
456 if (glRenderbufferStorageMultisampleEXT) {
457 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
458 internal_format, size.width(), size.height());
459 } else {
460 samples = 0;
461 glRenderbufferStorage(GL_RENDERBUFFER_EXT, internal_format,
462 size.width(), size.height());
463 }
464
465 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
466 GL_RENDERBUFFER_EXT, color_buffer);
467
468 QT_CHECK_GLERROR();
469 valid = checkFramebufferStatus();
470
471 if (valid)
472 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples);
473 }
474
475 if (attachment == QGLFramebufferObject::CombinedDepthStencil
476 && (QGLExtensions::glExtensions() & QGLExtensions::PackedDepthStencil)) {
477 // depth and stencil buffer needs another extension
478 glGenRenderbuffers(1, &depth_stencil_buffer);
479 Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
480 glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
481 Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
482 if (samples != 0 && glRenderbufferStorageMultisampleEXT)
483 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
484 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
485 else
486 glRenderbufferStorage(GL_RENDERBUFFER_EXT,
487 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
488
489 GLint i = 0;
490 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
491 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
492 GL_RENDERBUFFER_EXT, depth_stencil_buffer);
493 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
494 GL_RENDERBUFFER_EXT, depth_stencil_buffer);
495 fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
496
497 valid = checkFramebufferStatus();
498 if (!valid)
499 glDeleteRenderbuffers(1, &depth_stencil_buffer);
500 } else if (attachment == QGLFramebufferObject::Depth
501 || attachment == QGLFramebufferObject::CombinedDepthStencil)
502 {
503 glGenRenderbuffers(1, &depth_stencil_buffer);
504 Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
505 glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
506 Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
507 if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
508#ifdef QT_OPENGL_ES
509#define GL_DEPTH_COMPONENT16 0x81A5
510 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
511 GL_DEPTH_COMPONENT16, size.width(), size.height());
512#else
513 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
514 GL_DEPTH_COMPONENT, size.width(), size.height());
515#endif
516 } else {
517#ifdef QT_OPENGL_ES
518#define GL_DEPTH_COMPONENT16 0x81A5
519 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
520#else
521 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
522#endif
523 }
524 GLint i = 0;
525 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
526 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
527 GL_RENDERBUFFER_EXT, depth_stencil_buffer);
528 fbo_attachment = QGLFramebufferObject::Depth;
529 valid = checkFramebufferStatus();
530 if (!valid)
531 glDeleteRenderbuffers(1, &depth_stencil_buffer);
532 } else {
533 fbo_attachment = QGLFramebufferObject::NoAttachment;
534 }
535
536 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
537 if (!valid) {
538 if (color_buffer)
539 glDeleteRenderbuffers(1, &color_buffer);
540 else
541 glDeleteTextures(1, &texture);
542 glDeleteFramebuffers(1, &fbo);
543 fbo_guard.setId(0);
544 }
545 QT_CHECK_GLERROR();
546
547 format.setTextureTarget(target);
548 format.setSamples(int(samples));
549 format.setAttachment(fbo_attachment);
550 format.setInternalTextureFormat(internal_format);
551}
552
553/*!
554 \class QGLFramebufferObject
555 \brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
556 \since 4.2
557
558 \ingroup painting-3D
559
560 The QGLFramebufferObject class encapsulates an OpenGL framebuffer
561 object, defined by the \c{GL_EXT_framebuffer_object} extension. In
562 addition it provides a rendering surface that can be painted on
563 with a QPainter, rendered to using native GL calls, or both. This
564 surface can be bound and used as a regular texture in your own GL
565 drawing code. By default, the QGLFramebufferObject class
566 generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target),
567 which is used as the internal rendering target.
568
569 \bold{It is important to have a current GL context when creating a
570 QGLFramebufferObject, otherwise initialization will fail.}
571
572 OpenGL framebuffer objects and pbuffers (see
573 \l{QGLPixelBuffer}{QGLPixelBuffer}) can both be used to render to
574 offscreen surfaces, but there are a number of advantages with
575 using framebuffer objects instead of pbuffers:
576
577 \list 1
578 \o A framebuffer object does not require a separate rendering
579 context, so no context switching will occur when switching
580 rendering targets. There is an overhead involved in switching
581 targets, but in general it is cheaper than a context switch to a
582 pbuffer.
583
584 \o Rendering to dynamic textures (i.e. render-to-texture
585 functionality) works on all platforms. No need to do explicit copy
586 calls from a render buffer into a texture, as was necessary on
587 systems that did not support the \c{render_texture} extension.
588
589 \o It is possible to attach several rendering buffers (or texture
590 objects) to the same framebuffer object, and render to all of them
591 without doing a context switch.
592
593 \o The OpenGL framebuffer extension is a pure GL extension with no
594 system dependant WGL, CGL, or GLX parts. This makes using
595 framebuffer objects more portable.
596 \endlist
597
598 When using a QPainter to paint to a QGLFramebufferObject you should take
599 care that the QGLFramebufferObject is created with the CombinedDepthStencil
600 attachment for QPainter to be able to render correctly.
601 Note that you need to create a QGLFramebufferObject with more than one
602 sample per pixel for primitives to be antialiased when drawing using a
603 QPainter. To create a multisample framebuffer object you should use one of
604 the constructors that take a QGLFramebufferObject parameter, and set the
605 QGLFramebufferObject::samples() property to a non-zero value.
606
607 When painting to a QGLFramebufferObject using QPainter, the state of
608 the current GL context will be altered by the paint engine to reflect
609 its needs. Applications should not rely upon the GL state being reset
610 to its original conditions, particularly the current shader program,
611 GL viewport, texture units, and drawing modes.
612
613 For multisample framebuffer objects a color render buffer is created,
614 otherwise a texture with the specified texture target is created.
615 The color render buffer or texture will have the specified internal
616 format, and will be bound to the \c GL_COLOR_ATTACHMENT0
617 attachment in the framebuffer object.
618
619 If you want to use a framebuffer object with multisampling enabled
620 as a texture, you first need to copy from it to a regular framebuffer
621 object using QGLContext::blitFramebuffer().
622
623 \sa {Framebuffer Object Example}
624*/
625
626
627/*!
628 \enum QGLFramebufferObject::Attachment
629 \since 4.3
630
631 This enum type is used to configure the depth and stencil buffers
632 attached to the framebuffer object when it is created.
633
634 \value NoAttachment No attachment is added to the framebuffer object. Note that the
635 OpenGL depth and stencil tests won't work when rendering to a
636 framebuffer object without any depth or stencil buffers.
637 This is the default value.
638
639 \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present,
640 a combined depth and stencil buffer is attached.
641 If the extension is not present, only a depth buffer is attached.
642
643 \value Depth A depth buffer is attached to the framebuffer object.
644
645 \sa attachment()
646*/
647
648
649/*! \fn QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
650
651 Constructs an OpenGL framebuffer object and binds a 2D GL texture
652 to the buffer of the size \a size. The texture is bound to the
653 \c GL_COLOR_ATTACHMENT0 target in the framebuffer object.
654
655 The \a target parameter is used to specify the GL texture
656 target. The default target is \c GL_TEXTURE_2D. Keep in mind that
657 \c GL_TEXTURE_2D textures must have a power of 2 width and height
658 (e.g. 256x512), unless you are using OpenGL 2.0 or higher.
659
660 By default, no depth and stencil buffers are attached. This behavior
661 can be toggled using one of the overloaded constructors.
662
663 The default internal texture format is \c GL_RGBA8 for desktop
664 OpenGL, and \c GL_RGBA for OpenGL/ES.
665
666 It is important that you have a current GL context set when
667 creating the QGLFramebufferObject, otherwise the initialization
668 will fail.
669
670 \sa size(), texture(), attachment()
671*/
672
673QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
674 : d_ptr(new QGLFramebufferObjectPrivate)
675{
676 Q_D(QGLFramebufferObject);
677 d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
678}
679
680#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
681/*! \internal */
682QGLFramebufferObject::QGLFramebufferObject(const QSize &size, QMacCompatGLenum target)
683 : d_ptr(new QGLFramebufferObjectPrivate)
684{
685 Q_D(QGLFramebufferObject);
686 d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
687}
688#endif
689
690/*! \overload
691
692 Constructs an OpenGL framebuffer object and binds a 2D GL texture
693 to the buffer of the given \a width and \a height.
694
695 \sa size(), texture()
696*/
697QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
698 : d_ptr(new QGLFramebufferObjectPrivate)
699{
700 Q_D(QGLFramebufferObject);
701 d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
702}
703
704/*! \overload
705
706 Constructs an OpenGL framebuffer object of the given \a size based on the
707 supplied \a format.
708*/
709
710QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format)
711 : d_ptr(new QGLFramebufferObjectPrivate)
712{
713 Q_D(QGLFramebufferObject);
714 d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
715 format.samples());
716}
717
718/*! \overload
719
720 Constructs an OpenGL framebuffer object of the given \a width and \a height
721 based on the supplied \a format.
722*/
723
724QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format)
725 : d_ptr(new QGLFramebufferObjectPrivate)
726{
727 Q_D(QGLFramebufferObject);
728 d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
729 format.internalTextureFormat(), format.samples());
730}
731
732#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
733/*! \internal */
734QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLenum target)
735 : d_ptr(new QGLFramebufferObjectPrivate)
736{
737 Q_D(QGLFramebufferObject);
738 d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
739}
740#endif
741
742/*! \overload
743
744 Constructs an OpenGL framebuffer object and binds a texture to the
745 buffer of the given \a width and \a height.
746
747 The \a attachment parameter describes the depth/stencil buffer
748 configuration, \a target the texture target and \a internal_format
749 the internal texture format. The default texture target is \c
750 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
751 for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
752
753 \sa size(), texture(), attachment()
754*/
755QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
756 GLenum target, GLenum internal_format)
757 : d_ptr(new QGLFramebufferObjectPrivate)
758{
759 Q_D(QGLFramebufferObject);
760 d->init(this, QSize(width, height), attachment, target, internal_format);
761}
762
763#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
764/*! \internal */
765QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
766 QMacCompatGLenum target, QMacCompatGLenum internal_format)
767 : d_ptr(new QGLFramebufferObjectPrivate)
768{
769 Q_D(QGLFramebufferObject);
770 d->init(this, QSize(width, height), attachment, target, internal_format);
771}
772#endif
773
774/*! \overload
775
776 Constructs an OpenGL framebuffer object and binds a texture to the
777 buffer of the given \a size.
778
779 The \a attachment parameter describes the depth/stencil buffer
780 configuration, \a target the texture target and \a internal_format
781 the internal texture format. The default texture target is \c
782 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
783 for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
784
785 \sa size(), texture(), attachment()
786*/
787QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
788 GLenum target, GLenum internal_format)
789 : d_ptr(new QGLFramebufferObjectPrivate)
790{
791 Q_D(QGLFramebufferObject);
792 d->init(this, size, attachment, target, internal_format);
793}
794
795#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
796/*! \internal */
797QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
798 QMacCompatGLenum target, QMacCompatGLenum internal_format)
799 : d_ptr(new QGLFramebufferObjectPrivate)
800{
801 Q_D(QGLFramebufferObject);
802 d->init(this, size, attachment, target, internal_format);
803}
804#endif
805
806/*!
807 \fn QGLFramebufferObject::~QGLFramebufferObject()
808
809 Destroys the framebuffer object and frees any allocated resources.
810*/
811QGLFramebufferObject::~QGLFramebufferObject()
812{
813 Q_D(QGLFramebufferObject);
814 QGL_FUNC_CONTEXT;
815
816 delete d->engine;
817
818 if (isValid() && ctx) {
819 QGLShareContextScope scope(ctx);
820 if (d->texture)
821 glDeleteTextures(1, &d->texture);
822 if (d->color_buffer)
823 glDeleteRenderbuffers(1, &d->color_buffer);
824 if (d->depth_stencil_buffer)
825 glDeleteRenderbuffers(1, &d->depth_stencil_buffer);
826 GLuint fbo = d->fbo();
827 glDeleteFramebuffers(1, &fbo);
828 }
829}
830
831/*!
832 \fn bool QGLFramebufferObject::isValid() const
833
834 Returns true if the framebuffer object is valid.
835
836 The framebuffer can become invalid if the initialization process
837 fails, the user attaches an invalid buffer to the framebuffer
838 object, or a non-power of two width/height is specified as the
839 texture size if the texture target is \c{GL_TEXTURE_2D}.
840 The non-power of two limitation does not apply if the OpenGL version
841 is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension
842 is present.
843
844 The framebuffer can also become invalid if the QGLContext that
845 the framebuffer was created within is destroyed and there are
846 no other shared contexts that can take over ownership of the
847 framebuffer.
848*/
849bool QGLFramebufferObject::isValid() const
850{
851 Q_D(const QGLFramebufferObject);
852 return d->valid && d->fbo_guard.context();
853}
854
855/*!
856 \fn bool QGLFramebufferObject::bind()
857
858 Switches rendering from the default, windowing system provided
859 framebuffer to this framebuffer object.
860 Returns true upon success, false otherwise.
861
862 \sa release()
863*/
864bool QGLFramebufferObject::bind()
865{
866 if (!isValid())
867 return false;
868 Q_D(QGLFramebufferObject);
869 QGL_FUNC_CONTEXT;
870 if (!ctx)
871 return false; // Context no longer exists.
872 const QGLContext *current = QGLContext::currentContext();
873#ifdef QT_DEBUG
874 if (!current ||
875 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
876 {
877 qWarning("QGLFramebufferObject::bind() called from incompatible context");
878 }
879#endif
880 glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo());
881 d->valid = d->checkFramebufferStatus();
882 if (d->valid && current)
883 current->d_ptr->current_fbo = d->fbo();
884 return d->valid;
885}
886
887/*!
888 \fn bool QGLFramebufferObject::release()
889
890 Switches rendering back to the default, windowing system provided
891 framebuffer.
892 Returns true upon success, false otherwise.
893
894 \sa bind()
895*/
896bool QGLFramebufferObject::release()
897{
898 if (!isValid())
899 return false;
900 QGL_FUNC_CONTEXT;
901 if (!ctx)
902 return false; // Context no longer exists.
903
904 const QGLContext *current = QGLContext::currentContext();
905
906#ifdef QT_DEBUG
907 if (!current ||
908 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
909 {
910 qWarning("QGLFramebufferObject::release() called from incompatible context");
911 }
912#endif
913
914 if (current) {
915 current->d_ptr->current_fbo = current->d_ptr->default_fbo;
916 glBindFramebuffer(GL_FRAMEBUFFER_EXT, current->d_ptr->default_fbo);
917 }
918
919 return true;
920}
921
922/*!
923 \fn GLuint QGLFramebufferObject::texture() const
924
925 Returns the texture id for the texture attached as the default
926 rendering target in this framebuffer object. This texture id can
927 be bound as a normal texture in your own GL code.
928
929 If a multisample framebuffer object is used then the value returned
930 from this function will be invalid.
931*/
932GLuint QGLFramebufferObject::texture() const
933{
934 Q_D(const QGLFramebufferObject);
935 return d->texture;
936}
937
938/*!
939 \fn QSize QGLFramebufferObject::size() const
940
941 Returns the size of the texture attached to this framebuffer
942 object.
943*/
944QSize QGLFramebufferObject::size() const
945{
946 Q_D(const QGLFramebufferObject);
947 return d->size;
948}
949
950/*!
951 Returns the format of this framebuffer object.
952*/
953QGLFramebufferObjectFormat QGLFramebufferObject::format() const
954{
955 Q_D(const QGLFramebufferObject);
956 return d->format;
957}
958
959/*!
960 \fn QImage QGLFramebufferObject::toImage() const
961
962 Returns the contents of this framebuffer object as a QImage.
963*/
964QImage QGLFramebufferObject::toImage() const
965{
966 Q_D(const QGLFramebufferObject);
967 if (!d->valid)
968 return QImage();
969
970 // qt_gl_read_framebuffer doesn't work on a multisample FBO
971 if (format().samples() != 0) {
972 QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
973
974 QRect rect(QPoint(0, 0), size());
975 blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
976
977 return temp.toImage();
978 }
979
980 bool wasBound = isBound();
981 if (!wasBound)
982 const_cast<QGLFramebufferObject *>(this)->bind();
983 QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
984 if (!wasBound)
985 const_cast<QGLFramebufferObject *>(this)->release();
986
987 return image;
988}
989
990#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
991Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
992#endif
993
994#ifndef QT_OPENGL_ES_2
995Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
996#endif
997
998/*! \reimp */
999QPaintEngine *QGLFramebufferObject::paintEngine() const
1000{
1001 Q_D(const QGLFramebufferObject);
1002 if (d->engine)
1003 return d->engine;
1004
1005#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
1006#if !defined (QT_OPENGL_ES_2)
1007 if (qt_gl_preferGL2Engine()) {
1008#endif
1009 QPaintEngine *engine = qt_buffer_2_engine();
1010 if (engine->isActive() && engine->paintDevice() != this) {
1011 d->engine = new QGL2PaintEngineEx;
1012 return d->engine;
1013 }
1014 return engine;
1015#if !defined (QT_OPENGL_ES_2)
1016 }
1017#endif
1018#endif
1019
1020#if !defined(QT_OPENGL_ES_2)
1021 QPaintEngine *engine = qt_buffer_engine();
1022 if (engine->isActive() && engine->paintDevice() != this) {
1023 d->engine = new QOpenGLPaintEngine;
1024 return d->engine;
1025 }
1026 return engine;
1027#endif
1028}
1029
1030/*!
1031 \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1032
1033 Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension
1034 is present on this system; otherwise returns false.
1035*/
1036bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1037{
1038 return (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
1039}
1040
1041/*!
1042 \since 4.4
1043
1044 Draws the given texture, \a textureId, to the given target rectangle,
1045 \a target, in OpenGL model space. The \a textureTarget should be a 2D
1046 texture target.
1047
1048 The framebuffer object should be bound when calling this function.
1049
1050 Equivalent to the corresponding QGLContext::drawTexture().
1051*/
1052void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
1053{
1054 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
1055}
1056
1057#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
1058/*! \internal */
1059void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
1060{
1061 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
1062}
1063#endif
1064
1065/*!
1066 \since 4.4
1067
1068 Draws the given texture, \a textureId, at the given \a point in OpenGL
1069 model space. The \a textureTarget should be a 2D texture target.
1070
1071 The framebuffer object should be bound when calling this function.
1072
1073 Equivalent to the corresponding QGLContext::drawTexture().
1074*/
1075void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
1076{
1077 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
1078}
1079
1080#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
1081/*! \internal */
1082void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
1083{
1084 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
1085}
1086#endif
1087
1088extern int qt_defaultDpiX();
1089extern int qt_defaultDpiY();
1090
1091/*! \reimp */
1092int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
1093{
1094 Q_D(const QGLFramebufferObject);
1095
1096 float dpmx = qt_defaultDpiX()*100./2.54;
1097 float dpmy = qt_defaultDpiY()*100./2.54;
1098 int w = d->size.width();
1099 int h = d->size.height();
1100 switch (metric) {
1101 case PdmWidth:
1102 return w;
1103
1104 case PdmHeight:
1105 return h;
1106
1107 case PdmWidthMM:
1108 return qRound(w * 1000 / dpmx);
1109
1110 case PdmHeightMM:
1111 return qRound(h * 1000 / dpmy);
1112
1113 case PdmNumColors:
1114 return 0;
1115
1116 case PdmDepth:
1117 return 32;//d->depth;
1118
1119 case PdmDpiX:
1120 return qRound(dpmx * 0.0254);
1121
1122 case PdmDpiY:
1123 return qRound(dpmy * 0.0254);
1124
1125 case PdmPhysicalDpiX:
1126 return qRound(dpmx * 0.0254);
1127
1128 case PdmPhysicalDpiY:
1129 return qRound(dpmy * 0.0254);
1130
1131 default:
1132 qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
1133 break;
1134 }
1135 return 0;
1136}
1137
1138/*!
1139 \fn GLuint QGLFramebufferObject::handle() const
1140
1141 Returns the GL framebuffer object handle for this framebuffer
1142 object (returned by the \c{glGenFrameBuffersEXT()} function). This
1143 handle can be used to attach new images or buffers to the
1144 framebuffer. The user is responsible for cleaning up and
1145 destroying these objects.
1146*/
1147GLuint QGLFramebufferObject::handle() const
1148{
1149 Q_D(const QGLFramebufferObject);
1150 return d->fbo();
1151}
1152
1153/*! \fn int QGLFramebufferObject::devType() const
1154 \internal
1155*/
1156
1157
1158/*!
1159 Returns the status of the depth and stencil buffers attached to
1160 this framebuffer object.
1161*/
1162
1163QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
1164{
1165 Q_D(const QGLFramebufferObject);
1166 if (d->valid)
1167 return d->fbo_attachment;
1168 return NoAttachment;
1169}
1170
1171/*!
1172 \since 4.5
1173
1174 Returns true if the framebuffer object is currently bound to a context,
1175 otherwise false is returned.
1176*/
1177
1178bool QGLFramebufferObject::isBound() const
1179{
1180 Q_D(const QGLFramebufferObject);
1181 const QGLContext *current = QGLContext::currentContext();
1182 return current ? current->d_ptr->current_fbo == d->fbo() : false;
1183}
1184
1185/*!
1186 \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1187
1188 \since 4.6
1189
1190 Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
1191 is present on this system; otherwise returns false.
1192
1193 \sa blitFramebuffer()
1194*/
1195bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1196{
1197 return (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit);
1198}
1199
1200/*!
1201 \since 4.6
1202
1203 Blits from the \a sourceRect rectangle in the \a source framebuffer
1204 object to the \a targetRect rectangle in the \a target framebuffer object.
1205
1206 If \a source or \a target is 0, the default framebuffer will be used
1207 instead of a framebuffer object as source or target respectively.
1208
1209 The \a buffers parameter should be a mask consisting of any combination of
1210 \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
1211 \c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both
1212 in the source and target buffers is ignored.
1213
1214 The \a sourceRect and \a targetRect rectangles may have different sizes;
1215 in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or
1216 \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to
1217 \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest
1218 interpolation should be used when scaling is performed.
1219
1220 If \a source equals \a target a copy is performed within the same buffer.
1221 Results are undefined if the source and target rectangles overlap and
1222 have different sizes. The sizes must also be the same if any of the
1223 framebuffer objects are multisample framebuffers.
1224
1225 Note that the scissor test will restrict the blit area if enabled.
1226
1227 This function will have no effect unless hasOpenGLFramebufferBlit() returns
1228 true.
1229
1230 \sa hasOpenGLFramebufferBlit()
1231*/
1232void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
1233 QGLFramebufferObject *source, const QRect &sourceRect,
1234 GLbitfield buffers,
1235 GLenum filter)
1236{
1237 if (!(QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit))
1238 return;
1239
1240 const QGLContext *ctx = QGLContext::currentContext();
1241 if (!ctx)
1242 return;
1243
1244 const int height = ctx->device()->height();
1245
1246 const int sh = source ? source->height() : height;
1247 const int th = target ? target->height() : height;
1248
1249 const int sx0 = sourceRect.left();
1250 const int sx1 = sourceRect.left() + sourceRect.width();
1251 const int sy0 = sh - (sourceRect.top() + sourceRect.height());
1252 const int sy1 = sh - sourceRect.top();
1253
1254 const int tx0 = targetRect.left();
1255 const int tx1 = targetRect.left() + targetRect.width();
1256 const int ty0 = th - (targetRect.top() + targetRect.height());
1257 const int ty1 = th - targetRect.top();
1258
1259 glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0);
1260 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0);
1261
1262 glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
1263 tx0, ty0, tx1, ty1,
1264 buffers, filter);
1265
1266 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
1267}
1268
1269QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.