source: trunk/src/opengl/qgl_p.h@ 780

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

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

File size: 20.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#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#ifndef QT_OPENGL_ES_1_CL
68#define q_vertexType float
69#define q_vertexTypeEnum GL_FLOAT
70#define f2vt(f) (f)
71#define vt2f(x) (x)
72#define i2vt(i) (float(i))
73#else
74#define FLOAT2X(f) (int( (f) * (65536)))
75#define X2FLOAT(x) (float(x) / 65536.0f)
76#define f2vt(f) FLOAT2X(f)
77#define i2vt(i) ((i)*65536)
78#define vt2f(x) X2FLOAT(x)
79#define q_vertexType GLfixed
80#define q_vertexTypeEnum GL_FIXED
81#endif //QT_OPENGL_ES_1_CL
82
83#if defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2)
84QT_BEGIN_INCLUDE_NAMESPACE
85
86#if defined(QT_OPENGL_ES_2)
87# include <GLES2/gl2.h>
88#endif
89
90#if defined(QT_GLES_EGL)
91# include <GLES/egl.h>
92#else
93# include <EGL/egl.h>
94#endif
95
96QT_END_INCLUDE_NAMESPACE
97#endif
98
99QT_BEGIN_NAMESPACE
100
101class QGLContext;
102class QGLOverlayWidget;
103class QPixmap;
104class QPixmapFilter;
105#ifdef Q_WS_MAC
106# ifdef qDebug
107# define old_qDebug qDebug
108# undef qDebug
109# endif
110QT_BEGIN_INCLUDE_NAMESPACE
111#ifndef QT_MAC_USE_COCOA
112# include <AGL/agl.h>
113#endif
114QT_END_INCLUDE_NAMESPACE
115# ifdef old_qDebug
116# undef qDebug
117# define qDebug QT_QDEBUG_MACRO
118# undef old_qDebug
119# endif
120class QMacWindowChangeEvent;
121#endif
122
123#ifdef Q_WS_QWS
124class QWSGLWindowSurface;
125#endif
126
127#if defined(QT_OPENGL_ES)
128class QEglContext;
129#endif
130
131QT_BEGIN_INCLUDE_NAMESPACE
132#include <QtOpenGL/private/qglextensions_p.h>
133QT_END_INCLUDE_NAMESPACE
134
135class QGLFormatPrivate
136{
137public:
138 QGLFormatPrivate()
139 : ref(1)
140 {
141 opts = QGL::DoubleBuffer | QGL::DepthBuffer | QGL::Rgba | QGL::DirectRendering | QGL::StencilBuffer;
142 pln = 0;
143 depthSize = accumSize = stencilSize = redSize = greenSize = blueSize = alphaSize = -1;
144 numSamples = -1;
145 swapInterval = -1;
146 }
147 QGLFormatPrivate(const QGLFormatPrivate *other)
148 : ref(1),
149 opts(other->opts),
150 pln(other->pln),
151 depthSize(other->depthSize),
152 accumSize(other->accumSize),
153 stencilSize(other->stencilSize),
154 redSize(other->redSize),
155 greenSize(other->greenSize),
156 blueSize(other->blueSize),
157 alphaSize(other->alphaSize),
158 numSamples(other->numSamples),
159 swapInterval(other->swapInterval)
160 {
161 }
162 QAtomicInt ref;
163 QGL::FormatOptions opts;
164 int pln;
165 int depthSize;
166 int accumSize;
167 int stencilSize;
168 int redSize;
169 int greenSize;
170 int blueSize;
171 int alphaSize;
172 int numSamples;
173 int swapInterval;
174};
175
176class QGLWidgetPrivate : public QWidgetPrivate
177{
178 Q_DECLARE_PUBLIC(QGLWidget)
179public:
180 QGLWidgetPrivate() : QWidgetPrivate()
181 , disable_clear_on_painter_begin(false)
182#ifdef Q_WS_QWS
183 , wsurf(0)
184#endif
185#if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
186 , eglSurfaceWindowId(0)
187#endif
188 {
189 isGLWidget = 1;
190 }
191
192 ~QGLWidgetPrivate() {}
193
194 void init(QGLContext *context, const QGLWidget* shareWidget);
195 void initContext(QGLContext *context, const QGLWidget* shareWidget);
196 bool renderCxPm(QPixmap *pixmap);
197 void cleanupColormaps();
198
199 QGLContext *glcx;
200 QGLWidgetGLPaintDevice glDevice;
201 bool autoSwap;
202
203 QGLColormap cmap;
204#ifndef QT_OPENGL_ES
205 QMap<QString, int> displayListCache;
206#endif
207
208 bool disable_clear_on_painter_begin;
209
210#if defined(Q_WS_WIN)
211 void updateColormap();
212 QGLContext *olcx;
213#elif defined(Q_WS_X11)
214 QGLOverlayWidget *olw;
215#if defined(QT_OPENGL_ES)
216 void recreateEglSurface(bool force);
217 WId eglSurfaceWindowId;
218#endif
219#elif defined(Q_WS_MAC)
220 QGLContext *olcx;
221 void updatePaintDevice();
222#elif defined(Q_WS_QWS)
223 QWSGLWindowSurface *wsurf;
224#endif
225};
226
227class QGLContextResource;
228class QGLSharedResourceGuard;
229
230typedef QHash<QString, GLuint> QGLDDSCache;
231
232// QGLContextPrivate has the responsibility of creating context groups.
233// QGLContextPrivate maintains the reference counter and destroys
234// context groups when needed.
235class QGLContextGroup
236{
237public:
238 ~QGLContextGroup();
239
240 QGLExtensionFuncs &extensionFuncs() {return m_extensionFuncs;}
241 const QGLContext *context() const {return m_context;}
242 bool isSharing() const { return m_shares.size() >= 2; }
243 QList<const QGLContext *> shares() const { return m_shares; }
244
245 void addGuard(QGLSharedResourceGuard *guard);
246 void removeGuard(QGLSharedResourceGuard *guard);
247
248 static void addShare(const QGLContext *context, const QGLContext *share);
249 static void removeShare(const QGLContext *context);
250private:
251 QGLContextGroup(const QGLContext *context) : m_context(context), m_guards(0), m_refs(1) { }
252
253 QGLExtensionFuncs m_extensionFuncs;
254 const QGLContext *m_context; // context group's representative
255 QList<const QGLContext *> m_shares;
256 QHash<QGLContextResource *, void *> m_resources;
257 QGLSharedResourceGuard *m_guards; // double-linked list of active guards.
258 QAtomicInt m_refs;
259 QGLDDSCache m_dds_cache;
260
261 void cleanupResources(const QGLContext *ctx);
262
263 friend class QGLContext;
264 friend class QGLContextPrivate;
265 friend class QGLContextResource;
266};
267
268// Get the context that resources for "ctx" will transfer to once
269// "ctx" is destroyed. Returns null if nothing is sharing with ctx.
270Q_OPENGL_EXPORT const QGLContext *qt_gl_transfer_context(const QGLContext *);
271
272// GL extension definitions
273class QGLExtensions {
274public:
275 enum Extension {
276 TextureRectangle = 0x00000001,
277 SampleBuffers = 0x00000002,
278 GenerateMipmap = 0x00000004,
279 TextureCompression = 0x00000008,
280 FragmentProgram = 0x00000010,
281 MirroredRepeat = 0x00000020,
282 FramebufferObject = 0x00000040,
283 StencilTwoSide = 0x00000080,
284 StencilWrap = 0x00000100,
285 PackedDepthStencil = 0x00000200,
286 NVFloatBuffer = 0x00000400,
287 PixelBufferObject = 0x00000800,
288 FramebufferBlit = 0x00001000,
289 NPOTTextures = 0x00002000,
290 BGRATextureFormat = 0x00004000,
291 DDSTextureCompression = 0x00008000,
292 ETC1TextureCompression = 0x00010000,
293 PVRTCTextureCompression = 0x00020000,
294 FragmentShader = 0x00040000
295 };
296 Q_DECLARE_FLAGS(Extensions, Extension)
297
298 static Extensions glExtensions();
299
300private:
301 static Extensions currentContextExtensions();
302};
303
304/*
305 QGLTemporaryContext - the main objective of this class is to have a way of
306 creating a GL context and making it current, without going via QGLWidget
307 and friends. At certain points during GL initialization we need a current
308 context in order decide what GL features are available, and to resolve GL
309 extensions. Having a light-weight way of creating such a context saves
310 initial application startup time, and it doesn't wind up creating recursive
311 conflicts.
312 The class currently uses a private d pointer to hide the platform specific
313 types. This could possibly been done inline with #ifdef'ery, but it causes
314 major headaches on e.g. X11 due to namespace pollution.
315*/
316class QGLTemporaryContextPrivate;
317class QGLTemporaryContext {
318public:
319 QGLTemporaryContext(bool directRendering = true, QWidget *parent = 0);
320 ~QGLTemporaryContext();
321
322private:
323 QScopedPointer<QGLTemporaryContextPrivate> d;
324};
325
326class QGLTexture;
327
328// This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's
329// all the GL2 engine uses:
330#define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3
331
332class QGLContextPrivate
333{
334 Q_DECLARE_PUBLIC(QGLContext)
335public:
336 explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {group = new QGLContextGroup(context);}
337 ~QGLContextPrivate();
338 QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format,
339 QGLContext::BindOptions options);
340 QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
341 QGLContext::BindOptions options);
342 QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
343 QGLContext::BindOptions options);
344 QGLTexture *textureCacheLookup(const qint64 key, GLenum target);
345 void init(QPaintDevice *dev, const QGLFormat &format);
346 QImage convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format);
347 int maxTextureSize();
348
349 void cleanup();
350
351 void setVertexAttribArrayEnabled(int arrayIndex, bool enabled = true);
352 void syncGlState(); // Makes sure the GL context's state is what we think it is
353
354#if defined(Q_WS_WIN)
355 HGLRC rc;
356 HDC dc;
357 WId win;
358 int pixelFormatId;
359 QGLCmap* cmap;
360 HBITMAP hbitmap;
361 HDC hbitmap_hdc;
362#endif
363#if defined(QT_OPENGL_ES)
364 QEglContext *eglContext;
365 EGLSurface eglSurface;
366 void destroyEglSurfaceForDevice();
367#elif defined(Q_WS_X11) || defined(Q_WS_MAC)
368 void* cx;
369#endif
370#if defined(Q_WS_X11) || defined(Q_WS_MAC)
371 void* vi;
372#endif
373#if defined(Q_WS_X11)
374 void* pbuf;
375 quint32 gpm;
376 int screen;
377 QHash<QPixmapData*, QPixmap> boundPixmaps;
378 QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key,
379 QGLContext::BindOptions options);
380 static void destroyGlSurfaceForPixmap(QPixmapData*);
381 static void unbindPixmapFromTexture(QPixmapData*);
382#endif
383#if defined(Q_WS_MAC)
384 bool update;
385 void *tryFormat(const QGLFormat &format);
386 void clearDrawable();
387#endif
388 QGLFormat glFormat;
389 QGLFormat reqFormat;
390 GLuint fbo;
391
392 uint valid : 1;
393 uint sharing : 1;
394 uint initDone : 1;
395 uint crWin : 1;
396 uint internal_context : 1;
397 uint version_flags_cached : 1;
398 uint extension_flags_cached : 1;
399 QPaintDevice *paintDevice;
400 QColor transpColor;
401 QGLContext *q_ptr;
402 QGLFormat::OpenGLVersionFlags version_flags;
403 QGLExtensions::Extensions extension_flags;
404
405 QGLContextGroup *group;
406 GLint max_texture_size;
407
408 GLuint current_fbo;
409 GLuint default_fbo;
410 QPaintEngine *active_engine;
411
412 bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT];
413
414 static inline QGLContextGroup *contextGroup(const QGLContext *ctx) { return ctx->d_ptr->group; }
415
416#ifdef Q_WS_WIN
417 static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *ctx) { return ctx->d_ptr->group->extensionFuncs(); }
418#endif
419
420#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
421 static QGLExtensionFuncs qt_extensionFuncs;
422 static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *) { return qt_extensionFuncs; }
423#endif
424
425 static void setCurrentContext(QGLContext *context);
426};
427
428// ### make QGLContext a QObject in 5.0 and remove the proxy stuff
429class Q_OPENGL_EXPORT QGLSignalProxy : public QObject
430{
431 Q_OBJECT
432public:
433 QGLSignalProxy() : QObject() {}
434 void emitAboutToDestroyContext(const QGLContext *context) {
435 emit aboutToDestroyContext(context);
436 }
437 static QGLSignalProxy *instance();
438Q_SIGNALS:
439 void aboutToDestroyContext(const QGLContext *context);
440};
441
442Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions)
443
444// Temporarily make a context current if not already current or
445// shared with the current contex. The previous context is made
446// current when the object goes out of scope.
447class Q_OPENGL_EXPORT QGLShareContextScope
448{
449public:
450 QGLShareContextScope(const QGLContext *ctx)
451 : m_oldContext(0)
452 {
453 QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
454 if (currentContext != ctx && !QGLContext::areSharing(ctx, currentContext)) {
455 m_oldContext = currentContext;
456 m_ctx = const_cast<QGLContext *>(ctx);
457 m_ctx->makeCurrent();
458 } else {
459 m_ctx = currentContext;
460 }
461 }
462
463 operator QGLContext *()
464 {
465 return m_ctx;
466 }
467
468 QGLContext *operator->()
469 {
470 return m_ctx;
471 }
472
473 ~QGLShareContextScope()
474 {
475 if (m_oldContext)
476 m_oldContext->makeCurrent();
477 }
478
479private:
480 QGLContext *m_oldContext;
481 QGLContext *m_ctx;
482};
483
484class QGLTexture {
485public:
486 QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D,
487 QGLContext::BindOptions opt = QGLContext::DefaultBindOption)
488 : context(ctx),
489 id(tx_id),
490 target(tx_target),
491 options(opt)
492#if defined(Q_WS_X11)
493 , boundPixmap(0)
494#endif
495 {}
496
497 ~QGLTexture() {
498 if (options & QGLContext::MemoryManagedBindOption) {
499 Q_ASSERT(context);
500 QGLShareContextScope scope(context);
501#if defined(Q_WS_X11)
502 // Although glXReleaseTexImage is a glX call, it must be called while there
503 // is a current context - the context the pixmap was bound to a texture in.
504 // Otherwise the release doesn't do anything and you get BadDrawable errors
505 // when you come to delete the context.
506 if (boundPixmap)
507 QGLContextPrivate::unbindPixmapFromTexture(boundPixmap);
508#endif
509 glDeleteTextures(1, &id);
510 }
511 }
512
513 QGLContext *context;
514 GLuint id;
515 GLenum target;
516
517 QGLContext::BindOptions options;
518
519#if defined(Q_WS_X11)
520 QPixmapData* boundPixmap;
521#endif
522
523 bool canBindCompressedTexture
524 (const char *buf, int len, const char *format, bool *hasAlpha);
525 QSize bindCompressedTexture
526 (const QString& fileName, const char *format = 0);
527 QSize bindCompressedTexture
528 (const char *buf, int len, const char *format = 0);
529 QSize bindCompressedTextureDDS(const char *buf, int len);
530 QSize bindCompressedTexturePVR(const char *buf, int len);
531};
532
533class Q_AUTOTEST_EXPORT QGLTextureCache {
534public:
535 QGLTextureCache();
536 ~QGLTextureCache();
537
538 void insert(QGLContext *ctx, qint64 key, QGLTexture *texture, int cost);
539 void remove(quint64 key) { m_cache.remove(key); }
540 bool remove(QGLContext *ctx, GLuint textureId);
541 void removeContextTextures(QGLContext *ctx);
542 int size() { return m_cache.size(); }
543 void setMaxCost(int newMax) { m_cache.setMaxCost(newMax); }
544 int maxCost() {return m_cache.maxCost(); }
545 QGLTexture* getTexture(quint64 key) { return m_cache.object(key); }
546
547 static QGLTextureCache *instance();
548 static void deleteIfEmpty();
549 static void cleanupTexturesForCacheKey(qint64 cacheKey);
550 static void cleanupTexturesForPixampData(QPixmapData* pixmap);
551 static void cleanupBeforePixmapDestruction(QPixmapData* pixmap);
552
553private:
554 QCache<qint64, QGLTexture> m_cache;
555};
556
557
558extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine();
559
560bool qt_gl_preferGL2Engine();
561
562inline GLenum qt_gl_preferredTextureFormat()
563{
564 return (QGLExtensions::glExtensions() & QGLExtensions::BGRATextureFormat) && QSysInfo::ByteOrder == QSysInfo::LittleEndian
565 ? GL_BGRA : GL_RGBA;
566}
567
568inline GLenum qt_gl_preferredTextureTarget()
569{
570#if defined(QT_OPENGL_ES_2)
571 return GL_TEXTURE_2D;
572#else
573 return (QGLExtensions::glExtensions() & QGLExtensions::TextureRectangle)
574 && !qt_gl_preferGL2Engine()
575 ? GL_TEXTURE_RECTANGLE_NV
576 : GL_TEXTURE_2D;
577#endif
578}
579
580// One resource per group of shared contexts.
581class Q_OPENGL_EXPORT QGLContextResource
582{
583public:
584 typedef void (*FreeFunc)(void *);
585 QGLContextResource(FreeFunc f);
586 ~QGLContextResource();
587 // Set resource 'value' for 'key' and all its shared contexts.
588 void insert(const QGLContext *key, void *value);
589 // Return resource for 'key' or a shared context.
590 void *value(const QGLContext *key);
591 // Cleanup 'value' in response to a context group being destroyed.
592 void cleanup(const QGLContext *ctx, void *value);
593private:
594 FreeFunc free;
595 QAtomicInt active;
596};
597
598// Put a guard around a GL object identifier and its context.
599// When the context goes away, a shared context will be used
600// in its place. If there are no more shared contexts, then
601// the identifier is returned as zero - it is assumed that the
602// context destruction cleaned up the identifier in this case.
603class Q_OPENGL_EXPORT QGLSharedResourceGuard
604{
605public:
606 QGLSharedResourceGuard(const QGLContext *context)
607 : m_group(0), m_id(0), m_next(0), m_prev(0)
608 {
609 setContext(context);
610 }
611 QGLSharedResourceGuard(const QGLContext *context, GLuint id)
612 : m_group(0), m_id(id), m_next(0), m_prev(0)
613 {
614 setContext(context);
615 }
616 ~QGLSharedResourceGuard();
617
618 const QGLContext *context() const
619 {
620 return m_group ? m_group->context() : 0;
621 }
622
623 void setContext(const QGLContext *context);
624
625 GLuint id() const
626 {
627 return m_id;
628 }
629
630 void setId(GLuint id)
631 {
632 m_id = id;
633 }
634
635private:
636 QGLContextGroup *m_group;
637 GLuint m_id;
638 QGLSharedResourceGuard *m_next;
639 QGLSharedResourceGuard *m_prev;
640
641 friend class QGLContextGroup;
642};
643
644
645// This class can be used to match GL extensions without doing any mallocs. The
646// class assumes that the GL extension string ends with a space character,
647// which it should do on all conformant platforms. Create the object and pass
648// in a pointer to the extension string, then call match() on each extension
649// that should be matched. The match() function takes the extension name
650// *without* the terminating space character as input.
651
652class QGLExtensionMatcher
653{
654public:
655 QGLExtensionMatcher(const char *str)
656 : gl_extensions(str), gl_extensions_length(qstrlen(str))
657 {}
658
659 bool match(const char *str) {
660 int str_length = qstrlen(str);
661 const char *extensions = gl_extensions;
662 int extensions_length = gl_extensions_length;
663
664 while (1) {
665 // the total length that needs to be matched is the str_length +
666 // the space character that terminates the extension name
667 if (extensions_length < str_length + 1)
668 return false;
669 if (qstrncmp(extensions, str, str_length) == 0 && extensions[str_length] == ' ')
670 return true;
671
672 int split_pos = 0;
673 while (split_pos < extensions_length && extensions[split_pos] != ' ')
674 ++split_pos;
675 ++split_pos; // added for the terminating space character
676 extensions += split_pos;
677 extensions_length -= split_pos;
678 }
679 return false;
680 }
681
682private:
683 const char *gl_extensions;
684 int gl_extensions_length;
685};
686
687QT_END_NAMESPACE
688
689#endif // QGL_P_H
Note: See TracBrowser for help on using the repository browser.