47cc6670f2da27083c0579ce4c024c1234a7a78a
[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, QQuickCanvas *canvas)
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(canvas);
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     return format;
382 }
383
384
385 /*!
386     Factory function for texture objects.
387
388     If \a image is a valid image, the QSGTexture::setImage function
389     will be called with \a image as argument.
390  */
391
392 QSGTexture *QSGContext::createTexture(const QImage &image) const
393 {
394     QSGPlainTexture *t = new QSGPlainTexture();
395     if (!image.isNull())
396         t->setImage(image);
397     return t;
398 }
399
400
401
402 /*!
403     Returns the minimum supported framebuffer object size.
404  */
405
406 QSize QSGContext::minimumFBOSize() const
407 {
408 #ifdef Q_OS_MAC
409     return QSize(33, 33);
410 #else
411     return QSize(1, 1);
412 #endif
413 }
414
415
416
417 /*!
418     Returns a shared pointer to a depth stencil buffer that can be used with \a fbo.
419   */
420 QSharedPointer<QSGDepthStencilBuffer> QSGContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
421 {
422     Q_D(QSGContext);
423     if (!d->gl)
424         return QSharedPointer<QSGDepthStencilBuffer>();
425     QSGDepthStencilBufferManager *manager = depthStencilBufferManager();
426     QSGDepthStencilBuffer::Format format;
427     format.size = fbo->size();
428     format.samples = fbo->format().samples();
429     format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment;
430     QSharedPointer<QSGDepthStencilBuffer> buffer = manager->bufferForFormat(format);
431     if (buffer.isNull()) {
432         buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(d->gl, format));
433         manager->insertBuffer(buffer);
434     }
435     return buffer;
436 }
437
438 /*!
439     Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom
440     implementations of \l depthStencilBufferForFbo().
441   */
442 QSGDepthStencilBufferManager *QSGContext::depthStencilBufferManager()
443 {
444     Q_D(QSGContext);
445     if (!d->gl)
446         return 0;
447     if (!d->depthStencilBufferManager)
448         d->depthStencilBufferManager = new QSGDepthStencilBufferManager(d->gl);
449     return d->depthStencilBufferManager;
450 }
451
452
453 /*!
454     Returns a material shader for the given material.
455  */
456
457 QSGMaterialShader *QSGContext::prepareMaterial(QSGMaterial *material)
458 {
459     Q_D(QSGContext);
460     QSGMaterialType *type = material->type();
461     QSGMaterialShader *shader = d->materials.value(type);
462     if (shader)
463         return shader;
464
465     shader = material->createShader();
466     shader->compile();
467     shader->initialize();
468     d->materials[type] = shader;
469
470     return shader;
471 }
472
473
474
475 /*!
476     Sets whether the scene graph should render with flashing update rectangles or not
477   */
478
479 void QSGContext::setFlashModeEnabled(bool enabled)
480 {
481     d_func()->flashMode = enabled;
482 }
483
484
485 /*!
486     Returns true if the scene graph should be rendered with flashing update rectangles
487  */
488 bool QSGContext::isFlashModeEnabled() const
489 {
490     return d_func()->flashMode;
491 }
492
493
494 /*!
495     Sets the toplevel opacity for rendering. This value will be multiplied into all
496     drawing calls where possible.
497
498     The default value is 1. Any other value will cause artifacts and is primarily
499     useful for debugging.
500  */
501 void QSGContext::setRenderAlpha(qreal renderAlpha)
502 {
503     d_func()->renderAlpha = renderAlpha;
504 }
505
506
507 /*!
508     Returns the toplevel opacity used for rendering.
509
510     The default value is 1.
511
512     \sa setRenderAlpha()
513  */
514 qreal QSGContext::renderAlpha() const
515 {
516     return d_func()->renderAlpha;
517 }
518
519
520 /*!
521     Sets whether or not the scene graph should use the distance field technique to render text
522   */
523 void QSGContext::setDistanceFieldEnabled(bool enabled)
524 {
525     d_func()->distanceFieldDisabled = !enabled;
526 }
527
528
529 /*!
530     Returns true if the scene graph uses the distance field technique to render text
531  */
532 bool QSGContext::isDistanceFieldEnabled() const
533 {
534     return !d_func()->distanceFieldDisabled;
535 }
536
537
538
539 /*!
540     Creates a new animation driver.
541  */
542
543 QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
544 {
545     return new QAnimationDriver(parent);
546 }
547
548
549 QT_END_NAMESPACE