source: trunk/src/opengl/qpaintengine_opengl.cpp@ 432

Last change on this file since 432 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 179.3 KB
Line 
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
86QT_BEGIN_NAMESPACE
87
88extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp
89#ifdef QT_MAC_USE_COCOA
90extern void *qt_current_nsopengl_context(); // qgl_mac.mm
91#endif
92
93#define QREAL_MAX 9e100
94#define QREAL_MIN -9e100
95
96extern 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
107static int DEBUG_OVERRIDE_FLAG = 0;
108static 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
114static 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
123struct QT_PointF {
124 qreal x;
125 qreal y;
126};
127
128void 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
145void 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
157struct 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
181const 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
193class QGLDrawable {
194public:
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
210private:
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
222void 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
245inline void QGLDrawable::swapBuffers()
246{
247 if (widget) {
248 if (widget->autoBufferSwap())
249 widget->swapBuffers();
250 } else {
251 glFlush();
252 }
253}
254
255inline 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
270inline void QGLDrawable::doneCurrent()
271{
272 if (fbo && !wasBound)
273 fbo->release();
274}
275
276inline 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
295inline 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
313inline 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
326inline 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
339inline 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
346inline 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
359inline bool QGLDrawable::autoFillBackground() const
360{
361 if (widget)
362 return widget->autoFillBackground();
363 else
364 return false;
365}
366
367
368class QOpenGLImmediateModeTessellator;
369class QGLMaskGenerator;
370class QGLOffscreen;
371
372class QGLMaskTextureCache
373{
374public:
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
415private:
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
442Q_GLOBAL_STATIC(QGLMaskTextureCache, qt_mask_texture_cache)
443
444class QGLOffscreen : public QObject
445{
446 Q_OBJECT
447public:
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