1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #ifndef QGL_P_H
43 #define QGL_P_H
44 
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists for the convenience
50 // of the QGLWidget class.  This header file may change from
51 // version to version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55 
56 #include "QtOpenGL/qgl.h"
57 #include "QtOpenGL/qglcolormap.h"
58 #include "QtCore/qmap.h"
59 #include "QtCore/qthread.h"
60 #include "QtCore/qthreadstorage.h"
61 #include "QtCore/qhash.h"
62 #include "QtCore/qatomic.h"
63 #include "private/qwidget_p.h"
64 #include "qcache.h"
65 #include "qglpaintdevice_p.h"
66 
67 #ifdef Q_OS_SYMBIAN
68 #include "qgltexturepool_p.h"
69 
70 class QGLPixmapData;
71 #endif
72 
73 #ifndef QT_NO_EGL
74 #include <QtGui/private/qegl_p.h>
75 #endif
76 
77 #if defined(Q_WS_QPA)
78 #include <QtGui/QPlatformGLContext>
79 #endif
80 
81 QT_BEGIN_NAMESPACE
82 
83 class QGLContext;
84 class QGLOverlayWidget;
85 class QPixmap;
86 class QPixmapFilter;
87 #ifdef Q_WS_MAC
88 # ifdef qDebug
89 #   define old_qDebug qDebug
90 #   undef qDebug
91 # endif
92 QT_BEGIN_INCLUDE_NAMESPACE
93 #ifndef QT_MAC_USE_COCOA
94 # include <AGL/agl.h>
95 #endif
96 QT_END_INCLUDE_NAMESPACE
97 # ifdef old_qDebug
98 #   undef qDebug
99 #   define qDebug QT_NO_QDEBUG_MACRO
100 #   undef old_qDebug
101 # endif
102 class QMacWindowChangeEvent;
103 #endif
104 
105 #ifdef Q_WS_QWS
106 class QWSGLWindowSurface;
107 #endif
108 
109 #ifdef Q_OS_SYMBIAN
110 extern bool qt_initializing_gl_share_widget();
111 #endif
112 
113 #ifndef QT_NO_EGL
114 class QEglContext;
115 #endif
116 
117 QT_BEGIN_INCLUDE_NAMESPACE
118 #include <QtOpenGL/private/qglextensions_p.h>
119 QT_END_INCLUDE_NAMESPACE
120 
121 class QGLFormatPrivate
122 {
123 public:
QGLFormatPrivate()124     QGLFormatPrivate()
125         : ref(1)
126     {
127         opts = QGL::DoubleBuffer | QGL::DepthBuffer | QGL::Rgba | QGL::DirectRendering
128              | QGL::StencilBuffer | QGL::DeprecatedFunctions;
129         pln = 0;
130         depthSize = accumSize = stencilSize = redSize = greenSize = blueSize = alphaSize = -1;
131         numSamples = -1;
132         swapInterval = -1;
133         majorVersion = 1;
134         minorVersion = 0;
135         profile = QGLFormat::NoProfile;
136     }
QGLFormatPrivate(const QGLFormatPrivate * other)137     QGLFormatPrivate(const QGLFormatPrivate *other)
138         : ref(1),
139           opts(other->opts),
140           pln(other->pln),
141           depthSize(other->depthSize),
142           accumSize(other->accumSize),
143           stencilSize(other->stencilSize),
144           redSize(other->redSize),
145           greenSize(other->greenSize),
146           blueSize(other->blueSize),
147           alphaSize(other->alphaSize),
148           numSamples(other->numSamples),
149           swapInterval(other->swapInterval),
150           majorVersion(other->majorVersion),
151           minorVersion(other->minorVersion),
152           profile(other->profile)
153     {
154     }
155     QAtomicInt ref;
156     QGL::FormatOptions opts;
157     int pln;
158     int depthSize;
159     int accumSize;
160     int stencilSize;
161     int redSize;
162     int greenSize;
163     int blueSize;
164     int alphaSize;
165     int numSamples;
166     int swapInterval;
167     int majorVersion;
168     int minorVersion;
169     QGLFormat::OpenGLContextProfile profile;
170 };
171 
172 class QGLWidgetPrivate : public QWidgetPrivate
173 {
Q_DECLARE_PUBLIC(QGLWidget)174     Q_DECLARE_PUBLIC(QGLWidget)
175 public:
176     QGLWidgetPrivate() : QWidgetPrivate()
177                        , disable_clear_on_painter_begin(false)
178 #if defined(Q_WS_QWS)
179                        , wsurf(0)
180 #endif
181 #if defined(Q_WS_X11) && !defined(QT_NO_EGL)
182                        , eglSurfaceWindowId(0)
183 #endif
184 #if defined(Q_OS_SYMBIAN)
185                        , eglSurfaceWindowId(0)
186                        , surfaceSizeInitialized(false)
187 #endif
188     {
189         isGLWidget = 1;
190 #if defined(Q_OS_SYMBIAN)
191         if (qt_initializing_gl_share_widget())
192             isGLGlobalShareWidget = 1;
193 #endif
194     }
195 
~QGLWidgetPrivate()196     ~QGLWidgetPrivate() {}
197 
198     void init(QGLContext *context, const QGLWidget* shareWidget);
199     void initContext(QGLContext *context, const QGLWidget* shareWidget);
200     bool renderCxPm(QPixmap *pixmap);
201     void cleanupColormaps();
aboutToDestroy()202     void aboutToDestroy() {
203         if (glcx)
204             glcx->reset();
205     }
206 
207     QGLContext *glcx;
208     QGLWidgetGLPaintDevice glDevice;
209     bool autoSwap;
210 
211     QGLColormap cmap;
212 #ifndef QT_OPENGL_ES
213     QMap<QString, int> displayListCache;
214 #endif
215 
216     bool disable_clear_on_painter_begin;
217 
218 #if defined(Q_WS_WIN)
219     void updateColormap();
220     QGLContext *olcx;
221 #elif defined(Q_WS_X11)
222     QGLOverlayWidget *olw;
223 #ifndef QT_NO_EGL
224     void recreateEglSurface();
225     WId eglSurfaceWindowId;
226 #endif
227 #elif defined(Q_WS_MAC)
228     QGLContext *olcx;
229     void updatePaintDevice();
230 #elif defined(Q_WS_QWS)
231     QWSGLWindowSurface *wsurf;
232 #endif
233 #ifdef Q_OS_SYMBIAN
234     void recreateEglSurface();
235     WId eglSurfaceWindowId;
236     bool surfaceSizeInitialized : 1;
237 #endif
238 };
239 
240 class QGLContextGroupResourceBase;
241 class QGLSharedResourceGuard;
242 
243 // QGLContextPrivate has the responsibility of creating context groups.
244 // QGLContextPrivate maintains the reference counter and destroys
245 // context groups when needed.
246 class QGLContextGroup
247 {
248 public:
249     ~QGLContextGroup();
250 
extensionFuncs()251     QGLExtensionFuncs &extensionFuncs() {return m_extensionFuncs;}
context()252     const QGLContext *context() const {return m_context;}
isSharing()253     bool isSharing() const { return m_shares.size() >= 2; }
shares()254     QList<const QGLContext *> shares() const { return m_shares; }
255 
256     void addGuard(QGLSharedResourceGuard *guard);
257     void removeGuard(QGLSharedResourceGuard *guard);
258 
259     static void addShare(const QGLContext *context, const QGLContext *share);
260     static void removeShare(const QGLContext *context);
261 
262 private:
263     QGLContextGroup(const QGLContext *context);
264 
265     QGLExtensionFuncs m_extensionFuncs;
266     const QGLContext *m_context; // context group's representative
267     QList<const QGLContext *> m_shares;
268     QHash<QGLContextGroupResourceBase *, void *> m_resources;
269     QGLSharedResourceGuard *m_guards; // double-linked list of active guards.
270     QAtomicInt m_refs;
271 
272     void cleanupResources(const QGLContext *ctx);
273 
274     friend class QGLContext;
275     friend class QGLContextPrivate;
276     friend class QGLContextGroupResourceBase;
277 };
278 
279 // Get the context that resources for "ctx" will transfer to once
280 // "ctx" is destroyed.  Returns null if nothing is sharing with ctx.
281 Q_OPENGL_EXPORT const QGLContext *qt_gl_transfer_context(const QGLContext *);
282 
283 // GL extension definitions
284 class QGLExtensions {
285 public:
286     enum Extension {
287         TextureRectangle        = 0x00000001,
288         SampleBuffers           = 0x00000002,
289         GenerateMipmap          = 0x00000004,
290         TextureCompression      = 0x00000008,
291         FragmentProgram         = 0x00000010,
292         MirroredRepeat          = 0x00000020,
293         FramebufferObject       = 0x00000040,
294         StencilTwoSide          = 0x00000080,
295         StencilWrap             = 0x00000100,
296         PackedDepthStencil      = 0x00000200,
297         NVFloatBuffer           = 0x00000400,
298         PixelBufferObject       = 0x00000800,
299         FramebufferBlit         = 0x00001000,
300         NPOTTextures            = 0x00002000,
301         BGRATextureFormat       = 0x00004000,
302         DDSTextureCompression   = 0x00008000,
303         ETC1TextureCompression  = 0x00010000,
304         PVRTCTextureCompression = 0x00020000,
305         FragmentShader          = 0x00040000,
306         ElementIndexUint        = 0x00080000,
307         Depth24                 = 0x00100000,
308         SRGBFrameBuffer         = 0x00200000
309     };
310     Q_DECLARE_FLAGS(Extensions, Extension)
311 
312     static Extensions glExtensions();
313     static Extensions currentContextExtensions();
314 };
315 
316 /*
317     QGLTemporaryContext - the main objective of this class is to have a way of
318     creating a GL context and making it current, without going via QGLWidget
319     and friends. At certain points during GL initialization we need a current
320     context in order decide what GL features are available, and to resolve GL
321     extensions. Having a light-weight way of creating such a context saves
322     initial application startup time, and it doesn't wind up creating recursive
323     conflicts.
324     The class currently uses a private d pointer to hide the platform specific
325     types. This could possibly been done inline with #ifdef'ery, but it causes
326     major headaches on e.g. X11 due to namespace pollution.
327 */
328 class QGLTemporaryContextPrivate;
329 class QGLTemporaryContext {
330 public:
331     QGLTemporaryContext(bool directRendering = true, QWidget *parent = 0);
332     ~QGLTemporaryContext();
333 
334 private:
335     QScopedPointer<QGLTemporaryContextPrivate> d;
336 };
337 
338 class QGLTexture;
339 class QGLTextureDestroyer;
340 
341 // This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's
342 // all the GL2 engine uses:
343 #define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3
344 
345 class QGLContextResourceBase;
346 
347 class QGLContextPrivate
348 {
349     Q_DECLARE_PUBLIC(QGLContext)
350 public:
351     explicit QGLContextPrivate(QGLContext *context);
352     ~QGLContextPrivate();
353     QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format,
354                             QGLContext::BindOptions options);
355     QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
356                             QGLContext::BindOptions options);
357     QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
358                             QGLContext::BindOptions options);
359     QGLTexture *textureCacheLookup(const qint64 key, GLenum target);
360     void init(QPaintDevice *dev, const QGLFormat &format);
361     QImage convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format);
362     int maxTextureSize();
363 
364     void cleanup();
365 
366     void setVertexAttribArrayEnabled(int arrayIndex, bool enabled = true);
367     void syncGlState(); // Makes sure the GL context's state is what we think it is
368     void swapRegion(const QRegion &region);
369 
370 #if defined(Q_WS_WIN)
371     void updateFormatVersion();
372 #endif
373 
374 #if defined(Q_WS_WIN)
375     HGLRC rc;
376     HDC dc;
377     WId        win;
378     int pixelFormatId;
379     QGLCmap* cmap;
380     HBITMAP hbitmap;
381     HDC hbitmap_hdc;
382     Qt::HANDLE threadId;
383 #endif
384 #ifndef QT_NO_EGL
385     QEglContext *eglContext;
386     EGLSurface eglSurface;
387     void destroyEglSurfaceForDevice();
388     EGLSurface eglSurfaceForDevice() const;
389     static QEglProperties *extraWindowSurfaceCreationProps;
390     static void setExtraWindowSurfaceCreationProps(QEglProperties *props);
391 #endif
392 
393 #if defined(Q_WS_QPA)
394     QPlatformGLContext *platformContext;
395     void setupSharing();
396 
397 #elif defined(Q_WS_X11) || defined(Q_WS_MAC)
398     void* cx;
399 #endif
400 #if defined(Q_WS_X11) || defined(Q_WS_MAC)
401     void* vi;
402 #endif
403 #if defined(Q_WS_X11)
404     void* pbuf;
405     quint32 gpm;
406     int screen;
407     QHash<QPixmapData*, QPixmap> boundPixmaps;
408     QGLTexture *bindTextureFromNativePixmap(QPixmap*, const qint64 key,
409                                             QGLContext::BindOptions options);
410     static void destroyGlSurfaceForPixmap(QPixmapData*);
411     static void unbindPixmapFromTexture(QPixmapData*);
412 #endif
413 #if defined(Q_WS_MAC)
414     bool update;
415     void *tryFormat(const QGLFormat &format);
416     void clearDrawable();
417 #endif
418     QGLFormat glFormat;
419     QGLFormat reqFormat;
420     GLuint fbo;
421 
422     uint valid : 1;
423     uint sharing : 1;
424     uint initDone : 1;
425     uint crWin : 1;
426     uint internal_context : 1;
427     uint version_flags_cached : 1;
428     uint extension_flags_cached : 1;
429 
430     // workarounds for driver/hw bugs on different platforms
431     uint workaround_needsFullClearOnEveryFrame : 1;
432     uint workaround_brokenFBOReadBack : 1;
433     uint workaround_brokenTexSubImage : 1;
434     uint workaroundsCached : 1;
435 
436     uint workaround_brokenTextureFromPixmap : 1;
437     uint workaround_brokenTextureFromPixmap_init : 1;
438 
439     uint workaround_brokenScissor : 1;
440     uint workaround_brokenAlphaTexSubImage : 1;
441     uint workaround_brokenAlphaTexSubImage_init : 1;
442 
443 #ifndef QT_NO_EGL
444     uint ownsEglContext : 1;
445 #endif
446 
447     QPaintDevice *paintDevice;
448     QColor transpColor;
449     QGLContext *q_ptr;
450     QGLFormat::OpenGLVersionFlags version_flags;
451     QGLExtensions::Extensions extension_flags;
452 
453     QGLContextGroup *group;
454     GLint max_texture_size;
455 
456     GLuint current_fbo;
457     GLuint default_fbo;
458     QPaintEngine *active_engine;
459     QHash<QGLContextResourceBase *, void *> m_resources;
460     QGLTextureDestroyer *texture_destroyer;
461 
462     bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT];
463 
contextGroup(const QGLContext * ctx)464     static inline QGLContextGroup *contextGroup(const QGLContext *ctx) { return ctx->d_ptr->group; }
465 
466 #ifdef Q_WS_WIN
extensionFuncs(const QGLContext * ctx)467     static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *ctx) { return ctx->d_ptr->group->extensionFuncs(); }
468 #endif
469 
470 #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN)
471     static Q_OPENGL_EXPORT QGLExtensionFuncs qt_extensionFuncs;
472     static Q_OPENGL_EXPORT QGLExtensionFuncs& extensionFuncs(const QGLContext *);
473 #endif
474 
475     static void setCurrentContext(QGLContext *context);
476 };
477 
Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions)478 Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions)
479 
480 // Temporarily make a context current if not already current or
481 // shared with the current contex.  The previous context is made
482 // current when the object goes out of scope.
483 class Q_OPENGL_EXPORT QGLShareContextScope
484 {
485 public:
486     QGLShareContextScope(const QGLContext *ctx)
487         : m_oldContext(0)
488     {
489         QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
490         if (currentContext != ctx && !QGLContext::areSharing(ctx, currentContext)) {
491             m_oldContext = currentContext;
492             m_ctx = const_cast<QGLContext *>(ctx);
493             m_ctx->makeCurrent();
494         } else {
495             m_ctx = currentContext;
496         }
497     }
498 
499     operator QGLContext *()
500     {
501         return m_ctx;
502     }
503 
504     QGLContext *operator->()
505     {
506         return m_ctx;
507     }
508 
509     ~QGLShareContextScope()
510     {
511         if (m_oldContext)
512             m_oldContext->makeCurrent();
513     }
514 
515 private:
516     QGLContext *m_oldContext;
517     QGLContext *m_ctx;
518 };
519 
520 class QGLTextureDestroyer : public QObject
521 {
522     Q_OBJECT
523 public:
QGLTextureDestroyer()524     QGLTextureDestroyer() : QObject() {
525         qRegisterMetaType<GLuint>("GLuint");
526         connect(this, SIGNAL(freeTexture(QGLContext *, QPixmapData *, GLuint)),
527                 this, SLOT(freeTexture_slot(QGLContext *, QPixmapData *, GLuint)));
528     }
emitFreeTexture(QGLContext * context,QPixmapData * boundPixmap,GLuint id)529     void emitFreeTexture(QGLContext *context, QPixmapData *boundPixmap, GLuint id) {
530         emit freeTexture(context, boundPixmap, id);
531     }
532 
533 Q_SIGNALS:
534     void freeTexture(QGLContext *context, QPixmapData *boundPixmap, GLuint id);
535 
536 private slots:
freeTexture_slot(QGLContext * context,QPixmapData * boundPixmap,GLuint id)537     void freeTexture_slot(QGLContext *context, QPixmapData *boundPixmap, GLuint id) {
538         Q_UNUSED(boundPixmap);
539 #if defined(Q_WS_X11)
540         if (boundPixmap) {
541             QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
542             context->makeCurrent();
543             // Although glXReleaseTexImage is a glX call, it must be called while there
544             // is a current context - the context the pixmap was bound to a texture in.
545             // Otherwise the release doesn't do anything and you get BadDrawable errors
546             // when you come to delete the context.
547             QGLContextPrivate::unbindPixmapFromTexture(boundPixmap);
548             glDeleteTextures(1, &id);
549             if (oldContext)
550                 oldContext->makeCurrent();
551             return;
552         }
553 #endif
554         QGLShareContextScope scope(context);
555         glDeleteTextures(1, &id);
556     }
557 };
558 
559 // ### make QGLContext a QObject in 5.0 and remove the proxy stuff
560 class Q_OPENGL_EXPORT QGLSignalProxy : public QObject
561 {
562     Q_OBJECT
563 public:
emitAboutToDestroyContext(const QGLContext * context)564     void emitAboutToDestroyContext(const QGLContext *context) {
565         emit aboutToDestroyContext(context);
566     }
567     static QGLSignalProxy *instance();
568 Q_SIGNALS:
569     void aboutToDestroyContext(const QGLContext *context);
570 };
571 
572 class QGLTexture {
573 public:
574     QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D,
575                QGLContext::BindOptions opt = QGLContext::DefaultBindOption)
context(ctx)576         : context(ctx),
577           id(tx_id),
578           target(tx_target),
579           options(opt)
580 #if defined(Q_WS_X11)
581         , boundPixmap(0)
582 #elif defined(Q_OS_SYMBIAN)
583         , boundPixmap(0)
584         , boundKey(0)
585         , nextLRU(0)
586         , prevLRU(0)
587         , inLRU(false)
588         , failedToAlloc(false)
589         , inTexturePool(false)
590 #endif
591     {}
592 
~QGLTexture()593     ~QGLTexture() {
594 #ifdef Q_OS_SYMBIAN
595         freeTexture();
596 #else
597         if (options & QGLContext::MemoryManagedBindOption) {
598             Q_ASSERT(context);
599 #if !defined(Q_WS_X11)
600             QPixmapData *boundPixmap = 0;
601 #endif
602             context->d_ptr->texture_destroyer->emitFreeTexture(context, boundPixmap, id);
603         }
604 #endif
605     }
606 
607     QGLContext *context;
608     GLuint id;
609     GLenum target;
610 
611     QGLContext::BindOptions options;
612 
613 #if defined(Q_WS_X11)
614     QPixmapData* boundPixmap;
615 #endif
616 
617     bool canBindCompressedTexture
618         (const char *buf, int len, const char *format, bool *hasAlpha);
619     QSize bindCompressedTexture
620         (const QString& fileName, const char *format = 0);
621     QSize bindCompressedTexture
622         (const char *buf, int len, const char *format = 0);
623     QSize bindCompressedTextureDDS(const char *buf, int len);
624     QSize bindCompressedTexturePVR(const char *buf, int len);
625 
626 #ifdef Q_OS_SYMBIAN
627     void freeTexture();
628 
629     QGLPixmapData* boundPixmap;
630     qint64 boundKey;
631 
632     QGLTexture *nextLRU;
633     QGLTexture *prevLRU;
634     mutable bool inLRU;
635     mutable bool failedToAlloc;
636     mutable bool inTexturePool;
637 #endif
638 };
639 
640 struct QGLTextureCacheKey {
641     qint64 key;
642     QGLContextGroup *group;
643 };
644 
645 inline bool operator==(const QGLTextureCacheKey &a, const QGLTextureCacheKey &b)
646 {
647     return a.key == b.key && a.group == b.group;
648 }
649 
qHash(const QGLTextureCacheKey & key)650 inline uint qHash(const QGLTextureCacheKey &key)
651 {
652     return qHash(key.key) ^ qHash(key.group);
653 }
654 
655 
656 class Q_AUTOTEST_EXPORT QGLTextureCache {
657 public:
658     QGLTextureCache();
659     ~QGLTextureCache();
660 
661     void insert(QGLContext *ctx, qint64 key, QGLTexture *texture, int cost);
662     void remove(qint64 key);
663     inline int size();
664     inline void setMaxCost(int newMax);
665     inline int maxCost();
666     inline QGLTexture* getTexture(QGLContext *ctx, qint64 key);
667 
668     bool remove(QGLContext *ctx, GLuint textureId);
669     void removeContextTextures(QGLContext *ctx);
670     static QGLTextureCache *instance();
671     static void cleanupTexturesForCacheKey(qint64 cacheKey);
672     static void cleanupTexturesForPixampData(QPixmapData* pixmap);
673     static void cleanupBeforePixmapDestruction(QPixmapData* pixmap);
674 
675 private:
676     QCache<QGLTextureCacheKey, QGLTexture> m_cache;
677     QReadWriteLock m_lock;
678 };
679 
size()680 int QGLTextureCache::size() {
681     QReadLocker locker(&m_lock);
682     return m_cache.size();
683 }
684 
setMaxCost(int newMax)685 void QGLTextureCache::setMaxCost(int newMax)
686 {
687     QWriteLocker locker(&m_lock);
688     m_cache.setMaxCost(newMax);
689 }
690 
maxCost()691 int QGLTextureCache::maxCost()
692 {
693     QReadLocker locker(&m_lock);
694     return m_cache.maxCost();
695 }
696 
getTexture(QGLContext * ctx,qint64 key)697 QGLTexture* QGLTextureCache::getTexture(QGLContext *ctx, qint64 key)
698 {
699     // Can't be a QReadLocker since QCache::object() modifies the cache (reprioritizes the object)
700     QWriteLocker locker(&m_lock);
701     const QGLTextureCacheKey cacheKey = {key, QGLContextPrivate::contextGroup(ctx)};
702     return m_cache.object(cacheKey);
703 }
704 
705 extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine();
706 
707 bool qt_gl_preferGL2Engine();
708 
qt_gl_preferredTextureFormat()709 inline GLenum qt_gl_preferredTextureFormat()
710 {
711     return (QGLExtensions::glExtensions() & QGLExtensions::BGRATextureFormat) && QSysInfo::ByteOrder == QSysInfo::LittleEndian
712         ? GL_BGRA : GL_RGBA;
713 }
714 
qt_gl_preferredTextureTarget()715 inline GLenum qt_gl_preferredTextureTarget()
716 {
717 #if defined(QT_OPENGL_ES_2)
718     return GL_TEXTURE_2D;
719 #else
720     return (QGLExtensions::glExtensions() & QGLExtensions::TextureRectangle)
721            && !qt_gl_preferGL2Engine()
722            ? GL_TEXTURE_RECTANGLE_NV
723            : GL_TEXTURE_2D;
724 #endif
725 }
726 
727 /*
728    Base for resources that are shared in a context group.
729 */
730 class Q_OPENGL_EXPORT QGLContextGroupResourceBase
731 {
732 public:
733     QGLContextGroupResourceBase();
734     virtual ~QGLContextGroupResourceBase();
735     void insert(const QGLContext *context, void *value);
736     void *value(const QGLContext *context);
737     void cleanup(const QGLContext *context);
738     void cleanup(const QGLContext *context, void *value);
739     virtual void freeResource(void *value) = 0;
740     virtual void contextDeleted(const QGLContext *ctx);
741 
742 protected:
743     QList<QGLContextGroup *> m_groups;
744 
745 private:
746     QAtomicInt active;
747 };
748 
749 /*
750    The QGLContextGroupResource template is used to manage a resource
751    for a group of sharing GL contexts. When the last context in the
752    group is destroyed, or when the QGLContextGroupResource object
753    itself is destroyed (implies potential context switches), the
754    resource will be freed.
755 
756    The class used as the template class type needs to have a
757    constructor with the following signature:
758      T(const QGLContext *);
759 */
760 template <class T>
761 class QGLContextGroupResource : public QGLContextGroupResourceBase
762 {
763 public:
~QGLContextGroupResource()764     ~QGLContextGroupResource() {
765         for (int i = 0; i < m_groups.size(); ++i) {
766             const QGLContext *context = m_groups.at(i)->context();
767             T *resource = reinterpret_cast<T *>(QGLContextGroupResourceBase::value(context));
768             if (resource) {
769                 QGLShareContextScope scope(context);
770                 delete resource;
771             }
772         }
773     }
774 
value(const QGLContext * context)775     T *value(const QGLContext *context) {
776         T *resource = reinterpret_cast<T *>(QGLContextGroupResourceBase::value(context));
777         if (!resource) {
778             resource = new T(context);
779             insert(context, resource);
780         }
781         return resource;
782     }
783 
784 protected:
freeResource(void * resource)785     void freeResource(void *resource) {
786         delete reinterpret_cast<T *>(resource);
787     }
788 };
789 
790 /*
791    Base for resources that are context specific.
792 */
793 class Q_OPENGL_EXPORT QGLContextResourceBase
794 {
795 public:
~QGLContextResourceBase()796     virtual ~QGLContextResourceBase() {
797         for (int i = 0; i < m_contexts.size(); ++i)
798             m_contexts.at(i)->d_ptr->m_resources.remove(this);
799     }
800 
insert(const QGLContext * context,void * value)801     void insert(const QGLContext *context, void *value) {
802         context->d_ptr->m_resources.insert(this, value);
803     }
804 
value(const QGLContext * context)805     void *value(const QGLContext *context) {
806         return context->d_ptr->m_resources.value(this, 0);
807     }
808     virtual void freeResource(void *value) = 0;
809 
810 protected:
811     QList<const QGLContext *> m_contexts;
812 };
813 
814 /*
815    The QGLContextResource template is used to manage a resource for a
816    single GL context. Just before the context is destroyed (while it's
817    still the current context), or when the QGLContextResource object
818    itself is destroyed (implies potential context switches), the
819    resource will be freed.  The class used as the template class type
820    needs to have a constructor with the following signature: T(const
821    QGLContext *);
822 */
823 template <class T>
824 class QGLContextResource : public QGLContextResourceBase
825 {
826 public:
~QGLContextResource()827     ~QGLContextResource() {
828         for (int i = 0; i < m_contexts.size(); ++i) {
829             const QGLContext *context = m_contexts.at(i);
830             T *resource = reinterpret_cast<T *>(QGLContextResourceBase::value(context));
831             if (resource) {
832                 QGLShareContextScope scope(context);
833                 delete resource;
834             }
835         }
836     }
837 
value(const QGLContext * context)838     T *value(const QGLContext *context) {
839         T *resource = reinterpret_cast<T *>(QGLContextResourceBase::value(context));
840         if (!resource) {
841             resource = new T(context);
842             insert(context, resource);
843         }
844         return resource;
845     }
846 
847 protected:
freeResource(void * resource)848     void freeResource(void *resource) {
849         delete reinterpret_cast<T *>(resource);
850     }
851 };
852 
853 // Put a guard around a GL object identifier and its context.
854 // When the context goes away, a shared context will be used
855 // in its place.  If there are no more shared contexts, then
856 // the identifier is returned as zero - it is assumed that the
857 // context destruction cleaned up the identifier in this case.
858 class Q_OPENGL_EXPORT QGLSharedResourceGuard
859 {
860 public:
QGLSharedResourceGuard(const QGLContext * context)861     QGLSharedResourceGuard(const QGLContext *context)
862         : m_group(0), m_id(0), m_next(0), m_prev(0)
863     {
864         setContext(context);
865     }
QGLSharedResourceGuard(const QGLContext * context,GLuint id)866     QGLSharedResourceGuard(const QGLContext *context, GLuint id)
867         : m_group(0), m_id(id), m_next(0), m_prev(0)
868     {
869         setContext(context);
870     }
871     ~QGLSharedResourceGuard();
872 
context()873     const QGLContext *context() const
874     {
875         return m_group ? m_group->context() : 0;
876     }
877 
878     void setContext(const QGLContext *context);
879 
id()880     GLuint id() const
881     {
882         return m_id;
883     }
884 
setId(GLuint id)885     void setId(GLuint id)
886     {
887         m_id = id;
888     }
889 
890 private:
891     QGLContextGroup *m_group;
892     GLuint m_id;
893     QGLSharedResourceGuard *m_next;
894     QGLSharedResourceGuard *m_prev;
895 
896     friend class QGLContextGroup;
897 };
898 
899 
900 class QGLExtensionMatcher
901 {
902 public:
903     QGLExtensionMatcher(const char *str);
904     QGLExtensionMatcher();
905 
match(const char * str)906     bool match(const char *str) const {
907         int str_length = qstrlen(str);
908 
909         Q_ASSERT(str);
910         Q_ASSERT(str_length > 0);
911         Q_ASSERT(str[str_length-1] != ' ');
912 
913         for (int i = 0; i < m_offsets.size(); ++i) {
914             const char *extension = m_extensions.constData() + m_offsets.at(i);
915             if (qstrncmp(extension, str, str_length) == 0 && extension[str_length] == ' ')
916                 return true;
917         }
918         return false;
919     }
920 
921 private:
922     void init(const char *str);
923 
924     QByteArray m_extensions;
925     QVector<int> m_offsets;
926 };
927 
928 
929 // this is a class that wraps a QThreadStorage object for storing
930 // thread local instances of the GL 1 and GL 2 paint engines
931 
932 template <class T>
933 class QGLEngineThreadStorage
934 {
935 public:
engine()936     QPaintEngine *engine() {
937         QPaintEngine *&localEngine = storage.localData();
938         if (!localEngine)
939             localEngine = new T;
940         return localEngine;
941     }
942 
943 private:
944     QThreadStorage<QPaintEngine *> storage;
945 };
946 QT_END_NAMESPACE
947 
948 #endif // QGL_P_H
949