1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qglframebufferobject.h"
41 #include "qglframebufferobject_p.h"
42 
43 #include <qdebug.h>
44 #include <private/qgl_p.h>
45 #include <private/qfont_p.h>
46 #include "gl2paintengineex/qpaintengineex_opengl2_p.h"
47 
48 #include <qimage.h>
49 #include <qwindow.h>
50 
51 QT_BEGIN_NAMESPACE
52 
53 extern QImage qt_gl_read_frame_buffer(const QSize&, bool, bool);
54 
55 #define QGL_FUNC_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
56 #define QGL_FUNCP_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
57 
58 #ifndef QT_NO_DEBUG
59 #define QT_RESET_GLERROR()                                \
60 {                                                         \
61     while (QOpenGLContext::currentContext()->functions()->glGetError() != GL_NO_ERROR) {} \
62 }
63 #define QT_CHECK_GLERROR()                                \
64 {                                                         \
65     GLenum err = QOpenGLContext::currentContext()->functions()->glGetError(); \
66     if (err != GL_NO_ERROR) {                             \
67         qDebug("[%s line %d] GL Error: %d",               \
68                __FILE__, __LINE__, (int)err);             \
69     }                                                     \
70 }
71 #else
72 #define QT_RESET_GLERROR() {}
73 #define QT_CHECK_GLERROR() {}
74 #endif
75 
76 // ####TODO Properly #ifdef this class to use #define symbols actually defined
77 // by OpenGL/ES includes
78 #ifndef GL_MAX_SAMPLES
79 #define GL_MAX_SAMPLES 0x8D57
80 #endif
81 
82 #ifndef GL_RENDERBUFFER_SAMPLES
83 #define GL_RENDERBUFFER_SAMPLES 0x8CAB
84 #endif
85 
86 #ifndef GL_DEPTH24_STENCIL8
87 #define GL_DEPTH24_STENCIL8 0x88F0
88 #endif
89 
90 #ifndef GL_DEPTH_COMPONENT24
91 #define GL_DEPTH_COMPONENT24 0x81A6
92 #endif
93 
94 #ifndef GL_DEPTH_COMPONENT24_OES
95 #define GL_DEPTH_COMPONENT24_OES 0x81A6
96 #endif
97 
98 #ifndef GL_READ_FRAMEBUFFER
99 #define GL_READ_FRAMEBUFFER 0x8CA8
100 #endif
101 
102 #ifndef GL_DRAW_FRAMEBUFFER
103 #define GL_DRAW_FRAMEBUFFER 0x8CA9
104 #endif
105 
106 #ifndef GL_DEPTH_STENCIL_ATTACHMENT
107 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
108 #endif
109 
110 #ifndef GL_DEPTH_STENCIL
111 #define GL_DEPTH_STENCIL 0x84F9
112 #endif
113 
114 /*!
115     \class QGLFramebufferObjectFormat
116     \inmodule QtOpenGL
117     \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL
118     framebuffer object.
119 
120     \since 4.6
121     \obsolete
122 
123     \ingroup painting-3D
124 
125     A framebuffer object has several characteristics:
126     \list
127     \li \l{setSamples()}{Number of samples per pixels.}
128     \li \l{setAttachment()}{Depth and/or stencil attachments.}
129     \li \l{setTextureTarget()}{Texture target.}
130     \li \l{setInternalTextureFormat()}{Internal texture format.}
131     \endlist
132 
133     Note that the desired attachments or number of samples per pixels might not
134     be supported by the hardware driver. Call QGLFramebufferObject::format()
135     after creating a QGLFramebufferObject to find the exact format that was
136     used to create the frame buffer object.
137 
138     \note This class has been deprecated in favor of QOpenGLFramebufferObjectFormat.
139 
140     \sa QGLFramebufferObject
141 */
142 
143 /*!
144     \internal
145 */
detach()146 void QGLFramebufferObjectFormat::detach()
147 {
148     if (d->ref.loadRelaxed() != 1) {
149         QGLFramebufferObjectFormatPrivate *newd
150             = new QGLFramebufferObjectFormatPrivate(d);
151         if (!d->ref.deref())
152             delete d;
153         d = newd;
154     }
155 }
156 
157 /*!
158     Creates a QGLFramebufferObjectFormat object for specifying
159     the format of an OpenGL framebuffer object.
160 
161     By default the format specifies a non-multisample framebuffer object with no
162     attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8.
163     On OpenGL/ES systems, the default internal format is \c GL_RGBA.
164 
165     \sa samples(), attachment(), internalTextureFormat()
166 */
167 
QGLFramebufferObjectFormat()168 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat()
169 {
170     d = new QGLFramebufferObjectFormatPrivate;
171 }
172 
173 /*!
174     Constructs a copy of \a other.
175 */
176 
QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat & other)177 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other)
178 {
179     d = other.d;
180     d->ref.ref();
181 }
182 
183 /*!
184     Assigns \a other to this object.
185 */
186 
operator =(const QGLFramebufferObjectFormat & other)187 QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other)
188 {
189     if (d != other.d) {
190         other.d->ref.ref();
191         if (!d->ref.deref())
192             delete d;
193         d = other.d;
194     }
195     return *this;
196 }
197 
198 /*!
199     Destroys the QGLFramebufferObjectFormat.
200 */
~QGLFramebufferObjectFormat()201 QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
202 {
203     if (!d->ref.deref())
204         delete d;
205 }
206 
207 /*!
208     Sets the number of samples per pixel for a multisample framebuffer object
209     to \a samples.  The default sample count of 0 represents a regular
210     non-multisample framebuffer object.
211 
212     If the desired amount of samples per pixel is not supported by the hardware
213     then the maximum number of samples per pixel will be used. Note that
214     multisample framebuffer objects cannot be bound as textures. Also, the
215     \c{GL_EXT_framebuffer_multisample} extension is required to create a
216     framebuffer with more than one sample per pixel.
217 
218     \sa samples()
219 */
setSamples(int samples)220 void QGLFramebufferObjectFormat::setSamples(int samples)
221 {
222     detach();
223     d->samples = samples;
224 }
225 
226 /*!
227     Returns the number of samples per pixel if a framebuffer object
228     is a multisample framebuffer object. Otherwise, returns 0.
229     The default value is 0.
230 
231     \sa setSamples()
232 */
samples() const233 int QGLFramebufferObjectFormat::samples() const
234 {
235     return d->samples;
236 }
237 
238 /*!
239     \since 4.8
240 
241     Enables mipmapping if \a enabled is true; otherwise disables it.
242 
243     Mipmapping is disabled by default.
244 
245     If mipmapping is enabled, additional memory will be allocated for
246     the mipmap levels. The mipmap levels can be updated by binding the
247     texture and calling glGenerateMipmap(). Mipmapping cannot be enabled
248     for multisampled framebuffer objects.
249 
250     \sa mipmap(), QGLFramebufferObject::texture()
251 */
setMipmap(bool enabled)252 void QGLFramebufferObjectFormat::setMipmap(bool enabled)
253 {
254     detach();
255     d->mipmap = enabled;
256 }
257 
258 /*!
259     \since 4.8
260 
261     Returns \c true if mipmapping is enabled.
262 
263     \sa setMipmap()
264 */
mipmap() const265 bool QGLFramebufferObjectFormat::mipmap() const
266 {
267     return d->mipmap;
268 }
269 
270 /*!
271     Sets the attachment configuration of a framebuffer object to \a attachment.
272 
273     \sa attachment()
274 */
setAttachment(QGLFramebufferObject::Attachment attachment)275 void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment)
276 {
277     detach();
278     d->attachment = attachment;
279 }
280 
281 /*!
282     Returns the configuration of the depth and stencil buffers attached to
283     a framebuffer object.  The default is QGLFramebufferObject::NoAttachment.
284 
285     \sa setAttachment()
286 */
attachment() const287 QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const
288 {
289     return d->attachment;
290 }
291 
292 /*!
293     Sets the texture target of the texture attached to a framebuffer object to
294     \a target. Ignored for multisample framebuffer objects.
295 
296     \sa textureTarget(), samples()
297 */
setTextureTarget(GLenum target)298 void QGLFramebufferObjectFormat::setTextureTarget(GLenum target)
299 {
300     detach();
301     d->target = target;
302 }
303 
304 /*!
305     Returns the texture target of the texture attached to a framebuffer object.
306     Ignored for multisample framebuffer objects.  The default is
307     \c GL_TEXTURE_2D.
308 
309     \sa setTextureTarget(), samples()
310 */
textureTarget() const311 GLenum QGLFramebufferObjectFormat::textureTarget() const
312 {
313     return d->target;
314 }
315 
316 /*!
317     Sets the internal format of a framebuffer object's texture or
318     multisample framebuffer object's color buffer to
319     \a internalTextureFormat.
320 
321     \sa internalTextureFormat()
322 */
setInternalTextureFormat(GLenum internalTextureFormat)323 void QGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat)
324 {
325     detach();
326     d->internal_format = internalTextureFormat;
327 }
328 
329 /*!
330     Returns the internal format of a framebuffer object's texture or
331     multisample framebuffer object's color buffer.  The default is
332     \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on
333     OpenGL/ES systems.
334 
335     \sa setInternalTextureFormat()
336 */
internalTextureFormat() const337 GLenum QGLFramebufferObjectFormat::internalTextureFormat() const
338 {
339     return d->internal_format;
340 }
341 
342 /*!
343     Returns \c true if all the options of this framebuffer object format
344     are the same as \a other; otherwise returns \c false.
345 */
operator ==(const QGLFramebufferObjectFormat & other) const346 bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const
347 {
348     if (d == other.d)
349         return true;
350     else
351         return d->equals(other.d);
352 }
353 
354 /*!
355     Returns \c false if all the options of this framebuffer object format
356     are the same as \a other; otherwise returns \c true.
357 */
operator !=(const QGLFramebufferObjectFormat & other) const358 bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const
359 {
360     return !(*this == other);
361 }
362 
setFBO(QGLFramebufferObject * f,QGLFramebufferObject::Attachment attachment)363 void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
364                                  QGLFramebufferObject::Attachment attachment)
365 {
366     fbo = f;
367     m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed
368 
369     // The context that the fbo was created in may not have depth
370     // and stencil buffers, but the fbo itself might.
371     fboFormat = QGLContext::currentContext()->format();
372     if (attachment == QGLFramebufferObject::CombinedDepthStencil) {
373         fboFormat.setDepth(true);
374         fboFormat.setStencil(true);
375     } else if (attachment == QGLFramebufferObject::Depth) {
376         fboFormat.setDepth(true);
377         fboFormat.setStencil(false);
378     } else {
379         fboFormat.setDepth(false);
380         fboFormat.setStencil(false);
381     }
382 
383     GLenum format = f->format().internalTextureFormat();
384     reqAlpha = (format != GL_RGB
385 #ifdef GL_RGB5
386                 && format != GL_RGB5
387 #endif
388 #ifdef GL_RGB8
389                 && format != GL_RGB8
390 #endif
391     );
392 }
393 
context() const394 QGLContext *QGLFBOGLPaintDevice::context() const
395 {
396     return const_cast<QGLContext *>(QGLContext::currentContext());
397 }
398 
checkFramebufferStatus() const399 bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
400 {
401     QGL_FUNCP_CONTEXT;
402     if (!ctx)
403         return false;   // Context no longer exists.
404     GLenum status = ctx->contextHandle()->functions()->glCheckFramebufferStatus(GL_FRAMEBUFFER);
405     switch(status) {
406     case GL_NO_ERROR:
407     case GL_FRAMEBUFFER_COMPLETE:
408         return true;
409     case GL_FRAMEBUFFER_UNSUPPORTED:
410         qDebug("QGLFramebufferObject: Unsupported framebuffer format.");
411         break;
412     case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
413         qDebug("QGLFramebufferObject: Framebuffer incomplete attachment.");
414         break;
415     case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
416         qDebug("QGLFramebufferObject: Framebuffer incomplete, missing attachment.");
417         break;
418 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT
419     case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT:
420         qDebug("QGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
421         break;
422 #endif
423 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
424     case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
425         qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
426         break;
427 #endif
428 #ifdef GL_FRAMEBUFFER_INCOMPLETE_FORMATS
429     case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
430         qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
431         break;
432 #endif
433 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
434     case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
435         qDebug("QGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
436         break;
437 #endif
438 #ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
439     case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
440         qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
441         break;
442 #endif
443 #ifdef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
444     case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
445         qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
446         break;
447 #endif
448     default:
449         qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
450         break;
451     }
452     return false;
453 }
454 
455 namespace
456 {
freeFramebufferFunc(QGLContext * ctx,GLuint id)457     void freeFramebufferFunc(QGLContext *ctx, GLuint id)
458     {
459         Q_ASSERT(ctx);
460         ctx->contextHandle()->functions()->glDeleteFramebuffers(1, &id);
461     }
462 
freeRenderbufferFunc(QGLContext * ctx,GLuint id)463     void freeRenderbufferFunc(QGLContext *ctx, GLuint id)
464     {
465         Q_ASSERT(ctx);
466         ctx->contextHandle()->functions()->glDeleteRenderbuffers(1, &id);
467     }
468 
freeTextureFunc(QGLContext * ctx,GLuint id)469     void freeTextureFunc(QGLContext *ctx, GLuint id)
470     {
471         Q_UNUSED(ctx);
472         ctx->contextHandle()->functions()->glDeleteTextures(1, &id);
473     }
474 }
475 
init(QGLFramebufferObject * q,const QSize & sz,QGLFramebufferObject::Attachment attachment,GLenum texture_target,GLenum internal_format,GLint samples,bool mipmap)476 void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
477                                        QGLFramebufferObject::Attachment attachment,
478                                        GLenum texture_target, GLenum internal_format,
479                                        GLint samples, bool mipmap)
480 {
481     QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
482 
483     funcs.initializeOpenGLFunctions();
484 
485     if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers))
486         return;
487 
488     ctx->d_ptr->refreshCurrentFbo();
489 
490     size = sz;
491     target = texture_target;
492     // texture dimensions
493 
494     QT_RESET_GLERROR(); // reset error state
495     GLuint fbo = 0;
496     funcs.glGenFramebuffers(1, &fbo);
497     funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo);
498 
499     GLuint texture = 0;
500     GLuint color_buffer = 0;
501     GLuint depth_buffer = 0;
502     GLuint stencil_buffer = 0;
503 
504     QT_CHECK_GLERROR();
505     // init texture
506     if (samples == 0) {
507         funcs.glGenTextures(1, &texture);
508         funcs.glBindTexture(target, texture);
509         funcs.glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
510                            GL_RGBA, GL_UNSIGNED_BYTE, NULL);
511         if (mipmap) {
512             int width = size.width();
513             int height = size.height();
514             int level = 0;
515             while (width > 1 || height > 1) {
516                 width = qMax(1, width >> 1);
517                 height = qMax(1, height >> 1);
518                 ++level;
519                 funcs.glTexImage2D(target, level, internal_format, width, height, 0,
520                                    GL_RGBA, GL_UNSIGNED_BYTE, NULL);
521             }
522         }
523         funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
524         funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
525         funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
526         funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
527         funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
528                 target, texture, 0);
529 
530         QT_CHECK_GLERROR();
531         valid = checkFramebufferStatus();
532         funcs.glBindTexture(target, 0);
533 
534         color_buffer = 0;
535     } else {
536         mipmap = false;
537         GLint maxSamples;
538         funcs.glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
539 
540         samples = qBound(0, int(samples), int(maxSamples));
541 
542         funcs.glGenRenderbuffers(1, &color_buffer);
543         funcs.glBindRenderbuffer(GL_RENDERBUFFER, color_buffer);
544         if (funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) && samples > 0) {
545             funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
546                 internal_format, size.width(), size.height());
547         } else {
548             samples = 0;
549             funcs.glRenderbufferStorage(GL_RENDERBUFFER, internal_format,
550                 size.width(), size.height());
551         }
552 
553         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
554                                      GL_RENDERBUFFER, color_buffer);
555 
556         QT_CHECK_GLERROR();
557         valid = checkFramebufferStatus();
558 
559         if (valid)
560             funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
561     }
562 
563     // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a
564     // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer
565     // might not be supported while separate buffers are, according to QTBUG-12861.
566 
567     if (attachment == QGLFramebufferObject::CombinedDepthStencil
568         && funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil)) {
569         // depth and stencil buffer needs another extension
570         funcs.glGenRenderbuffers(1, &depth_buffer);
571         funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
572         Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
573 #ifndef Q_OS_WASM
574         if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
575             funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
576                 GL_DEPTH24_STENCIL8, size.width(), size.height());
577         else
578             funcs.glRenderbufferStorage(GL_RENDERBUFFER,
579                 GL_DEPTH24_STENCIL8, size.width(), size.height());
580 
581         stencil_buffer = depth_buffer;
582         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
583                                      GL_RENDERBUFFER, depth_buffer);
584         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
585                                      GL_RENDERBUFFER, stencil_buffer);
586 #else
587         // webgl does not allow separate depth and stencil attachments
588         if (samples != 0) {
589             funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
590                                                    GL_DEPTH_STENCIL, size.width(), size.height());
591         } else {
592             funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL,
593                                         size.width(), size.height());
594         }
595         stencil_buffer = depth_buffer;
596         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
597                                         GL_RENDERBUFFER, depth_buffer);
598 #endif
599 
600         valid = checkFramebufferStatus();
601         if (!valid) {
602             funcs.glDeleteRenderbuffers(1, &depth_buffer);
603             stencil_buffer = depth_buffer = 0;
604         }
605     }
606 
607     if (depth_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil
608         || (attachment == QGLFramebufferObject::Depth)))
609     {
610         funcs.glGenRenderbuffers(1, &depth_buffer);
611         funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
612         Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
613         if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
614 #ifdef QT_OPENGL_ES
615             if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) {
616                 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
617                     GL_DEPTH_COMPONENT24_OES, size.width(), size.height());
618             } else {
619                 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
620                     GL_DEPTH_COMPONENT16, size.width(), size.height());
621             }
622 #else
623             if (ctx->contextHandle()->isOpenGLES()) {
624                 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24))
625                     funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
626                                                            GL_DEPTH_COMPONENT24, size.width(), size.height());
627                 else
628                     funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
629                                                            GL_DEPTH_COMPONENT16, size.width(), size.height());
630             } else {
631                 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
632                                                        GL_DEPTH_COMPONENT, size.width(), size.height());
633             }
634 #endif
635         } else {
636 #ifdef QT_OPENGL_ES
637             if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) {
638                 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES,
639                                         size.width(), size.height());
640             } else {
641                 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
642                                         size.width(), size.height());
643             }
644 #else
645             if (ctx->contextHandle()->isOpenGLES()) {
646                 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) {
647                     funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24,
648                                                 size.width(), size.height());
649                 } else {
650                     funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
651                                                 size.width(), size.height());
652                 }
653             } else {
654                 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height());
655             }
656 #endif
657         }
658         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
659                                      GL_RENDERBUFFER, depth_buffer);
660         valid = checkFramebufferStatus();
661         if (!valid) {
662             funcs.glDeleteRenderbuffers(1, &depth_buffer);
663             depth_buffer = 0;
664         }
665     }
666 
667     if (stencil_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil)) {
668         funcs.glGenRenderbuffers(1, &stencil_buffer);
669         funcs.glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer);
670         Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer));
671 
672 #ifdef QT_OPENGL_ES
673         GLenum storage = GL_STENCIL_INDEX8;
674 #else
675         GLenum storage = ctx->contextHandle()->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX;
676 #endif
677 
678         if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
679             funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage, size.width(), size.height());
680         else
681             funcs.glRenderbufferStorage(GL_RENDERBUFFER, storage, size.width(), size.height());
682 
683         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
684                                   GL_RENDERBUFFER, stencil_buffer);
685         valid = checkFramebufferStatus();
686         if (!valid) {
687             funcs.glDeleteRenderbuffers(1, &stencil_buffer);
688             stencil_buffer = 0;
689         }
690     }
691 
692     // The FBO might have become valid after removing the depth or stencil buffer.
693     valid = checkFramebufferStatus();
694 
695     if (depth_buffer && stencil_buffer) {
696         fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
697     } else if (depth_buffer) {
698         fbo_attachment = QGLFramebufferObject::Depth;
699     } else {
700         fbo_attachment = QGLFramebufferObject::NoAttachment;
701     }
702 
703     funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->current_fbo);
704     if (valid) {
705         fbo_guard = createSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
706         if (color_buffer)
707             color_buffer_guard = createSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
708         else
709             texture_guard = createSharedResourceGuard(ctx, texture, freeTextureFunc);
710         if (depth_buffer)
711             depth_buffer_guard = createSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
712         if (stencil_buffer) {
713             if (stencil_buffer == depth_buffer)
714                 stencil_buffer_guard = depth_buffer_guard;
715             else
716                 stencil_buffer_guard = createSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
717         }
718     } else {
719         if (color_buffer)
720             funcs.glDeleteRenderbuffers(1, &color_buffer);
721         else
722             funcs.glDeleteTextures(1, &texture);
723         if (depth_buffer)
724             funcs.glDeleteRenderbuffers(1, &depth_buffer);
725         if (stencil_buffer && depth_buffer != stencil_buffer)
726             funcs.glDeleteRenderbuffers(1, &stencil_buffer);
727         funcs.glDeleteFramebuffers(1, &fbo);
728     }
729     QT_CHECK_GLERROR();
730 
731     format.setTextureTarget(target);
732     format.setSamples(int(samples));
733     format.setAttachment(fbo_attachment);
734     format.setInternalTextureFormat(internal_format);
735     format.setMipmap(mipmap);
736 
737     glDevice.setFBO(q, attachment);
738 }
739 
740 /*!
741     \class QGLFramebufferObject
742     \inmodule QtOpenGL
743     \brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
744     \since 4.2
745 
746     \obsolete
747 
748     \ingroup painting-3D
749 
750     The QGLFramebufferObject class encapsulates an OpenGL framebuffer
751     object, defined by the \c{GL_EXT_framebuffer_object} extension. In
752     addition it provides a rendering surface that can be painted on
753     with a QPainter, rendered to using native GL calls, or both. This
754     surface can be bound and used as a regular texture in your own GL
755     drawing code.  By default, the QGLFramebufferObject class
756     generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target),
757     which is used as the internal rendering target.
758 
759     \b{It is important to have a current GL context when creating a
760     QGLFramebufferObject, otherwise initialization will fail.}
761 
762     OpenGL framebuffer objects and pbuffers (see
763     \l{QGLPixelBuffer}{QGLPixelBuffer}) can both be used to render to
764     offscreen surfaces, but there are a number of advantages with
765     using framebuffer objects instead of pbuffers:
766 
767     \list 1
768     \li A framebuffer object does not require a separate rendering
769     context, so no context switching will occur when switching
770     rendering targets. There is an overhead involved in switching
771     targets, but in general it is cheaper than a context switch to a
772     pbuffer.
773 
774     \li Rendering to dynamic textures (i.e. render-to-texture
775     functionality) works on all platforms. No need to do explicit copy
776     calls from a render buffer into a texture, as was necessary on
777     systems that did not support the \c{render_texture} extension.
778 
779     \li It is possible to attach several rendering buffers (or texture
780     objects) to the same framebuffer object, and render to all of them
781     without doing a context switch.
782 
783     \li The OpenGL framebuffer extension is a pure GL extension with no
784     system dependant WGL, CGL, or GLX parts. This makes using
785     framebuffer objects more portable.
786     \endlist
787 
788     When using a QPainter to paint to a QGLFramebufferObject you should take
789     care that the QGLFramebufferObject is created with the CombinedDepthStencil
790     attachment for QPainter to be able to render correctly.
791     Note that you need to create a QGLFramebufferObject with more than one
792     sample per pixel for primitives to be antialiased when drawing using a
793     QPainter. To create a multisample framebuffer object you should use one of
794     the constructors that take a QGLFramebufferObjectFormat parameter, and set
795     the QGLFramebufferObjectFormat::samples() property to a non-zero value.
796 
797     When painting to a QGLFramebufferObject using QPainter, the state of
798     the current GL context will be altered by the paint engine to reflect
799     its needs.  Applications should not rely upon the GL state being reset
800     to its original conditions, particularly the current shader program,
801     GL viewport, texture units, and drawing modes.
802 
803     For multisample framebuffer objects a color render buffer is created,
804     otherwise a texture with the specified texture target is created.
805     The color render buffer or texture will have the specified internal
806     format, and will be bound to the \c GL_COLOR_ATTACHMENT0
807     attachment in the framebuffer object.
808 
809     If you want to use a framebuffer object with multisampling enabled
810     as a texture, you first need to copy from it to a regular framebuffer
811     object using QGLContext::blitFramebuffer().
812 
813     \section1 Threading
814 
815     As of Qt 4.8, it's possible to draw into a QGLFramebufferObject
816     using a QPainter in a separate thread. Note that OpenGL 2.0 or
817     OpenGL ES 2.0 is required for this to work.
818 
819     \note This class has been deprecated in favor of QOpenGLFramebufferObject.
820 */
821 
822 
823 /*!
824     \enum QGLFramebufferObject::Attachment
825     \since 4.3
826 
827     This enum type is used to configure the depth and stencil buffers
828     attached to the framebuffer object when it is created.
829 
830     \value NoAttachment         No attachment is added to the framebuffer object. Note that the
831                                 OpenGL depth and stencil tests won't work when rendering to a
832                                 framebuffer object without any depth or stencil buffers.
833                                 This is the default value.
834 
835     \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present,
836                                 a combined depth and stencil buffer is attached.
837                                 If the extension is not present, only a depth buffer is attached.
838 
839     \value Depth                A depth buffer is attached to the framebuffer object.
840 
841     \sa attachment()
842 */
843 
844 
845 /*! \fn QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
846 
847     Constructs an OpenGL framebuffer object and binds a 2D GL texture
848     to the buffer of the size \a size. The texture is bound to the
849     \c GL_COLOR_ATTACHMENT0 target in the framebuffer object.
850 
851     The \a target parameter is used to specify the GL texture
852     target. The default target is \c GL_TEXTURE_2D. Keep in mind that
853     \c GL_TEXTURE_2D textures must have a power of 2 width and height
854     (e.g. 256x512), unless you are using OpenGL 2.0 or higher.
855 
856     By default, no depth and stencil buffers are attached. This behavior
857     can be toggled using one of the overloaded constructors.
858 
859     The default internal texture format is \c GL_RGBA8 for desktop
860     OpenGL, and \c GL_RGBA for OpenGL/ES.
861 
862     It is important that you have a current GL context set when
863     creating the QGLFramebufferObject, otherwise the initialization
864     will fail.
865 
866     \sa size(), texture(), attachment()
867 */
868 
QGLFramebufferObject(const QSize & size,GLenum target)869 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
870     : d_ptr(new QGLFramebufferObjectPrivate)
871 {
872     Q_D(QGLFramebufferObject);
873     d->init(this, size, NoAttachment, target,
874 #ifndef QT_OPENGL_ES_2
875             QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8
876 #else
877             GL_RGBA
878 #endif
879         );
880 }
881 
882 /*! \overload
883 
884     Constructs an OpenGL framebuffer object and binds a 2D GL texture
885     to the buffer of the given \a width and \a height.
886 
887     \sa size(), texture()
888 */
QGLFramebufferObject(int width,int height,GLenum target)889 QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
890     : d_ptr(new QGLFramebufferObjectPrivate)
891 {
892     Q_D(QGLFramebufferObject);
893     d->init(this, QSize(width, height), NoAttachment, target,
894 #ifndef QT_OPENGL_ES_2
895             QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8
896 #else
897             GL_RGBA
898 #endif
899         );
900 }
901 
902 /*! \overload
903 
904     Constructs an OpenGL framebuffer object of the given \a size based on the
905     supplied \a format.
906 */
907 
QGLFramebufferObject(const QSize & size,const QGLFramebufferObjectFormat & format)908 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format)
909     : d_ptr(new QGLFramebufferObjectPrivate)
910 {
911     Q_D(QGLFramebufferObject);
912     d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
913             format.samples(), format.mipmap());
914 }
915 
916 /*! \overload
917 
918     Constructs an OpenGL framebuffer object of the given \a width and \a height
919     based on the supplied \a format.
920 */
921 
QGLFramebufferObject(int width,int height,const QGLFramebufferObjectFormat & format)922 QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format)
923     : d_ptr(new QGLFramebufferObjectPrivate)
924 {
925     Q_D(QGLFramebufferObject);
926     d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
927             format.internalTextureFormat(), format.samples(), format.mipmap());
928 }
929 
930 /*! \overload
931 
932     Constructs an OpenGL framebuffer object and binds a texture to the
933     buffer of the given \a width and \a height.
934 
935     The \a attachment parameter describes the depth/stencil buffer
936     configuration, \a target the texture target and \a internal_format
937     the internal texture format. The default texture target is \c
938     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
939     for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
940 
941     \sa size(), texture(), attachment()
942 */
QGLFramebufferObject(int width,int height,Attachment attachment,GLenum target,GLenum internal_format)943 QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
944                                            GLenum target, GLenum internal_format)
945     : d_ptr(new QGLFramebufferObjectPrivate)
946 {
947     Q_D(QGLFramebufferObject);
948     if (!internal_format)
949 #ifdef QT_OPENGL_ES_2
950         internal_format = GL_RGBA;
951 #else
952     internal_format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8;
953 #endif
954     d->init(this, QSize(width, height), attachment, target, internal_format);
955 }
956 
957 /*! \overload
958 
959     Constructs an OpenGL framebuffer object and binds a texture to the
960     buffer of the given \a size.
961 
962     The \a attachment parameter describes the depth/stencil buffer
963     configuration, \a target the texture target and \a internal_format
964     the internal texture format. The default texture target is \c
965     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
966     for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
967 
968     \sa size(), texture(), attachment()
969 */
QGLFramebufferObject(const QSize & size,Attachment attachment,GLenum target,GLenum internal_format)970 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
971                                            GLenum target, GLenum internal_format)
972     : d_ptr(new QGLFramebufferObjectPrivate)
973 {
974     Q_D(QGLFramebufferObject);
975     if (!internal_format)
976 #ifdef QT_OPENGL_ES_2
977         internal_format = GL_RGBA;
978 #else
979         internal_format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8;
980 #endif
981     d->init(this, size, attachment, target, internal_format);
982 }
983 
984 /*!
985     \fn QGLFramebufferObject::~QGLFramebufferObject()
986 
987     Destroys the framebuffer object and frees any allocated resources.
988 */
~QGLFramebufferObject()989 QGLFramebufferObject::~QGLFramebufferObject()
990 {
991     Q_D(QGLFramebufferObject);
992 
993     delete d->engine;
994 
995     if (d->texture_guard)
996         d->texture_guard->free();
997     if (d->color_buffer_guard)
998         d->color_buffer_guard->free();
999     if (d->depth_buffer_guard)
1000         d->depth_buffer_guard->free();
1001     if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard)
1002         d->stencil_buffer_guard->free();
1003     if (d->fbo_guard)
1004         d->fbo_guard->free();
1005 }
1006 
1007 /*!
1008     \fn bool QGLFramebufferObject::isValid() const
1009 
1010     Returns \c true if the framebuffer object is valid.
1011 
1012     The framebuffer can become invalid if the initialization process
1013     fails, the user attaches an invalid buffer to the framebuffer
1014     object, or a non-power of two width/height is specified as the
1015     texture size if the texture target is \c{GL_TEXTURE_2D}.
1016     The non-power of two limitation does not apply if the OpenGL version
1017     is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension
1018     is present.
1019 
1020     The framebuffer can also become invalid if the QGLContext that
1021     the framebuffer was created within is destroyed and there are
1022     no other shared contexts that can take over ownership of the
1023     framebuffer.
1024 */
isValid() const1025 bool QGLFramebufferObject::isValid() const
1026 {
1027     Q_D(const QGLFramebufferObject);
1028     return d->valid && d->fbo_guard && d->fbo_guard->id();
1029 }
1030 
1031 /*!
1032     \fn bool QGLFramebufferObject::bind()
1033 
1034     Switches rendering from the default, windowing system provided
1035     framebuffer to this framebuffer object.
1036     Returns \c true upon success, false otherwise.
1037 
1038     \sa release()
1039 */
bind()1040 bool QGLFramebufferObject::bind()
1041 {
1042     if (!isValid())
1043         return false;
1044     Q_D(QGLFramebufferObject);
1045     QGL_FUNC_CONTEXT;
1046     if (!ctx)
1047         return false;   // Context no longer exists.
1048     const QGLContext *current = QGLContext::currentContext();
1049 #ifdef QT_DEBUG
1050     if (!current ||
1051         QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
1052     {
1053         qWarning("QGLFramebufferObject::bind() called from incompatible context");
1054     }
1055 #endif
1056     d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
1057     d->valid = d->checkFramebufferStatus();
1058     if (d->valid && current)
1059         current->d_ptr->setCurrentFbo(d->fbo());
1060     return d->valid;
1061 }
1062 
1063 /*!
1064     \fn bool QGLFramebufferObject::release()
1065 
1066     Switches rendering back to the default, windowing system provided
1067     framebuffer.
1068     Returns \c true upon success, false otherwise.
1069 
1070     \sa bind()
1071 */
release()1072 bool QGLFramebufferObject::release()
1073 {
1074     if (!isValid())
1075         return false;
1076     Q_D(QGLFramebufferObject);
1077     QGL_FUNC_CONTEXT;
1078     if (!ctx)
1079         return false;   // Context no longer exists.
1080 
1081     const QGLContext *current = QGLContext::currentContext();
1082 
1083 #ifdef QT_DEBUG
1084     if (!current ||
1085         QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
1086     {
1087         qWarning("QGLFramebufferObject::release() called from incompatible context");
1088     }
1089 #endif
1090 
1091     if (current) {
1092         current->d_ptr->setCurrentFbo(current->d_ptr->default_fbo);
1093         d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_ptr->default_fbo);
1094     }
1095 
1096     return true;
1097 }
1098 
1099 /*!
1100     \fn GLuint QGLFramebufferObject::texture() const
1101 
1102     Returns the texture id for the texture attached as the default
1103     rendering target in this framebuffer object. This texture id can
1104     be bound as a normal texture in your own GL code.
1105 
1106     If a multisample framebuffer object is used then the value returned
1107     from this function will be invalid.
1108 */
texture() const1109 GLuint QGLFramebufferObject::texture() const
1110 {
1111     Q_D(const QGLFramebufferObject);
1112     return d->texture_guard ? d->texture_guard->id() : 0;
1113 }
1114 
1115 /*!
1116     \fn QSize QGLFramebufferObject::size() const
1117 
1118     Returns the size of the texture attached to this framebuffer
1119     object.
1120 */
size() const1121 QSize QGLFramebufferObject::size() const
1122 {
1123     Q_D(const QGLFramebufferObject);
1124     return d->size;
1125 }
1126 
1127 /*!
1128     Returns the format of this framebuffer object.
1129 */
format() const1130 QGLFramebufferObjectFormat QGLFramebufferObject::format() const
1131 {
1132     Q_D(const QGLFramebufferObject);
1133     return d->format;
1134 }
1135 
1136 /*!
1137     \fn QImage QGLFramebufferObject::toImage() const
1138 
1139     Returns the contents of this framebuffer object as a QImage.
1140 
1141     The returned image has a format of premultiplied ARGB32 or RGB32. The latter is used
1142     only when internalTextureFormat() is set to \c GL_RGB.
1143 
1144     If the rendering in the framebuffer was not done with premultiplied alpha in mind,
1145     create a wrapper QImage with a non-premultiplied format. This is necessary before
1146     performing operations like QImage::save() because otherwise the image data would get
1147     unpremultiplied, even though it was not premultiplied in the first place. To create
1148     such a wrapper without performing a copy of the pixel data, do the following:
1149 
1150     \code
1151     QImage fboImage(fbo.toImage());
1152     QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32);
1153     \endcode
1154 
1155     On QNX the back buffer is not preserved when a buffer swap occures. So this function
1156     might return old content.
1157 */
toImage() const1158 QImage QGLFramebufferObject::toImage() const
1159 {
1160     Q_D(const QGLFramebufferObject);
1161     if (!d->valid)
1162         return QImage();
1163 
1164     // qt_gl_read_frame_buffer doesn't work on a multisample FBO
1165     if (format().samples() != 0) {
1166         QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
1167 
1168         QRect rect(QPoint(0, 0), size());
1169         blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
1170 
1171         return temp.toImage();
1172     }
1173 
1174     bool wasBound = isBound();
1175     if (!wasBound)
1176         const_cast<QGLFramebufferObject *>(this)->bind();
1177     QImage image = qt_gl_read_frame_buffer(d->size, format().internalTextureFormat() != GL_RGB, true);
1178     if (!wasBound)
1179         const_cast<QGLFramebufferObject *>(this)->release();
1180 
1181     return image;
1182 }
1183 
Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>,qt_buffer_2_engine)1184 Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_buffer_2_engine)
1185 
1186 /*! \reimp */
1187 QPaintEngine *QGLFramebufferObject::paintEngine() const
1188 {
1189     Q_D(const QGLFramebufferObject);
1190     if (d->engine)
1191         return d->engine;
1192 
1193     QPaintEngine *engine = qt_buffer_2_engine()->engine();
1194     if (engine->isActive() && engine->paintDevice() != this) {
1195         d->engine = new QGL2PaintEngineEx;
1196         return d->engine;
1197     }
1198     return engine;
1199 }
1200 
1201 /*!
1202     \fn bool QGLFramebufferObject::bindDefault()
1203 
1204     Switches rendering back to the default, windowing system provided
1205     framebuffer.
1206     Returns \c true upon success, false otherwise.
1207 
1208     \sa bind(), release()
1209 */
bindDefault()1210 bool QGLFramebufferObject::bindDefault()
1211 {
1212     QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
1213 
1214     if (ctx) {
1215         QOpenGLFunctions functions(ctx->contextHandle());
1216         if (!functions.hasOpenGLFeature(QOpenGLFunctions::Framebuffers))
1217             return false;
1218 
1219         ctx->d_ptr->setCurrentFbo(ctx->d_ptr->default_fbo);
1220         functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->default_fbo);
1221 #ifdef QT_DEBUG
1222     } else {
1223         qWarning("QGLFramebufferObject::bindDefault() called without current context.");
1224 #endif
1225     }
1226 
1227     return ctx != 0;
1228 }
1229 
1230 /*!
1231     \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1232 
1233     Returns \c true if the OpenGL \c{GL_EXT_framebuffer_object} extension
1234     is present on this system; otherwise returns \c false.
1235 */
hasOpenGLFramebufferObjects()1236 bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1237 {
1238     return qgl_hasFeature(QOpenGLFunctions::Framebuffers);
1239 }
1240 
1241 /*!
1242     \since 4.4
1243 
1244     Draws the given texture, \a textureId, to the given target rectangle,
1245     \a target, in OpenGL model space. The \a textureTarget should be a 2D
1246     texture target.
1247 
1248     The framebuffer object should be bound when calling this function.
1249 
1250     Equivalent to the corresponding QGLContext::drawTexture().
1251 */
drawTexture(const QRectF & target,GLuint textureId,GLenum textureTarget)1252 void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
1253 {
1254     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
1255 }
1256 
1257 /*!
1258     \since 4.4
1259 
1260     Draws the given texture, \a textureId, at the given \a point in OpenGL
1261     model space. The \a textureTarget should be a 2D texture target.
1262 
1263     The framebuffer object should be bound when calling this function.
1264 
1265     Equivalent to the corresponding QGLContext::drawTexture().
1266 */
drawTexture(const QPointF & point,GLuint textureId,GLenum textureTarget)1267 void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
1268 {
1269     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
1270 }
1271 
1272 /*! \reimp */
metric(PaintDeviceMetric metric) const1273 int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
1274 {
1275     Q_D(const QGLFramebufferObject);
1276 
1277     float dpmx = qt_defaultDpiX()*100./2.54;
1278     float dpmy = qt_defaultDpiY()*100./2.54;
1279     int w = d->size.width();
1280     int h = d->size.height();
1281     switch (metric) {
1282     case PdmWidth:
1283         return w;
1284 
1285     case PdmHeight:
1286         return h;
1287 
1288     case PdmWidthMM:
1289         return qRound(w * 1000 / dpmx);
1290 
1291     case PdmHeightMM:
1292         return qRound(h * 1000 / dpmy);
1293 
1294     case PdmNumColors:
1295         return 0;
1296 
1297     case PdmDepth:
1298         return 32;//d->depth;
1299 
1300     case PdmDpiX:
1301         return qRound(dpmx * 0.0254);
1302 
1303     case PdmDpiY:
1304         return qRound(dpmy * 0.0254);
1305 
1306     case PdmPhysicalDpiX:
1307         return qRound(dpmx * 0.0254);
1308 
1309     case PdmPhysicalDpiY:
1310         return qRound(dpmy * 0.0254);
1311 
1312     case QPaintDevice::PdmDevicePixelRatio:
1313         return 1;
1314 
1315     case QPaintDevice::PdmDevicePixelRatioScaled:
1316         return 1 * QPaintDevice::devicePixelRatioFScale();
1317 
1318     default:
1319         qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
1320         break;
1321     }
1322     return 0;
1323 }
1324 
1325 /*!
1326     \fn GLuint QGLFramebufferObject::handle() const
1327 
1328     Returns the GL framebuffer object handle for this framebuffer
1329     object (returned by the \c{glGenFrameBuffersEXT()} function). This
1330     handle can be used to attach new images or buffers to the
1331     framebuffer. The user is responsible for cleaning up and
1332     destroying these objects.
1333 */
handle() const1334 GLuint QGLFramebufferObject::handle() const
1335 {
1336     Q_D(const QGLFramebufferObject);
1337     return d->fbo();
1338 }
1339 
1340 /*! \fn int QGLFramebufferObject::devType() const
1341     \internal
1342 */
1343 
1344 
1345 /*!
1346     Returns the status of the depth and stencil buffers attached to
1347     this framebuffer object.
1348 */
1349 
attachment() const1350 QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
1351 {
1352     Q_D(const QGLFramebufferObject);
1353     if (d->valid)
1354         return d->fbo_attachment;
1355     return NoAttachment;
1356 }
1357 
1358 /*!
1359     \since 4.5
1360 
1361     Returns \c true if the framebuffer object is currently bound to a context,
1362     otherwise false is returned.
1363 */
1364 
isBound() const1365 bool QGLFramebufferObject::isBound() const
1366 {
1367     Q_D(const QGLFramebufferObject);
1368     const QGLContext *current = QGLContext::currentContext();
1369     if (current) {
1370         current->d_ptr->refreshCurrentFbo();
1371         return current->d_ptr->current_fbo == d->fbo();
1372     }
1373 
1374     return false;
1375 }
1376 
1377 /*!
1378     \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1379 
1380     \since 4.6
1381 
1382     Returns \c true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
1383     is present on this system; otherwise returns \c false.
1384 
1385     \sa blitFramebuffer()
1386 */
hasOpenGLFramebufferBlit()1387 bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1388 {
1389     return QOpenGLExtensions(QOpenGLContext::currentContext()).hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
1390 }
1391 
1392 /*!
1393     \since 4.6
1394 
1395     Blits from the \a sourceRect rectangle in the \a source framebuffer
1396     object to the \a targetRect rectangle in the \a target framebuffer object.
1397 
1398     If \a source or \a target is \nullptr, the default framebuffer will be used
1399     instead of a framebuffer object as source or target respectively.
1400 
1401     The \a buffers parameter should be a mask consisting of any combination of
1402     \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
1403     \c GL_STENCIL_BUFFER_BIT.  Any buffer type that is not present both
1404     in the source and target buffers is ignored.
1405 
1406     The \a sourceRect and \a targetRect rectangles may have different sizes;
1407     in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or
1408     \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to
1409     \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest
1410     interpolation should be used when scaling is performed.
1411 
1412     If \a source equals \a target a copy is performed within the same buffer.
1413     Results are undefined if the source and target rectangles overlap and
1414     have different sizes. The sizes must also be the same if any of the
1415     framebuffer objects are multisample framebuffers.
1416 
1417     Note that the scissor test will restrict the blit area if enabled.
1418 
1419     This function will have no effect unless hasOpenGLFramebufferBlit() returns
1420     true.
1421 
1422     \sa hasOpenGLFramebufferBlit()
1423 */
blitFramebuffer(QGLFramebufferObject * target,const QRect & targetRect,QGLFramebufferObject * source,const QRect & sourceRect,GLbitfield buffers,GLenum filter)1424 void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
1425                                            QGLFramebufferObject *source, const QRect &sourceRect,
1426                                            GLbitfield buffers,
1427                                            GLenum filter)
1428 {
1429     const QGLContext *ctx = QGLContext::currentContext();
1430     if (!ctx || !ctx->contextHandle())
1431         return;
1432 
1433     QOpenGLExtensions functions(ctx->contextHandle());
1434     if (!functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit))
1435         return;
1436 
1437     QSurface *surface = ctx->contextHandle()->surface();
1438 
1439     const int height = static_cast<QWindow *>(surface)->height();
1440 
1441     const int sh = source ? source->height() : height;
1442     const int th = target ? target->height() : height;
1443 
1444     const int sx0 = sourceRect.left();
1445     const int sx1 = sourceRect.left() + sourceRect.width();
1446     const int sy0 = sh - (sourceRect.top() + sourceRect.height());
1447     const int sy1 = sh - sourceRect.top();
1448 
1449     const int tx0 = targetRect.left();
1450     const int tx1 = targetRect.left() + targetRect.width();
1451     const int ty0 = th - (targetRect.top() + targetRect.height());
1452     const int ty1 = th - targetRect.top();
1453 
1454     ctx->d_ptr->refreshCurrentFbo();
1455 
1456     functions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : 0);
1457     functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : 0);
1458 
1459     functions.glBlitFramebuffer(sx0, sy0, sx1, sy1,
1460                          tx0, ty0, tx1, ty1,
1461                          buffers, filter);
1462 
1463     functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->current_fbo);
1464 }
1465 
1466 QT_END_NAMESPACE
1467