1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/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 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
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
70class 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
81QT_BEGIN_NAMESPACE
82
83class QGLContext;
84class QGLOverlayWidget;
85class QPixmap;
86class QPixmapFilter;
87#ifdef Q_WS_MAC
88# ifdef qDebug
89# define old_qDebug qDebug
90# undef qDebug
91# endif
92QT_BEGIN_INCLUDE_NAMESPACE
93#ifndef QT_MAC_USE_COCOA
94# include <AGL/agl.h>
95#endif
96QT_END_INCLUDE_NAMESPACE
97# ifdef old_qDebug
98# undef qDebug
99# define qDebug QT_NO_QDEBUG_MACRO
100# undef old_qDebug
101# endif
102class QMacWindowChangeEvent;
103#endif
104
105#ifdef Q_WS_QWS
106class QWSGLWindowSurface;
107#endif
108
109#ifdef Q_OS_SYMBIAN
110extern bool qt_initializing_gl_share_widget();
111#endif
112
113#ifndef QT_NO_EGL
114class QEglContext;
115#endif
116
117QT_BEGIN_INCLUDE_NAMESPACE
118#include <QtOpenGL/private/qglextensions_p.h>
119QT_END_INCLUDE_NAMESPACE
120
121class QGLFormatPrivate
122{
123public:
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 }
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
172class QGLWidgetPrivate : public QWidgetPrivate
173{
174 Q_DECLARE_PUBLIC(QGLWidget)
175public:
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
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();
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
240class QGLContextGroupResourceBase;
241class QGLSharedResourceGuard;
242
243// QGLContextPrivate has the responsibility of creating context groups.
244// QGLContextPrivate maintains the reference counter and destroys
245// context groups when needed.
246class QGLContextGroup
247{
248public:
249 ~QGLContextGroup();
250
251 QGLExtensionFuncs &extensionFuncs() {return m_extensionFuncs;}
252 const QGLContext *context() const {return m_context;}
253 bool isSharing() const { return m_shares.size() >= 2; }
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
262private:
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.
281Q_OPENGL_EXPORT const QGLContext *qt_gl_transfer_context(const QGLContext *);
282
283// GL extension definitions
284class QGLExtensions {
285public:
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*/
328class QGLTemporaryContextPrivate;
329class QGLTemporaryContext {
330public:
331 QGLTemporaryContext(bool directRendering = true, QWidget *parent = 0);
332 ~QGLTemporaryContext();
333
334private:
335 QScopedPointer<QGLTemporaryContextPrivate> d;
336};
337
338class QGLTexture;
339class 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
345class QGLContextResourceBase;
346
347class QGLContextPrivate
348{
349 Q_DECLARE_PUBLIC(QGLContext)
350public:
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
464 static inline QGLContextGroup *contextGroup(const QGLContext *ctx) { return ctx->d_ptr->group; }
465
466#ifdef Q_WS_WIN
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
478Q_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.
483class Q_OPENGL_EXPORT QGLShareContextScope
484{
485public:
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
515private:
516 QGLContext *m_oldContext;
517 QGLContext *m_ctx;
518};
519
520class QGLTextureDestroyer : public QObject
521{
522 Q_OBJECT
523public:
524 QGLTextureDestroyer() : QObject() {
525 qRegisterMetaType<GLuint>("GLuint");
526 connect(this, SIGNAL(freeTexture(QGLContext *, QPixmapData *, GLuint)),
527 this, SLOT(freeTexture_slot(QGLContext *, QPixmapData *, GLuint)));
528 }
529 void emitFreeTexture(QGLContext *context, QPixmapData *boundPixmap, GLuint id) {
530 emit freeTexture(context, boundPixmap, id);
531 }
532
533Q_SIGNALS:
534 void freeTexture(QGLContext *context, QPixmapData *boundPixmap, GLuint id);
535
536private slots:
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
560class Q_OPENGL_EXPORT QGLSignalProxy : public QObject
561{
562 Q_OBJECT
563public:
564 void emitAboutToDestroyContext(const QGLContext *context) {
565 emit aboutToDestroyContext(context);
566 }
567 static QGLSignalProxy *instance();
568Q_SIGNALS:
569 void aboutToDestroyContext(const QGLContext *context);
570};
571
572class QGLTexture {
573public:
574 QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D,
575 QGLContext::BindOptions opt = QGLContext::DefaultBindOption)
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
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
640struct QGLTextureCacheKey {
641 qint64 key;
642 QGLContextGroup *group;
643};
644
645inline bool operator==(const QGLTextureCacheKey &a, const QGLTextureCacheKey &b)
646{
647 return a.key == b.key && a.group == b.group;
648}
649
650inline uint qHash(const QGLTextureCacheKey &key)
651{
652 return qHash(key.key) ^ qHash(key.group);
653}
654
655
656class Q_AUTOTEST_EXPORT QGLTextureCache {
657public:
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
675private:
676 QCache<QGLTextureCacheKey, QGLTexture> m_cache;
677 QReadWriteLock m_lock;
678};
679
680int QGLTextureCache::size() {
681 QReadLocker locker(&m_lock);
682 return m_cache.size();
683}
684
685void QGLTextureCache::setMaxCost(int newMax)
686{
687 QWriteLocker locker(&m_lock);
688 m_cache.setMaxCost(newMax);
689}
690
691int QGLTextureCache::maxCost()
692{
693 QReadLocker locker(&m_lock);
694 return m_cache.maxCost();
695}
696
697QGLTexture* 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
705extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine();
706
707bool qt_gl_preferGL2Engine();
708
709inline GLenum qt_gl_preferredTextureFormat()
710{
711 return (QGLExtensions::glExtensions() & QGLExtensions::BGRATextureFormat) && QSysInfo::ByteOrder == QSysInfo::LittleEndian
712 ? GL_BGRA : GL_RGBA;
713}
714
715inline 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*/
730class Q_OPENGL_EXPORT QGLContextGroupResourceBase
731{
732public:
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
742protected:
743 QList<QGLContextGroup *> m_groups;
744
745private:
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*/
760template <class T>
761class QGLContextGroupResource : public QGLContextGroupResourceBase
762{
763public:
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
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
784protected:
785 void freeResource(void *resource) {
786 delete reinterpret_cast<T *>(resource);
787 }
788};
789
790/*
791 Base for resources that are context specific.
792*/
793class Q_OPENGL_EXPORT QGLContextResourceBase
794{
795public:
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
801 void insert(const QGLContext *context, void *value) {
802 context->d_ptr->m_resources.insert(this, value);
803 }
804
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
810protected:
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*/
823template <class T>
824class QGLContextResource : public QGLContextResourceBase
825{
826public:
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
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
847protected:
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.
858class Q_OPENGL_EXPORT QGLSharedResourceGuard
859{
860public:
861 QGLSharedResourceGuard(const QGLContext *context)
862 : m_group(0), m_id(0), m_next(0), m_prev(0)
863 {
864 setContext(context);
865 }
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
873 const QGLContext *context() const
874 {
875 return m_group ? m_group->context() : 0;
876 }
877
878 void setContext(const QGLContext *context);
879
880 GLuint id() const
881 {
882 return m_id;
883 }
884
885 void setId(GLuint id)
886 {
887 m_id = id;
888 }
889
890private:
891 QGLContextGroup *m_group;
892 GLuint m_id;
893 QGLSharedResourceGuard *m_next;
894 QGLSharedResourceGuard *m_prev;
895
896 friend class QGLContextGroup;
897};
898
899
900class QGLExtensionMatcher
901{
902public:
903 QGLExtensionMatcher(const char *str);
904 QGLExtensionMatcher();
905
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
921private:
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
932template <class T>
933class QGLEngineThreadStorage
934{
935public:
936 QPaintEngine *engine() {
937 QPaintEngine *&localEngine = storage.localData();
938 if (!localEngine)
939 localEngine = new T;
940 return localEngine;
941 }
942
943private:
944 QThreadStorage<QPaintEngine *> storage;
945};
946QT_END_NAMESPACE
947
948#endif // QGL_P_H
949