1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the QtOpenGL module of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
23 | ** In addition, as a special exception, Nokia gives you certain
|
---|
24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
26 | ** 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 are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include <private/qtextengine_p.h>
|
---|
43 | #include <qdebug.h>
|
---|
44 | #include <private/qfontengine_p.h>
|
---|
45 | #include <qmath.h>
|
---|
46 | #include <private/qmath_p.h>
|
---|
47 | #include <private/qdrawhelper_p.h>
|
---|
48 | #include <private/qpaintengine_p.h>
|
---|
49 | #include "qapplication.h"
|
---|
50 | #include "qbrush.h"
|
---|
51 | #include "qgl.h"
|
---|
52 | #include <private/qgl_p.h>
|
---|
53 | #include <private/qpainter_p.h>
|
---|
54 | #include "qmap.h"
|
---|
55 | #include <private/qpaintengine_opengl_p.h>
|
---|
56 | #include <private/qdatabuffer_p.h>
|
---|
57 | #include "qpen.h"
|
---|
58 | #include "qvarlengtharray.h"
|
---|
59 | #include <private/qpainter_p.h>
|
---|
60 | #include <qglpixelbuffer.h>
|
---|
61 | #include <private/qglpixelbuffer_p.h>
|
---|
62 | #include <private/qbezier_p.h>
|
---|
63 | #include <qglframebufferobject.h>
|
---|
64 |
|
---|
65 | #include "private/qtessellator_p.h"
|
---|
66 | #include "private/qwindowsurface_gl_p.h"
|
---|
67 |
|
---|
68 | #include "util/fragmentprograms_p.h"
|
---|
69 |
|
---|
70 | #ifdef Q_WS_QWS
|
---|
71 | #include "private/qglpaintdevice_qws_p.h"
|
---|
72 | #include "private/qglwindowsurface_qws_p.h"
|
---|
73 | #include "qwsmanager_qws.h"
|
---|
74 | #include "private/qwsmanager_p.h"
|
---|
75 | #endif
|
---|
76 |
|
---|
77 | #ifdef QT_OPENGL_ES_1_CL
|
---|
78 | #include "qgl_cl_p.h"
|
---|
79 | #endif
|
---|
80 |
|
---|
81 | #define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(drawable.context());
|
---|
82 |
|
---|
83 | #include <stdlib.h>
|
---|
84 | #include "qpaintengine_opengl_p.h"
|
---|
85 |
|
---|
86 | QT_BEGIN_NAMESPACE
|
---|
87 |
|
---|
88 | extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp
|
---|
89 | #ifdef QT_MAC_USE_COCOA
|
---|
90 | extern void *qt_current_nsopengl_context(); // qgl_mac.mm
|
---|
91 | #endif
|
---|
92 |
|
---|
93 | #define QREAL_MAX 9e100
|
---|
94 | #define QREAL_MIN -9e100
|
---|
95 |
|
---|
96 | extern int qt_next_power_of_two(int v);
|
---|
97 |
|
---|
98 | #define DISABLE_DEBUG_ONCE
|
---|
99 |
|
---|
100 | //#define DEBUG_DISPLAY_MASK_TEXTURE
|
---|
101 |
|
---|
102 | #ifdef DISABLE_DEBUG_ONCE
|
---|
103 | #define DEBUG_OVERRIDE(state) ;
|
---|
104 | #define DEBUG_ONCE_STR(str) ;
|
---|
105 | #define DEBUG_ONCE if (0)
|
---|
106 | #else
|
---|
107 | static int DEBUG_OVERRIDE_FLAG = 0;
|
---|
108 | static bool DEBUG_TEMP_FLAG;
|
---|
109 | #define DEBUG_OVERRIDE(state) { state ? ++DEBUG_OVERRIDE_FLAG : --DEBUG_OVERRIDE_FLAG; }
|
---|
110 | #define DEBUG_ONCE if ((DEBUG_TEMP_FLAG = DEBUG_OVERRIDE_FLAG) && 0) ; else for (static int DEBUG_ONCE_FLAG = false; !DEBUG_ONCE_FLAG || DEBUG_TEMP_FLAG; DEBUG_ONCE_FLAG = true, DEBUG_TEMP_FLAG = false)
|
---|
111 | #define DEBUG_ONCE_STR(str) DEBUG_ONCE qDebug() << (str);
|
---|
112 | #endif
|
---|
113 |
|
---|
114 | static inline void qt_glColor4ubv(unsigned char *col)
|
---|
115 | {
|
---|
116 | #ifdef QT_OPENGL_ES
|
---|
117 | glColor4f(col[0]/255.0, col[1]/255.0, col[2]/255.0, col[3]/255.0);
|
---|
118 | #else
|
---|
119 | glColor4ubv(col);
|
---|
120 | #endif
|
---|
121 | }
|
---|
122 |
|
---|
123 | struct QT_PointF {
|
---|
124 | qreal x;
|
---|
125 | qreal y;
|
---|
126 | };
|
---|
127 |
|
---|
128 | void qt_add_rect_to_array(const QRectF &r, q_vertexType *array)
|
---|
129 | {
|
---|
130 | qreal left = r.left();
|
---|
131 | qreal right = r.right();
|
---|
132 | qreal top = r.top();
|
---|
133 | qreal bottom = r.bottom();
|
---|
134 |
|
---|
135 | array[0] = f2vt(left);
|
---|
136 | array[1] = f2vt(top);
|
---|
137 | array[2] = f2vt(right);
|
---|
138 | array[3] = f2vt(top);
|
---|
139 | array[4] = f2vt(right);
|
---|
140 | array[5] = f2vt(bottom);
|
---|
141 | array[6] = f2vt(left);
|
---|
142 | array[7] = f2vt(bottom);
|
---|
143 | }
|
---|
144 |
|
---|
145 | void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array)
|
---|
146 | {
|
---|
147 | array[0] = f2vt(x1);
|
---|
148 | array[1] = f2vt(y1);
|
---|
149 | array[2] = f2vt(x2);
|
---|
150 | array[3] = f2vt(y1);
|
---|
151 | array[4] = f2vt(x2);
|
---|
152 | array[5] = f2vt(y2);
|
---|
153 | array[6] = f2vt(x1);
|
---|
154 | array[7] = f2vt(y2);
|
---|
155 | }
|
---|
156 |
|
---|
157 | struct QGLTrapezoid
|
---|
158 | {
|
---|
159 | QGLTrapezoid()
|
---|
160 | {}
|
---|
161 |
|
---|
162 | QGLTrapezoid(qreal top_, qreal bottom_, qreal topLeftX_, qreal topRightX_, qreal bottomLeftX_, qreal bottomRightX_)
|
---|
163 | : top(top_),
|
---|
164 | bottom(bottom_),
|
---|
165 | topLeftX(topLeftX_),
|
---|
166 | topRightX(topRightX_),
|
---|
167 | bottomLeftX(bottomLeftX_),
|
---|
168 | bottomRightX(bottomRightX_)
|
---|
169 | {}
|
---|
170 |
|
---|
171 | const QGLTrapezoid translated(const QPointF &delta) const;
|
---|
172 |
|
---|
173 | qreal top;
|
---|
174 | qreal bottom;
|
---|
175 | qreal topLeftX;
|
---|
176 | qreal topRightX;
|
---|
177 | qreal bottomLeftX;
|
---|
178 | qreal bottomRightX;
|
---|
179 | };
|
---|
180 |
|
---|
181 | const QGLTrapezoid QGLTrapezoid::translated(const QPointF &delta) const
|
---|
182 | {
|
---|
183 | QGLTrapezoid trap(*this);
|
---|
184 | trap.top += delta.y();
|
---|
185 | trap.bottom += delta.y();
|
---|
186 | trap.topLeftX += delta.x();
|
---|
187 | trap.topRightX += delta.x();
|
---|
188 | trap.bottomLeftX += delta.x();
|
---|
189 | trap.bottomRightX += delta.x();
|
---|
190 | return trap;
|
---|
191 | }
|
---|
192 |
|
---|
193 | class QGLDrawable {
|
---|
194 | public:
|
---|
195 | QGLDrawable() : widget(0), buffer(0), fbo(0)
|
---|
196 | , wsurf(0)
|
---|
197 | {}
|
---|
198 | inline void setDevice(QPaintDevice *pdev);
|
---|
199 | inline void swapBuffers();
|
---|
200 | inline void makeCurrent();
|
---|
201 | inline void doneCurrent();
|
---|
202 | inline QSize size() const;
|
---|
203 | inline QGLFormat format() const;
|
---|
204 | inline GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA);
|
---|
205 | inline GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA);
|
---|
206 | inline QColor backgroundColor() const;
|
---|
207 | inline QGLContext *context() const;
|
---|
208 | inline bool autoFillBackground() const;
|
---|
209 |
|
---|
210 | private:
|
---|
211 | bool wasBound;
|
---|
212 | QGLWidget *widget;
|
---|
213 | QGLPixelBuffer *buffer;
|
---|
214 | QGLFramebufferObject *fbo;
|
---|
215 | #ifdef Q_WS_QWS
|
---|
216 | QWSGLWindowSurface *wsurf;
|
---|
217 | #else
|
---|
218 | QGLWindowSurface *wsurf;
|
---|
219 | #endif
|
---|
220 | };
|
---|
221 |
|
---|
222 | void QGLDrawable::setDevice(QPaintDevice *pdev)
|
---|
223 | {
|
---|
224 | wasBound = false;
|
---|
225 | widget = 0;
|
---|
226 | buffer = 0;
|
---|
227 | fbo = 0;
|
---|
228 | #ifdef Q_WS_QWS
|
---|
229 | wsurf = 0;
|
---|
230 | #endif
|
---|
231 | if (pdev->devType() == QInternal::Widget)
|
---|
232 | widget = static_cast<QGLWidget *>(pdev);
|
---|
233 | else if (pdev->devType() == QInternal::Pbuffer)
|
---|
234 | buffer = static_cast<QGLPixelBuffer *>(pdev);
|
---|
235 | else if (pdev->devType() == QInternal::FramebufferObject)
|
---|
236 | fbo = static_cast<QGLFramebufferObject *>(pdev);
|
---|
237 | else if (pdev->devType() == QInternal::UnknownDevice)
|
---|
238 | #ifdef Q_WS_QWS
|
---|
239 | wsurf = static_cast<QWSGLPaintDevice*>(pdev)->windowSurface();
|
---|
240 | #else
|
---|
241 | wsurf = static_cast<QGLWindowSurface *>(pdev);
|
---|
242 | #endif
|
---|
243 | }
|
---|
244 |
|
---|
245 | inline void QGLDrawable::swapBuffers()
|
---|
246 | {
|
---|
247 | if (widget) {
|
---|
248 | if (widget->autoBufferSwap())
|
---|
249 | widget->swapBuffers();
|
---|
250 | } else {
|
---|
251 | glFlush();
|
---|
252 | }
|
---|
253 | }
|
---|
254 |
|
---|
255 | inline void QGLDrawable::makeCurrent()
|
---|
256 | {
|
---|
257 | if (widget)
|
---|
258 | widget->makeCurrent();
|
---|
259 | else if (buffer)
|
---|
260 | buffer->makeCurrent();
|
---|
261 | else if (wsurf)
|
---|
262 | wsurf->context()->makeCurrent();
|
---|
263 | else if (fbo) {
|
---|
264 | wasBound = fbo->isBound();
|
---|
265 | if (!wasBound)
|
---|
266 | fbo->bind();
|
---|
267 | }
|
---|
268 | }
|
---|
269 |
|
---|
270 | inline void QGLDrawable::doneCurrent()
|
---|
271 | {
|
---|
272 | if (fbo && !wasBound)
|
---|
273 | fbo->release();
|
---|
274 | }
|
---|
275 |
|
---|
276 | inline QSize QGLDrawable::size() const
|
---|
277 | {
|
---|
278 | if (widget) {
|
---|
279 | return QSize(widget->d_func()->glcx->device()->width(),
|
---|
280 | widget->d_func()->glcx->device()->height());
|
---|
281 | } else if (buffer) {
|
---|
282 | return buffer->size();
|
---|
283 | } else if (fbo) {
|
---|
284 | return fbo->size();
|
---|
285 | } else if (wsurf) {
|
---|
286 | #ifdef Q_WS_QWS
|
---|
287 | return wsurf->window()->frameSize();
|
---|
288 | #else
|
---|
289 | return QSize(wsurf->width(), wsurf->height());
|
---|
290 | #endif
|
---|
291 | }
|
---|
292 | return QSize();
|
---|
293 | }
|
---|
294 |
|
---|
295 | inline QGLFormat QGLDrawable::format() const
|
---|
296 | {
|
---|
297 | if (widget)
|
---|
298 | return widget->format();
|
---|
299 | else if (buffer)
|
---|
300 | return buffer->format();
|
---|
301 | else if (wsurf)
|
---|
302 | return wsurf->context()->format();
|
---|
303 | else if (fbo && QGLContext::currentContext()) {
|
---|
304 | QGLFormat fmt = QGLContext::currentContext()->format();
|
---|
305 | fmt.setStencil(fbo->attachment() == QGLFramebufferObject::CombinedDepthStencil);
|
---|
306 | fmt.setDepth(fbo->attachment() != QGLFramebufferObject::NoAttachment);
|
---|
307 | return fmt;
|
---|
308 | }
|
---|
309 |
|
---|
310 | return QGLFormat();
|
---|
311 | }
|
---|
312 |
|
---|
313 | inline GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format)
|
---|
314 | {
|
---|
315 | if (widget)
|
---|
316 | return widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true);
|
---|
317 | else if (buffer)
|
---|
318 | return buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true);
|
---|
319 | else if (fbo && QGLContext::currentContext())
|
---|
320 | return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true);
|
---|
321 | else if (wsurf)
|
---|
322 | return wsurf->context()->d_func()->bindTexture(image, target, format, true);
|
---|
323 | return 0;
|
---|
324 | }
|
---|
325 |
|
---|
326 | inline GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
|
---|
327 | {
|
---|
328 | if (widget)
|
---|
329 | return widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true);
|
---|
330 | else if (buffer)
|
---|
331 | return buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true);
|
---|
332 | else if (fbo && QGLContext::currentContext())
|
---|
333 | return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true);
|
---|
334 | else if (wsurf)
|
---|
335 | return wsurf->context()->d_func()->bindTexture(pixmap, target, format, true);
|
---|
336 | return 0;
|
---|
337 | }
|
---|
338 |
|
---|
339 | inline QColor QGLDrawable::backgroundColor() const
|
---|
340 | {
|
---|
341 | if (widget)
|
---|
342 | return widget->palette().brush(widget->backgroundRole()).color();
|
---|
343 | return QApplication::palette().brush(QPalette::Background).color();
|
---|
344 | }
|
---|
345 |
|
---|
346 | inline QGLContext *QGLDrawable::context() const
|
---|
347 | {
|
---|
348 | if (widget)
|
---|
349 | return widget->d_func()->glcx;
|
---|
350 | else if (buffer)
|
---|
351 | return buffer->d_func()->qctx;
|
---|
352 | else if (fbo)
|
---|
353 | return const_cast<QGLContext *>(QGLContext::currentContext());
|
---|
354 | else if (wsurf)
|
---|
355 | return wsurf->context();
|
---|
356 | return 0;
|
---|
357 | }
|
---|
358 |
|
---|
359 | inline bool QGLDrawable::autoFillBackground() const
|
---|
360 | {
|
---|
361 | if (widget)
|
---|
362 | return widget->autoFillBackground();
|
---|
363 | else
|
---|
364 | return false;
|
---|
365 | }
|
---|
366 |
|
---|
367 |
|
---|
368 | class QOpenGLImmediateModeTessellator;
|
---|
369 | class QGLMaskGenerator;
|
---|
370 | class QGLOffscreen;
|
---|
371 |
|
---|
372 | class QGLMaskTextureCache
|
---|
373 | {
|
---|
374 | public:
|
---|
375 | void setOffscreenSize(const QSize &offscreenSize);
|
---|
376 | void setDrawableSize(const QSize &drawableSize);
|
---|
377 |
|
---|
378 | struct CacheLocation {
|
---|
379 | QRect rect;
|
---|
380 | int channel;
|
---|
381 |
|
---|
382 | QRect screen_rect;
|
---|
383 | };
|
---|
384 |
|
---|
385 | struct CacheInfo {
|
---|
386 | inline CacheInfo(const QPainterPath &p, const QTransform &m, qreal w = -1) :
|
---|
387 | path(p), matrix(m), stroke_width(w), age(0) {}
|
---|
388 |
|
---|
389 | QPainterPath path;
|
---|
390 | QTransform matrix;
|
---|
391 | qreal stroke_width;
|
---|
392 |
|
---|
393 | CacheLocation loc;
|
---|
394 |
|
---|
395 | int age;
|
---|
396 | };
|
---|
397 |
|
---|
398 | struct QuadTreeNode {
|
---|
399 | quint64 key;
|
---|
400 |
|
---|
401 | int largest_available_block;
|
---|
402 | int largest_used_block;
|
---|
403 | };
|
---|
404 |
|
---|
405 | CacheLocation getMask(QGLMaskGenerator &maskGenerator, QOpenGLPaintEnginePrivate *engine);
|
---|
406 |
|
---|
407 | typedef QMultiHash<quint64, CacheInfo> QGLTextureCacheHash;
|
---|
408 |
|
---|
409 | enum {block_size = 64};
|
---|
410 |
|
---|
411 | // throw out keys that are too old
|
---|
412 | void maintainCache();
|
---|
413 | void clearCache();
|
---|
414 |
|
---|
415 | private:
|
---|
416 | quint64 hash(const QPainterPath &p, const QTransform &m, qreal w);
|
---|
417 |
|
---|
418 | void createMask(quint64 key, CacheInfo &info, QGLMaskGenerator &maskGenerator);
|
---|
419 |
|
---|
420 | QSize offscreenSize;
|
---|
421 | QSize drawableSize;
|
---|
422 |
|
---|
423 | QGLTextureCacheHash cache;
|
---|
424 |
|
---|
425 | QVector<QuadTreeNode> occupied_quadtree[4];
|
---|
426 |
|
---|
427 | void quadtreeUpdate(int channel, int node, int current_block_size);
|
---|
428 | void quadtreeAllocate(quint64 key, const QSize &size, QRect *rect, int *channel);
|
---|
429 |
|
---|
430 | bool quadtreeFindAvailableLocation(const QSize &size, QRect *rect, int *channel);
|
---|
431 | void quadtreeFindExistingLocation(const QSize &size, QRect *rect, int *channel);
|
---|
432 |
|
---|
433 | void quadtreeInsert(int channel, quint64 key, const QRect &rect, int node = 0);
|
---|
434 | void quadtreeClear(int channel, const QRect &rect, int node = 0);
|
---|
435 |
|
---|
436 | int quadtreeBlocksize(int node);
|
---|
437 | QPoint quadtreeLocation(int node);
|
---|
438 |
|
---|
439 | QOpenGLPaintEnginePrivate *engine;
|
---|
440 | };
|
---|
441 |
|
---|
442 | Q_GLOBAL_STATIC(QGLMaskTextureCache, qt_mask_texture_cache)
|
---|
443 |
|
---|
444 | class QGLOffscreen : public QObject
|
---|
445 | {
|
---|
446 | Q_OBJECT
|
---|
447 | public:
|
---|
448 | QGLOffscreen()
|
---|
449 | : QObject(),
|
---|
450 | offscreen(0),
|
---|
451 | ctx(0),
|
---|
452 | mask_dim(0),
|
---|
453 | activated(false),
|
---|
454 | bound(false)
|
---|
455 | {
|
---|
456 | connect(QGLSignalProxy::instance(),
|
---|
457 | SIGNAL(aboutToDestroyContext(const QGLContext *)),
|
---|
458 | SLOT(cleanupGLContextRefs(const QGLContext *)));
|
---|
459 | }
|
---|
460 |
|
---|
461 | inline void setDevice(QPaintDevice *pdev);
|
---|
462 |
|
---|
463 | void begin();
|
---|
464 | void end();
|
---|
465 |
|
---|
466 | inline void bind();
|
---|
467 | inline void release();
|
---|
468 |
|
---|
469 | inline bool isBound() const;
|
---|
470 |
|
---|
471 | inline QSize drawableSize() const;
|
---|
472 | inline QSize offscreenSize() const;
|
---|
473 |
|
---|
474 | inline GLuint offscreenTexture() const;
|
---|
475 |
|
---|
476 | QGLContext *context() const;
|
---|
477 |
|
---|
478 | static bool isSupported();
|
---|
479 |
|
---|
|
---|