Update to 5.0.0-beta1
[profile/ivi/qtdeclarative.git] / src / quick / scenegraph / qsgcontext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtQuick/private/qsgcontext_p.h>
43 #include <QtQuick/private/qsgdefaultrenderer_p.h>
44 #include <QtQuick/private/qsgdistancefieldutil_p.h>
45 #include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h>
46 #include <QtQuick/private/qsgdefaultrectanglenode_p.h>
47 #include <QtQuick/private/qsgdefaultimagenode_p.h>
48 #include <QtQuick/private/qsgdefaultglyphnode_p.h>
49 #include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
50 #include <QtQuick/private/qsgshareddistancefieldglyphcache_p.h>
51
52 #include <QtQuick/private/qsgtexture_p.h>
53 #include <QtQuick/private/qquickpixmapcache_p.h>
54
55 #include <QGuiApplication>
56 #include <QOpenGLContext>
57 #include <QtGui/qopenglframebufferobject.h>
58
59 #include <private/qqmlglobal_p.h>
60
61 #include <QtQuick/private/qsgtexture_p.h>
62 #include <QtGui/private/qguiapplication_p.h>
63 #include <qpa/qplatformintegration.h>
64
65 #include <qpa/qplatformsharedgraphicscache.h>
66
67 #include <private/qobject_p.h>
68 #include <qmutex.h>
69
70 DEFINE_BOOL_CONFIG_OPTION(qmlFlashMode, QML_FLASH_MODE)
71 DEFINE_BOOL_CONFIG_OPTION(qmlTranslucentMode, QML_TRANSLUCENT_MODE)
72 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
73
74 /*
75     Comments about this class from Gunnar:
76
77     The QSGContext class is right now two things.. The first is the
78     adaptation layer and central storage ground for all the things
79     in the scene graph, like textures and materials. This part really
80     belongs inside the scene graph coreapi.
81
82     The other part is the QML adaptation classes, like how to implement
83     rectangle nodes. This is not part of the scene graph core API, but
84     more part of the QML adaptation of scene graph.
85
86     If we ever move the scene graph core API into its own thing, this class
87     needs to be split in two. Right now its one because we're lazy when it comes
88     to defining plugin interfaces..
89 */
90
91
92 QT_BEGIN_NAMESPACE
93
94 class QSGContextPrivate : public QObjectPrivate
95 {
96 public:
97     QSGContextPrivate()
98         : gl(0)
99         , depthStencilBufferManager(0)
100         , distanceFieldCacheManager(0)
101     #ifndef QT_OPENGL_ES
102         , distanceFieldAntialiasing(QSGGlyphNode::HighQualitySubPixelAntialiasing)
103     #else
104         , distanceFieldAntialiasing(QSGGlyphNode::GrayAntialiasing)
105     #endif
106         , flashMode(qmlFlashMode())
107         , distanceFieldDisabled(qmlDisableDistanceField())
108     {
109         renderAlpha = qmlTranslucentMode() ? 0.5 : 1;
110     }
111
112     ~QSGContextPrivate()
113     {
114     }
115
116     QOpenGLContext *gl;
117
118     QHash<QSGMaterialType *, QSGMaterialShader *> materials;
119     QMutex textureMutex;
120     QHash<QQuickTextureFactory *, QSGTexture *> textures;
121     QSGDepthStencilBufferManager *depthStencilBufferManager;
122     QSGDistanceFieldGlyphCacheManager *distanceFieldCacheManager;
123
124     QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing;
125
126     bool flashMode;
127     float renderAlpha;
128     bool distanceFieldDisabled;
129 };
130
131 class QSGTextureCleanupEvent : public QEvent
132 {
133 public:
134     QSGTextureCleanupEvent(QSGTexture *t) : QEvent(QEvent::User), texture(t) { }
135     ~QSGTextureCleanupEvent() { delete texture; }
136     QSGTexture *texture;
137 };
138
139 /*!
140     \class QSGContext
141
142     \brief The QSGContext holds the scene graph entry points for one QML engine.
143
144     The context is not ready for use until it has a QOpenGLContext. Once that happens,
145     the scene graph population can start.
146
147     \internal
148  */
149
150 QSGContext::QSGContext(QObject *parent) :
151     QObject(*(new QSGContextPrivate), parent)
152 {
153     Q_D(QSGContext);
154     static bool doSubpixel = qApp->arguments().contains(QLatin1String("--text-subpixel-antialiasing"));
155     static bool doLowQualSubpixel = qApp->arguments().contains(QLatin1String("--text-subpixel-antialiasing-lowq"));
156     static bool doGray = qApp->arguments().contains(QLatin1String("--text-gray-antialiasing"));
157     if (doSubpixel)
158         d->distanceFieldAntialiasing = QSGGlyphNode::HighQualitySubPixelAntialiasing;
159     else if (doLowQualSubpixel)
160         d->distanceFieldAntialiasing = QSGGlyphNode::LowQualitySubPixelAntialiasing;
161     else if (doGray)
162        d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
163 }
164
165
166 QSGContext::~QSGContext()
167 {
168     invalidate();
169 }
170
171
172
173 void QSGContext::invalidate()
174 {
175     Q_D(QSGContext);
176     d->textureMutex.lock();
177     qDeleteAll(d->textures.values());
178     d->textures.clear();
179     d->textureMutex.unlock();
180     qDeleteAll(d->materials.values());
181     d->materials.clear();
182     delete d->depthStencilBufferManager;
183     d->depthStencilBufferManager = 0;
184     delete d->distanceFieldCacheManager;
185     d->distanceFieldCacheManager = 0;
186
187     d->gl = 0;
188
189     emit invalidated();
190 }
191
192
193 QSGTexture *QSGContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window)
194 {
195     Q_D(QSGContext);
196     if (!factory)
197         return 0;
198
199     d->textureMutex.lock();
200     QSGTexture *texture = d->textures.value(factory);
201     if (!texture) {
202         if (QQuickDefaultTextureFactory *dtf = qobject_cast<QQuickDefaultTextureFactory *>(factory))
203             texture = createTexture(dtf->image());
204         else
205             texture = factory->createTexture(window);
206         d->textures.insert(factory, texture);
207         connect(factory, SIGNAL(destroyed(QObject *)), this, SLOT(textureFactoryDestroyed(QObject *)), Qt::DirectConnection);
208     }
209     d->textureMutex.unlock();
210     return texture;
211 }
212
213
214 void QSGContext::textureFactoryDestroyed(QObject *o)
215 {
216     Q_D(QSGContext);
217     QQuickTextureFactory *f = static_cast<QQuickTextureFactory *>(o);
218
219     d->textureMutex.lock();
220     QSGTexture *t = d->textures.take(f);
221     d->textureMutex.unlock();
222
223     if (t) {
224         if (t->thread() == thread())
225             t->deleteLater();
226         else
227             QCoreApplication::postEvent(this, new QSGTextureCleanupEvent(t));
228     }
229 }
230
231
232 QOpenGLContext *QSGContext::glContext() const
233 {
234     Q_D(const QSGContext);
235     return d->gl;
236 }
237
238 /*!
239     Initializes the scene graph context with the GL context \a context. This also
240     emits the ready() signal so that the QML graph can start building scene graph nodes.
241  */
242 void QSGContext::initialize(QOpenGLContext *context)
243 {
244     Q_D(QSGContext);
245
246     Q_ASSERT(!d->gl);
247     d->gl = context;
248
249     emit initialized();
250 }
251
252
253 /*!
254     Returns if the scene graph context is ready or not, meaning that it has a valid
255     GL context.
256  */
257 bool QSGContext::isReady() const
258 {
259     Q_D(const QSGContext);
260     return d->gl;
261 }
262
263
264 void QSGContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
265 {
266     if (fboId) {
267         QSGBindableFboId bindable(fboId);
268         renderer->renderScene(bindable);
269     } else {
270         renderer->renderScene();
271     }
272
273 }
274
275 /*!
276     Factory function for scene graph backends of the Rectangle element.
277  */
278 QSGRectangleNode *QSGContext::createRectangleNode()
279 {
280     return new QSGDefaultRectangleNode;
281 }
282
283 /*!
284     Factory function for scene graph backends of the Image element.
285  */
286 QSGImageNode *QSGContext::createImageNode()
287 {
288     return new QSGDefaultImageNode;
289 }
290
291 /*!
292     Factory function for scene graph backends of the distance-field glyph cache.
293  */
294 QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont &font)
295 {
296     Q_D(QSGContext);
297
298     if (!d->distanceFieldCacheManager)
299         d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager;
300
301     QSGDistanceFieldGlyphCache *cache = d->distanceFieldCacheManager->cache(font);
302     if (!cache) {
303         QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
304         if (platformIntegration != 0
305             && platformIntegration->hasCapability(QPlatformIntegration::SharedGraphicsCache)) {
306             QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine;
307             if (!fe->faceId().filename.isEmpty()) {
308                 QByteArray keyName = fe->faceId().filename;
309                 if (font.style() != QFont::StyleNormal)
310                     keyName += QByteArray(" I");
311                 if (font.weight() != QFont::Normal)
312                     keyName += ' ' + QByteArray::number(font.weight());
313                 keyName += QByteArray(" DF");
314                 QPlatformSharedGraphicsCache *sharedGraphicsCache =
315                         platformIntegration->createPlatformSharedGraphicsCache(keyName);
316
317                 if (sharedGraphicsCache != 0) {
318                     sharedGraphicsCache->ensureCacheInitialized(keyName,
319                                                                 QPlatformSharedGraphicsCache::OpenGLTexture,
320                                                                 QPlatformSharedGraphicsCache::Alpha8);
321
322                     cache = new QSGSharedDistanceFieldGlyphCache(keyName,
323                                                                 sharedGraphicsCache,
324                                                                 d->distanceFieldCacheManager,
325                                                                 glContext(),
326                                                                 font);
327                 }
328             }
329         }
330         if (!cache)
331             cache = new QSGDefaultDistanceFieldGlyphCache(d->distanceFieldCacheManager, glContext(), font);
332         d->distanceFieldCacheManager->insertCache(font, cache);
333     }
334     return cache;
335 }
336
337 /*!
338     Factory function for scene graph backends of the Text elements which supports native
339     text rendering. Used in special cases where native look and feel is a main objective.
340 */
341 QSGGlyphNode *QSGContext::createNativeGlyphNode()
342 {
343     return new QSGDefaultGlyphNode;
344 }
345
346 /*!
347     Factory function for scene graph backends of the Text elements;
348  */
349 QSGGlyphNode *QSGContext::createGlyphNode()
350 {
351     Q_D(QSGContext);
352
353     if (d->distanceFieldDisabled) {
354         return createNativeGlyphNode();
355     } else {
356         QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(this);
357         node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing);
358         return node;
359     }
360 }
361
362 /*!
363     Factory function for the scene graph renderers.
364
365     The renderers are used for the toplevel renderer and once for every
366     QQuickShaderEffectSource used in the QML scene.
367  */
368 QSGRenderer *QSGContext::createRenderer()
369 {
370     return new QSGDefaultRenderer(this);
371 }
372
373
374
375
376 QSurfaceFormat QSGContext::defaultSurfaceFormat() const
377 {
378     QSurfaceFormat format;
379     format.setDepthBufferSize(24);
380     format.setStencilBufferSize(8);
381     format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
382     return format;
383 }
384
385
386 /*!
387     Factory function for texture objects.
388
389     If \a image is a valid image, the QSGTexture::setImage function
390     will be called with \a image as argument.
391  */
392
393 QSGTexture *QSGContext::createTexture(const QImage &image) const
394 {
395     QSGPlainTexture *t = new QSGPlainTexture();
396     if (!image.isNull())
397         t->setImage(image);
398     return t;
399 }
400
401
402
403 /*!
404     Returns the minimum supported framebuffer object size.
405  */
406
407 QSize QSGContext::minimumFBOSize() const
408 {
409 #ifdef Q_OS_MAC
410     return QSize(33, 33);
411 #else
412     return QSize(1, 1);
413 #endif
414 }
415
416
417
418 /*!
419     Returns a shared pointer to a depth stencil buffer that can be used with \a fbo.
420   */
421 QSharedPointer<QSGDepthStencilBuffer> QSGContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
422 {
423     Q_D(QSGContext);
424     if (!d->gl)
425         return QSharedPointer<QSGDepthStencilBuffer>();
426     QSGDepthStencilBufferManager *manager = depthStencilBufferManager();
427     QSGDepthStencilBuffer::Format format;
428     format.size = fbo->size();
429     format.samples = fbo->format().samples();
430     format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment;
431     QSharedPointer<QSGDepthStencilBuffer> buffer = manager->bufferForFormat(format);
432     if (buffer.isNull()) {
433         buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(d->gl, format));
434         manager->insertBuffer(buffer);
435     }
436     return buffer;
437 }
438
439 /*!
440     Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom
441     implementations of \l depthStencilBufferForFbo().
442   */
443 QSGDepthStencilBufferManager *QSGContext::depthStencilBufferManager()
444 {
445     Q_D(QSGContext);
446     if (!d->gl)
447         return 0;
448     if (!d->depthStencilBufferManager)
449         d->depthStencilBufferManager = new QSGDepthStencilBufferManager(d->gl);
450     return d->depthStencilBufferManager;
451 }
452
453
454 /*!
455     Returns a material shader for the given material.
456  */
457
458 QSGMaterialShader *QSGContext::prepareMaterial(QSGMaterial *material)
459 {
460     Q_D(QSGContext);
461     QSGMaterialType *type = material->type();
462     QSGMaterialShader *shader = d->materials.value(type);
463     if (shader)
464         return shader;
465
466     shader = material->createShader();
467     shader->compile();
468     shader->initialize();
469     d->materials[type] = shader;
470
471     return shader;
472 }
473
474
475
476 /*!
477     Sets whether the scene graph should render with flashing update rectangles or not
478   */
479
480 void QSGContext::setFlashModeEnabled(bool enabled)
481 {
482     d_func()->flashMode = enabled;
483 }
484
485
486 /*!
487     Returns true if the scene graph should be rendered with flashing update rectangles
488  */
489 bool QSGContext::isFlashModeEnabled() const
490 {
491     return d_func()->flashMode;
492 }
493
494
495 /*!
496     Sets the toplevel opacity for rendering. This value will be multiplied into all
497     drawing calls where possible.
498
499     The default value is 1. Any other value will cause artifacts and is primarily
500     useful for debugging.
501  */
502 void QSGContext::setRenderAlpha(qreal renderAlpha)
503 {
504     d_func()->renderAlpha = renderAlpha;
505 }
506
507
508 /*!
509     Returns the toplevel opacity used for rendering.
510
511     The default value is 1.
512
513     \sa setRenderAlpha()
514  */
515 qreal QSGContext::renderAlpha() const
516 {
517     return d_func()->renderAlpha;
518 }
519
520
521 /*!
522     Sets whether or not the scene graph should use the distance field technique to render text
523   */
524 void QSGContext::setDistanceFieldEnabled(bool enabled)
525 {
526     d_func()->distanceFieldDisabled = !enabled;
527 }
528
529
530 /*!
531     Returns true if the scene graph uses the distance field technique to render text
532  */
533 bool QSGContext::isDistanceFieldEnabled() const
534 {
535     return !d_func()->distanceFieldDisabled;
536 }
537
538
539
540 /*!
541     Creates a new animation driver.
542  */
543
544 QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
545 {
546     return new QAnimationDriver(parent);
547 }
548
549
550 QT_END_NAMESPACE