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

Last change on this file since 967 was 846, checked in by Dmitry A. Kuminov, 14 years ago

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

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