From 906d5c5c40183468f9521277c6244a6c46730de6 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 17 Oct 2013 14:53:33 +0200 Subject: Use one render loop per QQuickWindow See the task for the full reasoning behind this patch. The threaded renderloop has been refactored to have one window per thread. This is mostly a simplification of the current code path where for loops over multiple windows are turned into if (window). The QSGContext has been split into two classes, QSGRenderContext for which there is one per OpenGLContext. The rest of the patch is name changes and a couple of cleanups in the hopes of simplifying this change. Task-number: QTBUG-33993 Change-Id: I31c81f9694d7da7474a72333169be38de62613c4 Reviewed-by: Sean Harmer --- src/quick/scenegraph/qsgcontext.cpp | 550 +++++++++++++++++------------------- 1 file changed, 252 insertions(+), 298 deletions(-) (limited to 'src/quick/scenegraph/qsgcontext.cpp') diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index bb8e3c4b36..558711ea0e 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -72,11 +72,8 @@ #include -DEFINE_BOOL_CONFIG_OPTION(qmlFlashMode, QML_FLASH_MODE) -DEFINE_BOOL_CONFIG_OPTION(qmlTranslucentMode, QML_TRANSLUCENT_MODE) DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) - /* Comments about this class from Gunnar: @@ -94,49 +91,32 @@ DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) to defining plugin interfaces.. */ - QT_BEGIN_NAMESPACE class QSGContextPrivate : public QObjectPrivate { public: QSGContextPrivate() - : gl(0) - , depthStencilBufferManager(0) - , distanceFieldCacheManager(0) - #if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2_ANGLE) - , distanceFieldAntialiasing(QSGGlyphNode::HighQualitySubPixelAntialiasing) - #else - , distanceFieldAntialiasing(QSGGlyphNode::GrayAntialiasing) - #endif - , atlasManager(0) - , flashMode(qmlFlashMode()) + : antialiasingMethod(QSGContext::UndecidedAntialiasing) , distanceFieldDisabled(qmlDisableDistanceField()) - , msaa(false) + , distanceFieldAntialiasing( +#if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2_ANGLE) + QSGGlyphNode::HighQualitySubPixelAntialiasing +#else + QSGGlyphNode::GrayAntialiasing +#endif + ) { - renderAlpha = qmlTranslucentMode() ? 0.5 : 1; } ~QSGContextPrivate() { } - QOpenGLContext *gl; - - QMutex textureMutex; - QHash textures; - QSGDepthStencilBufferManager *depthStencilBufferManager; - QSGDistanceFieldGlyphCacheManager *distanceFieldCacheManager; - - QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing; - - QSGAtlasTexture::Manager *atlasManager; - - bool flashMode; - float renderAlpha; + QMutex mutex; + QSGContext::AntialiasingMethod antialiasingMethod; bool distanceFieldDisabled; - - bool msaa; + QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing; }; class QSGTextureCleanupEvent : public QEvent @@ -188,143 +168,158 @@ QSGContext::QSGContext(QObject *parent) : QSGContext::~QSGContext() { - invalidate(); } - - -void QSGContext::invalidate() +void QSGContext::renderContextInitialized(QSGRenderContext *renderContext) { Q_D(QSGContext); - d->textureMutex.lock(); - qDeleteAll(d->textures.values()); - d->textures.clear(); - d->textureMutex.unlock(); - delete d->depthStencilBufferManager; - d->depthStencilBufferManager = 0; - delete d->distanceFieldCacheManager; - d->distanceFieldCacheManager = 0; - d->gl = 0; - - emit invalidated(); - - /* The cleanup of the atlas textures is a bit intruiging. - As part of the cleanup in the threaded render loop, we - do: - 1. call this function - 2. call QCoreApp::sendPostedEvents() to immediately process - any pending deferred deletes. - 3. delete the GL context. - As textures need the atlas manager while cleaning up, the - manager needs to be cleaned up after the textures, so - we post a deleteLater here at the very bottom so it gets - deferred deleted last. - - Another alternative would be to use a QPointer in - QSGAtlasTexture::Texture, but this seemed simpler. - */ - - if (d->atlasManager) { - d->atlasManager->deleteLater(); - d->atlasManager = 0; + d->mutex.lock(); + if (d->antialiasingMethod == UndecidedAntialiasing) { + QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD"); + if (aaType == "msaa") { + d->antialiasingMethod = MsaaAntialiasing; + } else if (aaType == "vertex") { + d->antialiasingMethod = VertexAntialiasing; + } else { + if (renderContext->openglContext()->format().samples() > 0) + d->antialiasingMethod = MsaaAntialiasing; + else + d->antialiasingMethod = VertexAntialiasing; + } } + d->mutex.unlock(); } +void QSGContext::renderContextInvalidated(QSGRenderContext *) +{ +} -QSGTexture *QSGContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window) +/*! + Factory function for scene graph backends of the Rectangle element. + */ +QSGRectangleNode *QSGContext::createRectangleNode() { Q_D(QSGContext); - if (!factory) - return 0; - - d->textureMutex.lock(); - QSGTexture *texture = d->textures.value(factory); - if (!texture) { - if (QQuickDefaultTextureFactory *dtf = qobject_cast(factory)) - texture = createTexture(dtf->image()); - else - texture = factory->createTexture(window); - d->textures.insert(factory, texture); - connect(factory, SIGNAL(destroyed(QObject *)), this, SLOT(textureFactoryDestroyed(QObject *)), Qt::DirectConnection); - } - d->textureMutex.unlock(); - return texture; + return d->antialiasingMethod == MsaaAntialiasing + ? new QSGMultisampleAntialiasing::RectangleNode + : new QSGDefaultRectangleNode; } +/*! + Factory function for scene graph backends of the Image element. + */ +QSGImageNode *QSGContext::createImageNode() +{ + Q_D(QSGContext); + return d->antialiasingMethod == MsaaAntialiasing + ? new QSGMultisampleAntialiasing::ImageNode + : new QSGDefaultImageNode; +} -void QSGContext::textureFactoryDestroyed(QObject *o) +/*! + Factory function for scene graph backends of the Text elements which supports native + text rendering. Used in special cases where native look and feel is a main objective. +*/ +QSGGlyphNode *QSGContext::createNativeGlyphNode(QSGRenderContext *rc) { +#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_ES_2_ANGLE) Q_D(QSGContext); - QQuickTextureFactory *f = static_cast(o); + if (d->distanceFieldDisabled) + return new QSGDefaultGlyphNode; + else + return createGlyphNode(rc); +#else + Q_UNUSED(rc); + return new QSGDefaultGlyphNode; +#endif +} - d->textureMutex.lock(); - QSGTexture *t = d->textures.take(f); - d->textureMutex.unlock(); +/*! + Factory function for scene graph backends of the Text elements; + */ +QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc) +{ + Q_D(QSGContext); - if (t) { - if (t->thread() == thread()) - t->deleteLater(); - else - QCoreApplication::postEvent(this, new QSGTextureCleanupEvent(t)); + if (d->distanceFieldDisabled) { + return createNativeGlyphNode(rc); + } else { + QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(rc); + node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing); + return node; } } - -QOpenGLContext *QSGContext::glContext() const +QSurfaceFormat QSGContext::defaultSurfaceFormat() const { - Q_D(const QSGContext); - return d->gl; + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + if (QQuickWindow::hasDefaultAlphaBuffer()) + format.setAlphaBufferSize(8); + format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + return format; } /*! - Initializes the scene graph context with the GL context \a context. This also - emits the ready() signal so that the QML graph can start building scene graph nodes. + Returns the minimum supported framebuffer object size. */ -void QSGContext::initialize(QOpenGLContext *context) + +QSize QSGContext::minimumFBOSize() const { - Q_D(QSGContext); +#ifdef Q_OS_MAC + return QSize(33, 33); +#else + return QSize(1, 1); +#endif +} - QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD"); - if (aaType == "msaa") { - d->msaa = true; - } else if (aaType == "vertex") { - d->msaa = false; - } else { - if (context->format().samples() > 0) - d->msaa = true; - else - d->msaa = false; - } - // Sanity check the surface format, in case it was overridden by the application - QSurfaceFormat requested = defaultSurfaceFormat(); - QSurfaceFormat actual = context->format(); - if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0) - qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors"); - if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0) - qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors"); - d->atlasManager = new QSGAtlasTexture::Manager(); +/*! + Sets whether or not the scene graph should use the distance field technique to render text + */ +void QSGContext::setDistanceFieldEnabled(bool enabled) +{ + d_func()->distanceFieldDisabled = !enabled; +} - Q_ASSERT(!d->gl); - d->gl = context; - emit initialized(); +/*! + Returns true if the scene graph uses the distance field technique to render text + */ +bool QSGContext::isDistanceFieldEnabled() const +{ + return !d_func()->distanceFieldDisabled; } + + /*! - Returns if the scene graph context is ready or not, meaning that it has a valid - GL context. + Creates a new animation driver. */ -bool QSGContext::isReady() const + +QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent) +{ + return new QAnimationDriver(parent); +} + +QSGRenderContext::QSGRenderContext(QSGContext *context) + : m_gl(0) + , m_sg(context) + , m_atlasManager(0) + , m_depthStencilManager(0) + , m_distanceFieldCacheManager(0) { - Q_D(const QSGContext); - return d->gl; } +QSGRenderContext::~QSGRenderContext() +{ + invalidate(); +} -void QSGContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) +void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) { if (fboId) { QSGBindableFboId bindable(fboId); @@ -335,37 +330,15 @@ void QSGContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) } -/*! - Factory function for scene graph backends of the Rectangle element. - */ -QSGRectangleNode *QSGContext::createRectangleNode() -{ - Q_D(QSGContext); - return d->msaa ? new QSGMultisampleAntialiasing::RectangleNode - : new QSGDefaultRectangleNode; -} - -/*! - Factory function for scene graph backends of the Image element. - */ -QSGImageNode *QSGContext::createImageNode() -{ - Q_D(QSGContext); - return d->msaa ? new QSGMultisampleAntialiasing::ImageNode - : new QSGDefaultImageNode; -} - /*! Factory function for scene graph backends of the distance-field glyph cache. */ -QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont &font) +QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRawFont &font) { - Q_D(QSGContext); - - if (!d->distanceFieldCacheManager) - d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager; + if (!m_distanceFieldCacheManager) + m_distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager; - QSGDistanceFieldGlyphCache *cache = d->distanceFieldCacheManager->cache(font); + QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font); if (!cache) { QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration(); if (platformIntegration != 0 @@ -387,125 +360,114 @@ QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont & QPlatformSharedGraphicsCache::Alpha8); cache = new QSGSharedDistanceFieldGlyphCache(keyName, - sharedGraphicsCache, - d->distanceFieldCacheManager, - glContext(), - font); + sharedGraphicsCache, + m_distanceFieldCacheManager, + font); } } } if (!cache) - cache = new QSGDefaultDistanceFieldGlyphCache(d->distanceFieldCacheManager, glContext(), font); - d->distanceFieldCacheManager->insertCache(font, cache); + cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, font); + m_distanceFieldCacheManager->insertCache(font, cache); } + return cache; } -/*! - Factory function for scene graph backends of the Text elements which supports native - text rendering. Used in special cases where native look and feel is a main objective. -*/ -QSGGlyphNode *QSGContext::createNativeGlyphNode() +#define QSG_RENDERCONTEXT_PROPERTY "_q_sgrendercontext" + +QSGRenderContext *QSGRenderContext::from(QOpenGLContext *context) { -#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_ES_2_ANGLE) - Q_D(QSGContext); - if (d->distanceFieldDisabled) - return new QSGDefaultGlyphNode; - else - return createGlyphNode(); -#else - return new QSGDefaultGlyphNode; -#endif + return qobject_cast(context->property(QSG_RENDERCONTEXT_PROPERTY).value()); } -/*! - Factory function for scene graph backends of the Text elements; - */ -QSGGlyphNode *QSGContext::createGlyphNode() +void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine) { - Q_D(QSGContext); - - if (d->distanceFieldDisabled) { - return createNativeGlyphNode(); - } else { - QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(this); - node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing); - return node; - } + m_fontEnginesToClean << engine; } /*! - Factory function for the scene graph renderers. - - The renderers are used for the toplevel renderer and once for every - QQuickShaderEffectSource used in the QML scene. + Initializes the scene graph render context with the GL context \a context. This also + emits the ready() signal so that the QML graph can start building scene graph nodes. */ -QSGRenderer *QSGContext::createRenderer() +void QSGRenderContext::initialize(QOpenGLContext *context) { - return new QSGBatchRenderer::Renderer(this); -} - + // Sanity check the surface format, in case it was overridden by the application + QSurfaceFormat requested = m_sg->defaultSurfaceFormat(); + QSurfaceFormat actual = context->format(); + if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0) + qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors"); + if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0) + qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors"); + if (!m_atlasManager) + m_atlasManager = new QSGAtlasTexture::Manager(); + Q_ASSERT_X(!m_gl, "QSGRenderContext::initialize", "already initialized!"); + m_gl = context; + m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this)); + m_sg->renderContextInitialized(this); -QSurfaceFormat QSGContext::defaultSurfaceFormat() const -{ - QSurfaceFormat format; - format.setDepthBufferSize(24); - format.setStencilBufferSize(8); - if (QQuickWindow::hasDefaultAlphaBuffer()) - format.setAlphaBufferSize(8); - format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - return format; + emit initialized(); } - -/*! - Factory function for texture objects. - - If \a image is a valid image, the QSGTexture::setImage function - will be called with \a image as argument. - */ - -QSGTexture *QSGContext::createTexture(const QImage &image) const +void QSGRenderContext::invalidate() { - Q_D(const QSGContext); - QSGTexture *at = d->atlasManager->create(image); - if (at) - return at; - return createTextureNoAtlas(image); -} + if (!m_gl) + return; + + qDeleteAll(m_textures.values()); + m_textures.clear(); + + /* The cleanup of the atlas textures is a bit intriguing. + As part of the cleanup in the threaded render loop, we + do: + 1. call this function + 2. call QCoreApp::sendPostedEvents() to immediately process + any pending deferred deletes. + 3. delete the GL context. + + As textures need the atlas manager while cleaning up, the + manager needs to be cleaned up after the textures, so + we post a deleteLater here at the very bottom so it gets + deferred deleted last. + + Another alternative would be to use a QPointer in + QSGAtlasTexture::Texture, but this seemed simpler. + */ + m_atlasManager->invalidate(); + m_atlasManager->deleteLater(); + m_atlasManager = 0; + + // The following piece of code will read/write to the font engine's caches, + // potentially from different threads. However, this is safe because this + // code is only called from QQuickWindow's shutdown which is called + // only when the GUI is blocked, and multiple threads will call it in + // sequence. (see qsgdefaultglyphnode_p.cpp's init()) + for (QSet::const_iterator it = m_fontEnginesToClean.constBegin(), + end = m_fontEnginesToClean.constEnd(); it != end; ++it) { + (*it)->clearGlyphCache(m_gl); + } -QSGTexture *QSGContext::createTextureNoAtlas(const QImage &image) const -{ - QSGPlainTexture *t = new QSGPlainTexture(); - if (!image.isNull()) - t->setImage(image); - return t; -} + delete m_depthStencilManager; + m_depthStencilManager = 0; -/*! - Returns the minimum supported framebuffer object size. - */ - -QSize QSGContext::minimumFBOSize() const -{ -#ifdef Q_OS_MAC - return QSize(33, 33); -#else - return QSize(1, 1); -#endif -} + delete m_distanceFieldCacheManager; + m_distanceFieldCacheManager = 0; + m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant()); + m_gl = 0; + m_sg->renderContextInvalidated(this); + emit invalidated(); +} /*! Returns a shared pointer to a depth stencil buffer that can be used with \a fbo. */ -QSharedPointer QSGContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo) +QSharedPointer QSGRenderContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo) { - Q_D(QSGContext); - if (!d->gl) + if (!m_gl) return QSharedPointer(); QSGDepthStencilBufferManager *manager = depthStencilBufferManager(); QSGDepthStencilBuffer::Format format; @@ -514,7 +476,7 @@ QSharedPointer QSGContext::depthStencilBufferForFbo(QOpen format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment; QSharedPointer buffer = manager->bufferForFormat(format); if (buffer.isNull()) { - buffer = QSharedPointer(new QSGDefaultDepthStencilBuffer(d->gl, format)); + buffer = QSharedPointer(new QSGDefaultDepthStencilBuffer(m_gl, format)); manager->insertBuffer(buffer); } return buffer; @@ -524,89 +486,81 @@ QSharedPointer QSGContext::depthStencilBufferForFbo(QOpen Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom implementations of \l depthStencilBufferForFbo(). */ -QSGDepthStencilBufferManager *QSGContext::depthStencilBufferManager() +QSGDepthStencilBufferManager *QSGRenderContext::depthStencilBufferManager() { - Q_D(QSGContext); - if (!d->gl) + if (!m_gl) return 0; - if (!d->depthStencilBufferManager) - d->depthStencilBufferManager = new QSGDepthStencilBufferManager(d->gl); - return d->depthStencilBufferManager; + if (!m_depthStencilManager) + m_depthStencilManager = new QSGDepthStencilBufferManager(m_gl); + return m_depthStencilManager; } /*! - Sets whether the scene graph should render with flashing update rectangles or not - */ - -void QSGContext::setFlashModeEnabled(bool enabled) -{ - d_func()->flashMode = enabled; -} - + Factory function for texture objects. -/*! - Returns true if the scene graph should be rendered with flashing update rectangles + If \a image is a valid image, the QSGTexture::setImage function + will be called with \a image as argument. */ -bool QSGContext::isFlashModeEnabled() const + +QSGTexture *QSGRenderContext::createTexture(const QImage &image) const { - return d_func()->flashMode; + QSGTexture *t = m_atlasManager->create(image); + if (t) + return t; + return createTextureNoAtlas(image); } - -/*! - Sets the toplevel opacity for rendering. This value will be multiplied into all - drawing calls where possible. - - The default value is 1. Any other value will cause artifacts and is primarily - useful for debugging. - */ -void QSGContext::setRenderAlpha(qreal renderAlpha) +QSGTexture *QSGRenderContext::createTextureNoAtlas(const QImage &image) const { - d_func()->renderAlpha = renderAlpha; + QSGPlainTexture *t = new QSGPlainTexture(); + if (!image.isNull()) + t->setImage(image); + return t; } - /*! - Returns the toplevel opacity used for rendering. - - The default value is 1. + Factory function for the scene graph renderers. - \sa setRenderAlpha() + The renderers are used for the toplevel renderer and once for every + QQuickShaderEffectSource used in the QML scene. */ -qreal QSGContext::renderAlpha() const +QSGRenderer *QSGRenderContext::createRenderer() { - return d_func()->renderAlpha; + return new QSGBatchRenderer::Renderer(this); } - -/*! - Sets whether or not the scene graph should use the distance field technique to render text - */ -void QSGContext::setDistanceFieldEnabled(bool enabled) +QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window) { - d_func()->distanceFieldDisabled = !enabled; -} - + if (!factory) + return 0; -/*! - Returns true if the scene graph uses the distance field technique to render text - */ -bool QSGContext::isDistanceFieldEnabled() const -{ - return !d_func()->distanceFieldDisabled; -} + m_mutex.lock(); + QSGTexture *texture = m_textures.value(factory); + m_mutex.unlock(); + if (!texture) { + if (QQuickDefaultTextureFactory *dtf = qobject_cast(factory)) + texture = createTexture(dtf->image()); + else + texture = factory->createTexture(window); + m_mutex.lock(); + m_textures.insert(factory, texture); + m_mutex.unlock(); -/*! - Creates a new animation driver. - */ + connect(factory, SIGNAL(destroyed(QObject *)), this, SLOT(textureFactoryDestroyed(QObject *)), Qt::DirectConnection); + } + return texture; +} -QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent) +void QSGRenderContext::textureFactoryDestroyed(QObject *o) { - return new QAnimationDriver(parent); + m_mutex.lock(); + QSGTexture *t = m_textures.take(static_cast(o)); + m_mutex.unlock(); + if (t) + t->deleteLater(); } - QT_END_NAMESPACE -- cgit v1.2.3 From 4a7f1326e3d342148a4a9147505a4d8d531b4a06 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Wed, 30 Oct 2013 14:09:18 +0100 Subject: Work around Nouveau driver bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I25311a2bd88f41087352e0a43ba505f4e27b7e85 Reviewed-by: Jørgen Lind --- src/quick/scenegraph/qsgcontext.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/quick/scenegraph/qsgcontext.cpp') diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 558711ea0e..4fbefb37d8 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -311,6 +311,7 @@ QSGRenderContext::QSGRenderContext(QSGContext *context) , m_atlasManager(0) , m_depthStencilManager(0) , m_distanceFieldCacheManager(0) + , m_brokenIBOs(false) { } @@ -408,6 +409,12 @@ void QSGRenderContext::initialize(QOpenGLContext *context) m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this)); m_sg->renderContextInitialized(this); +#ifdef Q_OS_LINUX + const char *vendor = (const char *) glGetString(GL_VENDOR); + if (strstr(vendor, "nouveau")) + m_brokenIBOs = true; +#endif + emit initialized(); } -- cgit v1.2.3 From 5b05a78d0055757adb3b2703ea990e07dbcd145a Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Wed, 30 Oct 2013 14:32:54 +0100 Subject: Added private API for enabling sharing between the QQuickwindow instances. This API is primarily a hook which is needed by the Qt WebEngine to set up sharing with the scene graph's OpenGL contexts. Change-Id: I5bb03abd9ab99f502db8e413fe838a8b30365b8d Reviewed-by: Jocelyn Turcotte --- src/quick/scenegraph/qsgcontext.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/quick/scenegraph/qsgcontext.cpp') diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 4fbefb37d8..c6dbf350b6 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -117,8 +117,12 @@ public: QSGContext::AntialiasingMethod antialiasingMethod; bool distanceFieldDisabled; QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing; + + static QOpenGLContext *sharedOpenGLContext; }; +QOpenGLContext *QSGContextPrivate::sharedOpenGLContext = 0; + class QSGTextureCleanupEvent : public QEvent { public: @@ -170,6 +174,20 @@ QSGContext::~QSGContext() { } +/*! + * This function is used by the Qt WebEngine to set up context sharing + * across multiple windows. Do not use it for any other purpose. + */ +void QSGContext::setSharedOpenGLContext(QOpenGLContext *context) +{ + QSGContextPrivate::sharedOpenGLContext = context; +} + +QOpenGLContext *QSGContext::sharedOpenGLContext() +{ + return QSGContextPrivate::sharedOpenGLContext; +} + void QSGContext::renderContextInitialized(QSGRenderContext *renderContext) { Q_D(QSGContext); -- cgit v1.2.3 From 2a1fc76f4ed1680e78b740c47fa736768aed82e9 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 31 Oct 2013 09:45:57 +0100 Subject: Added QSG_INFO=1 environment variable to spit out graphics info Change-Id: I12bc0bc475b3e99185aefcd58eef5a0fb5e9852e Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/scenegraph/qsgcontext.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/quick/scenegraph/qsgcontext.cpp') diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index c6dbf350b6..4ccbaca08e 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -206,6 +206,16 @@ void QSGContext::renderContextInitialized(QSGRenderContext *renderContext) d->antialiasingMethod = VertexAntialiasing; } } + + static bool dumped = false; + if (!dumped && qEnvironmentVariableIsSet("QSG_INFO")) { + dumped = true; + qDebug() << "GL_VENDOR: " << (const char *) glGetString(GL_VENDOR); + qDebug() << "GL_RENDERER: " << (const char *) glGetString(GL_RENDERER); + qDebug() << "GL_VERSION: " << (const char *) glGetString(GL_VERSION); + qDebug() << "GL_EXTENSIONS:\n " << QByteArray((const char *) glGetString(GL_EXTENSIONS)).replace(" ", "\n ").constData(); + } + d->mutex.unlock(); } -- cgit v1.2.3 From 9d90a33c7f83a49919133cd8647b0503e18e6444 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 5 Nov 2013 15:17:03 +0100 Subject: Fix crash when invalidating QSGContext. A pointer list was not cleared when invalidating the context, potentially holding dangling pointers after that. Change-Id: I0618c54ffa67b31b115901e8be3a6d3cd16dc844 Reviewed-by: Gunnar Sletta --- src/quick/scenegraph/qsgcontext.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/quick/scenegraph/qsgcontext.cpp') diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 4ccbaca08e..1f219e735f 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -483,6 +483,7 @@ void QSGRenderContext::invalidate() end = m_fontEnginesToClean.constEnd(); it != end; ++it) { (*it)->clearGlyphCache(m_gl); } + m_fontEnginesToClean.clear(); delete m_depthStencilManager; m_depthStencilManager = 0; -- cgit v1.2.3 From 3afffa47feabc80e1bc20ffd2143a722a1c360a2 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Wed, 6 Nov 2013 13:07:58 +0000 Subject: Adapt Qt Quick 2 renderer to work with OpenGL Core Profile The basic approach is to have the batched renderer create and bind a vertex array object if it detects we are using an OpenGL Core profile context. The VAO is bound for the duration of the QQ2 renderer's work cycle and unbound at the end so as to not interfere with any other VAO's a user may wish to use. All shaders have been copied and ported to be compliant with the GLSL 150 core specification which is the minimum for a Core profile context (OpenGL 3.2 Core). We are not using any newer features as yet so this will work anywhere we can get a Core profile context. The QSGShaderSourceBuilder class has been extended to resolve any requests for shaders to the same basefilename with "_core" appended prior to any file extension. This could be extended in the future to allow version, or GPU or platform specific shaders. The QSGShaderSourceBuilder has also been extended to allow it to insert #define definitions in the prologue of a shader. Any such definition is inserted: * After the last #extension directive (if any are found) * Otherwise after the #version directive (if found) * Otherwise at the start of the shader source This is required by the custom particle shaders which make extensive use of such #defines. In addition the mechanism used by the distance field glyph cache to extend the cache with new glyphs has been modified to work (and work more efficiently) when using a Core profile context. Rather than using a shader program and a buffer filling quad to blit the old texture into the new cache texture, we instead use the technique of framebuffer blitting. The existing fallback implementation using glTexSubImage2D() is still available if needed. The DECLARATIVE_EXAMPLE_MAIN macro has been extended to allow easy testing of any of the QtDeclarative examples with a core profile context. Just run the example with QT_QUICK_CORE_PROFILE=1 ./text for e.g. The only ones that may not work out of the box are those that provide GLSL shader source e.g. the customparticles or shader effect examples. These work fine if the shader source is adapted to GLSL 150 core. In the future it may be a good idea to expose some context property to QML that the user can use to determine what shader source variation to provide to Qt Quick. Along these lines it would also be very nice to allow the provision of shader source to ShaderEffect or CustomParticle from a separate source file just as we now do within Qt Quick. Task-number: QTBUG-32050 Change-Id: Ia6e9f06dbb8508af9ae03c6b60fb418b4cc9e41f Reviewed-by: Lars Knoll --- src/quick/scenegraph/qsgcontext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/quick/scenegraph/qsgcontext.cpp') diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 1f219e735f..fa095b8165 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -391,12 +391,13 @@ QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRaw cache = new QSGSharedDistanceFieldGlyphCache(keyName, sharedGraphicsCache, m_distanceFieldCacheManager, + openglContext(), font); } } } if (!cache) - cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, font); + cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); m_distanceFieldCacheManager->insertCache(font, cache); } -- cgit v1.2.3 From 3f1245aabc125c416f26028a12923f9055765e4f Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Wed, 20 Nov 2013 12:05:49 +0100 Subject: Enforce window rendering in sequence on llvmpipe. When rendering multiple windows in parallel on llvmpipe we end up with crashes deep inside llvmpipe as multiple threads seem to access unprotected resources. Work around this bug by enforcing that scene graph rendering happens on one window at a time. Task-number: QTCREATORBUG-10666 Change-Id: I2f734e8f653b2a9b4108eb189280ab922581e2c0 Reviewed-by: Kai Koehne --- src/quick/scenegraph/qsgcontext.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/quick/scenegraph/qsgcontext.cpp') diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index fa095b8165..afde7939f2 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -340,6 +340,7 @@ QSGRenderContext::QSGRenderContext(QSGContext *context) , m_depthStencilManager(0) , m_distanceFieldCacheManager(0) , m_brokenIBOs(false) + , m_serializedRender(false) { } @@ -348,8 +349,13 @@ QSGRenderContext::~QSGRenderContext() invalidate(); } +static QBasicMutex qsg_framerender_mutex; + void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) { + if (m_serializedRender) + qsg_framerender_mutex.lock(); + if (fboId) { QSGBindableFboId bindable(fboId); renderer->renderScene(bindable); @@ -357,6 +363,9 @@ void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) renderer->renderScene(); } + if (m_serializedRender) + qsg_framerender_mutex.unlock(); + } /*! @@ -442,6 +451,9 @@ void QSGRenderContext::initialize(QOpenGLContext *context) const char *vendor = (const char *) glGetString(GL_VENDOR); if (strstr(vendor, "nouveau")) m_brokenIBOs = true; + const char *renderer = (const char *) glGetString(GL_RENDERER); + if (strstr(renderer, "llvmpipe")) + m_serializedRender = true; #endif emit initialized(); -- cgit v1.2.3