From bb1504c271e18a26ad6ac20d55485c167671b1c2 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 5 Nov 2015 15:00:58 +0200 Subject: Fix QNetworkAccessManager crash at application shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed textures to use a common network access manager from QML engine instead of each of them creating their own. Change-Id: Ia70a756edc7f3c32679965a8edf28fa64be86dd4 Reviewed-by: Tomi Korpipää Reviewed-by: Pasi Keränen --- src/imports/qtcanvas3d/teximage3d.cpp | 51 ++++++++++++++++++++--------------- src/imports/qtcanvas3d/teximage3d_p.h | 7 +++-- 2 files changed, 35 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/imports/qtcanvas3d/teximage3d.cpp b/src/imports/qtcanvas3d/teximage3d.cpp index b6c0be2..38db6cf 100644 --- a/src/imports/qtcanvas3d/teximage3d.cpp +++ b/src/imports/qtcanvas3d/teximage3d.cpp @@ -154,7 +154,8 @@ QJSValue CanvasTextureImageFactory::newTexImage() CanvasTextureImage::CanvasTextureImage(CanvasTextureImageFactory *parent, QQmlEngine *engine) : CanvasAbstractObject(0, parent), m_engine(engine), - m_networkAccessManager(0), + m_networkAccessManager(m_engine->networkAccessManager()), + m_networkReply(0), m_state(INITIALIZED), m_errorString(""), m_pixelCache(0), @@ -162,9 +163,6 @@ CanvasTextureImage::CanvasTextureImage(CanvasTextureImageFactory *parent, QQmlEn m_pixelCacheFlipY(false), m_parentFactory(parent) { - m_networkAccessManager = new QNetworkAccessManager(this); - QObject::connect(m_networkAccessManager, &QNetworkAccessManager::finished, - this, &CanvasTextureImage::handleReply); } CanvasTextureImage::CanvasTextureImage(const QImage &source, @@ -173,24 +171,32 @@ CanvasTextureImage::CanvasTextureImage(const QImage &source, QQmlEngine *engine) : CanvasAbstractObject(0, parent), m_engine(engine), - m_networkAccessManager(0), + m_networkAccessManager(m_engine->networkAccessManager()), + m_networkReply(0), m_state(INITIALIZED), m_errorString(""), m_pixelCache(0), m_pixelCacheFormat(CanvasContext::NONE), m_pixelCacheFlipY(false) { - m_networkAccessManager = new QNetworkAccessManager(this); - QObject::connect(m_networkAccessManager, &QNetworkAccessManager::finished, - this, &CanvasTextureImage::handleReply); - m_image = source.scaled(width, height); setImageState(LOADING_FINISHED); } +void CanvasTextureImage::cleanupNetworkReply() +{ + if (m_networkReply) { + QObject::disconnect(m_networkReply, &QNetworkReply::finished, + this, &CanvasTextureImage::handleReply); + m_networkReply->abort(); + m_networkReply->deleteLater(); + m_networkReply = 0; + } +} + CanvasTextureImage::~CanvasTextureImage() { - delete m_networkAccessManager; + cleanupNetworkReply(); delete m_pixelCache; } @@ -250,7 +256,9 @@ void CanvasTextureImage::load() emit imageLoadingStarted(this); QNetworkRequest request(m_source); - m_networkAccessManager->get(request); + m_networkReply = m_networkAccessManager->get(request); + QObject::connect(m_networkReply, &QNetworkReply::finished, + this, &CanvasTextureImage::handleReply); } /*! @@ -262,18 +270,19 @@ QString CanvasTextureImage::errorString() const return m_errorString; } -void CanvasTextureImage::handleReply(QNetworkReply *reply) +void CanvasTextureImage::handleReply() { - if (reply->error() != QNetworkReply::NoError) { - m_errorString = reply->errorString(); - emit errorStringChanged(m_errorString); - setImageState(LOADING_ERROR); - return; + if (m_networkReply) { + if (m_networkReply->error() != QNetworkReply::NoError) { + m_errorString = m_networkReply->errorString(); + emit errorStringChanged(m_errorString); + setImageState(LOADING_ERROR); + } else { + m_image.loadFromData(m_networkReply->readAll()); + setImageState(LOADING_FINISHED); + } + cleanupNetworkReply(); } - - m_image.loadFromData(reply->readAll()); - - setImageState(LOADING_FINISHED); } QImage &CanvasTextureImage::getImage() diff --git a/src/imports/qtcanvas3d/teximage3d_p.h b/src/imports/qtcanvas3d/teximage3d_p.h index 70b7f1c..78a6679 100644 --- a/src/imports/qtcanvas3d/teximage3d_p.h +++ b/src/imports/qtcanvas3d/teximage3d_p.h @@ -120,7 +120,7 @@ public: void emitImageLoadingError(); void load(); - void handleReply(QNetworkReply *reply); + void handleReply(); QImage &getImage(); uchar *convertToFormat(CanvasContext::glEnums format, bool flipY = false, bool premultipliedAlpha = false); @@ -143,8 +143,11 @@ signals: void imageLoadingFailed(CanvasTextureImage *image); private: + void cleanupNetworkReply(); + QQmlEngine *m_engine; - QNetworkAccessManager *m_networkAccessManager; + QNetworkAccessManager *m_networkAccessManager; // not owned + QNetworkReply *m_networkReply; QImage m_image; QUrl m_source; TextureImageState m_state; -- cgit v1.2.3 From f7be841e43dde6af1194c370c6a50b0167dd89f4 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 11 Jan 2016 14:08:36 +0200 Subject: Fix context leak when destroying canvas that was never properly shown. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sharecontext gets created even if the canvas doesn't create the regular context, but it wasn't destroyed unless regular context also existed. Change-Id: Ib975ff65c4138000b4a2f1277fe56c9d5109c626 Task-number: QTBUG-50369 Reviewed-by: Tomi Korpipää Reviewed-by: Pasi Keränen --- src/imports/qtcanvas3d/canvasrenderer.cpp | 84 +++++++++++++++---------------- 1 file changed, 42 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/imports/qtcanvas3d/canvasrenderer.cpp b/src/imports/qtcanvas3d/canvasrenderer.cpp index 86ca838..7939c3b 100644 --- a/src/imports/qtcanvas3d/canvasrenderer.cpp +++ b/src/imports/qtcanvas3d/canvasrenderer.cpp @@ -315,64 +315,64 @@ void CanvasRenderer::init(QQuickWindow *window, const CanvasContextAttributes &c */ void CanvasRenderer::shutDown() { - if (!m_glContext) - return; - QMutexLocker locker(&m_shutdownMutex); - m_fps = 0; + if (m_glContext) { + if (m_renderTarget == Canvas::RenderTargetOffscreenBuffer) + m_glContext->makeCurrent(m_offscreenSurface); + + m_commandQueue.clearResourceMaps(); - if (m_renderTarget == Canvas::RenderTargetOffscreenBuffer) - m_glContext->makeCurrent(m_offscreenSurface); + deleteCommandData(); + m_executeQueue.clear(); - m_commandQueue.clearResourceMaps(); + delete m_renderFbo; + delete m_displayFbo; + delete m_antialiasFbo; - deleteCommandData(); - m_executeQueue.clear(); + if (m_renderTarget == Canvas::RenderTargetOffscreenBuffer) { + delete m_alphaMultiplierFbo; + m_alphaMultiplierFbo = 0; + glDeleteBuffers(1, &m_alphaMultiplierUVBuffer); + glDeleteBuffers(1, &m_alphaMultiplierVertexBuffer); + m_alphaMultiplierUVBuffer = 0; + m_alphaMultiplierVertexBuffer = 0; + delete m_alphaMultiplierProgram; + delete m_alphaMultiplierVertexShader; + delete m_alphaMultiplierFragmentShader; + m_alphaMultiplierProgram = 0; + m_alphaMultiplierVertexShader = 0; + m_alphaMultiplierFragmentShader = 0; - delete m_renderFbo; - delete m_displayFbo; - delete m_antialiasFbo; + m_glContext->doneCurrent(); + delete m_glContext; + } - if (m_renderTarget == Canvas::RenderTargetOffscreenBuffer) { - delete m_alphaMultiplierFbo; - m_alphaMultiplierFbo = 0; - glDeleteBuffers(1, &m_alphaMultiplierUVBuffer); - glDeleteBuffers(1, &m_alphaMultiplierVertexBuffer); - m_alphaMultiplierUVBuffer = 0; - m_alphaMultiplierVertexBuffer = 0; - delete m_alphaMultiplierProgram; - delete m_alphaMultiplierVertexShader; - delete m_alphaMultiplierFragmentShader; - m_alphaMultiplierProgram = 0; - m_alphaMultiplierVertexShader = 0; - m_alphaMultiplierFragmentShader = 0; + m_renderFbo = 0; + m_displayFbo = 0; + m_antialiasFbo = 0; - m_glContext->doneCurrent(); - delete m_glContext; - } + // m_offscreenSurface is owned by main thread, as on some platforms that is required. + if (m_offscreenSurface) { + m_offscreenSurface->deleteLater(); + m_offscreenSurface = 0; + } - m_renderFbo = 0; - m_displayFbo = 0; - m_antialiasFbo = 0; + m_currentFramebufferId = 0; + m_forceViewportRect = QRect(); - delete m_glContextShare; + delete m_stateStore; + m_stateStore = 0; - // m_offscreenSurface is owned by main thread, as on some platforms that is required. - if (m_offscreenSurface) { - m_offscreenSurface->deleteLater(); - m_offscreenSurface = 0; + m_glContext = 0; } - m_glContext = 0; + delete m_glContextShare; + m_glContextQt = 0; m_glContextShare = 0; - m_currentFramebufferId = 0; - m_forceViewportRect = QRect(); - - delete m_stateStore; - m_stateStore = 0; + m_fps = 0; } /*! -- cgit v1.2.3 From 30ae03d289dd967edfea5e164be677085dc45e84 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 13 Jan 2016 17:25:12 +0200 Subject: Fix CanvasTextureImage leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CanvasTextureImages were assigned as chilren of their parent factory, which has lifetime of the application, so they never got garbage collected. Change-Id: I3466491d37307b0d8daf7965a4c3d03ab7a62464 Task-number: QTBUG-50369 Reviewed-by: Tomi Korpipää Reviewed-by: Pasi Keränen --- src/imports/qtcanvas3d/teximage3d.cpp | 25 +++++++++++++++---------- src/imports/qtcanvas3d/teximage3d_p.h | 4 +++- 2 files changed, 18 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/imports/qtcanvas3d/teximage3d.cpp b/src/imports/qtcanvas3d/teximage3d.cpp index 38db6cf..652e8c2 100644 --- a/src/imports/qtcanvas3d/teximage3d.cpp +++ b/src/imports/qtcanvas3d/teximage3d.cpp @@ -119,7 +119,6 @@ void CanvasTextureImageFactory::notifyLoadedImages() if (image->imageState() == CanvasTextureImage::LOADING_FINISHED) { m_loadingImagesList.removeOne(image); image->emitImageLoaded(); - } else if (image->imageState() == CanvasTextureImage::LOADING_ERROR) { m_loadingImagesList.removeOne(image); image->emitImageLoadingError(); @@ -134,12 +133,14 @@ void CanvasTextureImageFactory::notifyLoadedImages() QJSValue CanvasTextureImageFactory::newTexImage() { CanvasTextureImage *newImg = new CanvasTextureImage(this, m_qmlEngine); - connect(newImg, &CanvasTextureImage::imageLoadingStarted, - this, &CanvasTextureImageFactory::handleImageLoadingStarted); - return m_qmlEngine->newQObject(newImg); } +void CanvasTextureImageFactory::handleImageDestroyed(CanvasTextureImage *image) +{ + m_loadingImagesList.removeOne(image); +} + /*! * \qmltype TextureImage * \since QtCanvas3D 1.0 @@ -152,7 +153,7 @@ QJSValue CanvasTextureImageFactory::newTexImage() * \sa TextureImageFactory */ CanvasTextureImage::CanvasTextureImage(CanvasTextureImageFactory *parent, QQmlEngine *engine) : - CanvasAbstractObject(0, parent), + CanvasAbstractObject(0, 0), m_engine(engine), m_networkAccessManager(m_engine->networkAccessManager()), m_networkReply(0), @@ -167,9 +168,9 @@ CanvasTextureImage::CanvasTextureImage(CanvasTextureImageFactory *parent, QQmlEn CanvasTextureImage::CanvasTextureImage(const QImage &source, int width, int height, - QObject *parent, + CanvasTextureImageFactory *parent, QQmlEngine *engine) : - CanvasAbstractObject(0, parent), + CanvasAbstractObject(0, 0), m_engine(engine), m_networkAccessManager(m_engine->networkAccessManager()), m_networkReply(0), @@ -177,7 +178,8 @@ CanvasTextureImage::CanvasTextureImage(const QImage &source, m_errorString(""), m_pixelCache(0), m_pixelCacheFormat(CanvasContext::NONE), - m_pixelCacheFlipY(false) + m_pixelCacheFlipY(false), + m_parentFactory(parent) { m_image = source.scaled(width, height); setImageState(LOADING_FINISHED); @@ -196,8 +198,10 @@ void CanvasTextureImage::cleanupNetworkReply() CanvasTextureImage::~CanvasTextureImage() { + if (m_parentFactory) + m_parentFactory->handleImageDestroyed(this); cleanupNetworkReply(); - delete m_pixelCache; + delete[] m_pixelCache; } /*! @@ -253,6 +257,7 @@ void CanvasTextureImage::load() return; setImageState(LOADING); + m_parentFactory->handleImageLoadingStarted(this); emit imageLoadingStarted(this); QNetworkRequest request(m_source); @@ -353,7 +358,7 @@ uchar *CanvasTextureImage::convertToFormat(CanvasContext::glEnums format, return m_pixelCache; // Destroy the pixel cache - delete m_pixelCache; + delete[] m_pixelCache; m_pixelCache = 0; m_pixelCacheFormat = CanvasContext::NONE; diff --git a/src/imports/qtcanvas3d/teximage3d_p.h b/src/imports/qtcanvas3d/teximage3d_p.h index 78a6679..6789a2e 100644 --- a/src/imports/qtcanvas3d/teximage3d_p.h +++ b/src/imports/qtcanvas3d/teximage3d_p.h @@ -74,6 +74,8 @@ public: void notifyLoadedImages(); Q_INVOKABLE QJSValue newTexImage(); + void handleImageDestroyed(CanvasTextureImage *image); + private: QQmlEngine *m_qmlEngine; QList m_loadingImagesList; @@ -129,7 +131,7 @@ public: private: void setImageState(TextureImageState state); explicit CanvasTextureImage(const QImage &source, int width, int height, - QObject *parent, QQmlEngine *engine); + CanvasTextureImageFactory *parent, QQmlEngine *engine); signals: void srcChanged(QUrl source); -- cgit v1.2.3 From 3051144dfdc06c53f1a13a7571548844bd1ef322 Mon Sep 17 00:00:00 2001 From: Michael Dippold Date: Fri, 29 Jan 2016 20:03:15 -0800 Subject: Use appropriate name strings for opengl extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This now uses the appropriate names similar to the extension lookup for webgl in the webengine code. Change-Id: I5a0a982b18b0986cd94d1d6fcb93a54c2ebaac56 Reviewed-by: Pasi Keränen --- src/imports/qtcanvas3d/context3d.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/imports/qtcanvas3d/context3d.cpp b/src/imports/qtcanvas3d/context3d.cpp index 8700319..232bc4f 100644 --- a/src/imports/qtcanvas3d/context3d.cpp +++ b/src/imports/qtcanvas3d/context3d.cpp @@ -5973,14 +5973,14 @@ QVariantList CanvasContext::getSupportedExtensions() if (!m_isOpenGLES2 || (m_contextVersion >= 3 - || m_extensions.contains("OES_standard_derivatives"))) { + || m_extensions.contains("GL_OES_standard_derivatives"))) { list.append(QVariant::fromValue(QStringLiteral("OES_standard_derivatives"))); } if (m_extensions.contains("GL_EXT_texture_compression_s3tc")) list.append(QVariant::fromValue(QStringLiteral("WEBGL_compressed_texture_s3tc"))); - if (m_extensions.contains("IMG_texture_compression_pvrtc")) + if (m_extensions.contains("GL_IMG_texture_compression_pvrtc")) list.append(QVariant::fromValue(QStringLiteral("WEBGL_compressed_texture_pvrtc"))); } -- cgit v1.2.3 From f669d1708c1009adc7d82d42bf550e0d971e827f Mon Sep 17 00:00:00 2001 From: Michael Dippold Date: Mon, 1 Feb 2016 17:51:28 -0800 Subject: Add correct extension lookup to getExtension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous change corrected the getSupportedExtensions function, this change fixes the getExtension function. Change-Id: Ie4d36366d3261bd65c7d5f6677902781156f9ad2 Reviewed-by: Miikka Heikkinen Reviewed-by: Pasi Keränen --- src/imports/qtcanvas3d/context3d.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/imports/qtcanvas3d/context3d.cpp b/src/imports/qtcanvas3d/context3d.cpp index 232bc4f..9e2c488 100644 --- a/src/imports/qtcanvas3d/context3d.cpp +++ b/src/imports/qtcanvas3d/context3d.cpp @@ -6082,7 +6082,7 @@ QVariant CanvasContext::getExtension(const QString &name) m_textureProviderExt = new CanvasTextureProvider(this, this); return QVariant::fromValue(m_textureProviderExt); } else if (upperCaseName == QStringLiteral("OES_STANDARD_DERIVATIVES") && - m_extensions.contains("OES_standard_derivatives")) { + m_extensions.contains("GL_OES_standard_derivatives")) { if (!m_standardDerivatives) m_standardDerivatives = new QObject(this); return QVariant::fromValue(m_standardDerivatives); @@ -6092,7 +6092,7 @@ QVariant CanvasContext::getExtension(const QString &name) m_compressedTextureS3TC = new CompressedTextureS3TC(this); return QVariant::fromValue(m_compressedTextureS3TC); } else if (upperCaseName == QStringLiteral("WEBGL_COMPRESSED_TEXTURE_PVRTC") && - m_extensions.contains("IMG_texture_compression_pvrtc")) { + m_extensions.contains("GL_IMG_texture_compression_pvrtc")) { if (!m_compressedTexturePVRTC) m_compressedTexturePVRTC = new CompressedTexturePVRTC(this); return QVariant::fromValue(m_compressedTexturePVRTC); -- cgit v1.2.3 From c00f1090b2287d345e83699d6b414336227aaf91 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 11 Feb 2016 13:19:08 +0200 Subject: Fix texture using application crash at shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Depending on order things are destroyed at shutdown, texture factory can get deleted before textures at shutdown. Textures notify factory at their destructor, which caused the crash. Changed factory pointer to a guarded one to avoid this. Change-Id: I032f066a9a77ef92c68c31e0552f880a8f0a90af Task-number: QTBUG-51045 Reviewed-by: Pasi Keränen --- src/imports/qtcanvas3d/teximage3d.cpp | 5 +++-- src/imports/qtcanvas3d/teximage3d_p.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/imports/qtcanvas3d/teximage3d.cpp b/src/imports/qtcanvas3d/teximage3d.cpp index 652e8c2..8528d15 100644 --- a/src/imports/qtcanvas3d/teximage3d.cpp +++ b/src/imports/qtcanvas3d/teximage3d.cpp @@ -198,7 +198,7 @@ void CanvasTextureImage::cleanupNetworkReply() CanvasTextureImage::~CanvasTextureImage() { - if (m_parentFactory) + if (!m_parentFactory.isNull()) m_parentFactory->handleImageDestroyed(this); cleanupNetworkReply(); delete[] m_pixelCache; @@ -257,7 +257,8 @@ void CanvasTextureImage::load() return; setImageState(LOADING); - m_parentFactory->handleImageLoadingStarted(this); + if (!m_parentFactory.isNull()) + m_parentFactory->handleImageLoadingStarted(this); emit imageLoadingStarted(this); QNetworkRequest request(m_source); diff --git a/src/imports/qtcanvas3d/teximage3d_p.h b/src/imports/qtcanvas3d/teximage3d_p.h index 6789a2e..59bd0d6 100644 --- a/src/imports/qtcanvas3d/teximage3d_p.h +++ b/src/imports/qtcanvas3d/teximage3d_p.h @@ -51,6 +51,7 @@ #include "abstractobject3d_p.h" #include +#include #include #include #include @@ -159,7 +160,7 @@ private: bool m_pixelCacheFlipY; QImage m_glImage; QVariant *m_anyValue; - CanvasTextureImageFactory *m_parentFactory; + QPointer m_parentFactory; }; QT_CANVAS3D_END_NAMESPACE -- cgit v1.2.3 From 5a17c4ca0552c9f4e6b5646f0cee2b21a55c3d18 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Thu, 11 Feb 2016 15:12:42 +0100 Subject: Doc: Fix version strings in documentation configuration Old version strings caused a conflict in documentation namespaces, resulting in wrong version of docs to be referenced for users that have multiple versions installed. Change-Id: I3386c2fb225e820b6251f067b9fb961b0879d28b Task-number: QTBUG-51051 Reviewed-by: Miikka Heikkinen Reviewed-by: Friedemann Kleint Reviewed-by: Leena Miettinen --- src/imports/qtcanvas3d/doc/qtcanvas3d.qdocconf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/imports/qtcanvas3d/doc/qtcanvas3d.qdocconf b/src/imports/qtcanvas3d/doc/qtcanvas3d.qdocconf index be8e805..c0a7ae4 100644 --- a/src/imports/qtcanvas3d/doc/qtcanvas3d.qdocconf +++ b/src/imports/qtcanvas3d/doc/qtcanvas3d.qdocconf @@ -1,8 +1,8 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) project = QtCanvas3D -description = QtCanvas3D Reference Documentation -version = 1.1.0 +description = Qt Canvas 3D Reference Documentation +version = $QT_VERSION exampledirs = ../../../../examples/canvas3d \ snippets @@ -18,15 +18,15 @@ depends = qtcore qtgui qtqml qtquick qtquickcontrols qtquicklayouts qtdoc qt qhp.projects = QtCanvas3D qhp.QtCanvas3D.file = qtcanvas3d.qhp -qhp.QtCanvas3D.namespace = org.qt-project.qtcanvas3d.100 +qhp.QtCanvas3D.namespace = org.qt-project.qtcanvas3d.$QT_VERSION_TAG qhp.QtCanvas3D.virtualFolder = qtcanvas3d qhp.QtCanvas3D.indexTitle = Qt Canvas 3D qhp.QtCanvas3D.indexRoot = -qhp.QtCanvas3D.filterAttributes = qtcanvas3d 1.1.0 qtrefdoc -qhp.QtCanvas3D.customFilters.Qt.name = QtCanvas3D 1.1.0 -qhp.QtCanvas3D.customFilters.Qt.filterAttributes = qtcanvas3d 1.1.0 +qhp.QtCanvas3D.filterAttributes = qtcanvas3d $QT_VERSION qtrefdoc +qhp.QtCanvas3D.customFilters.Qt.name = QtCanvas3D $QT_VERSION +qhp.QtCanvas3D.customFilters.Qt.filterAttributes = qtcanvas3d $QT_VERSION qhp.QtCanvas3D.subprojects = gettingstarted examples types qhp.QtCanvas3D.subprojects.gettingstarted.title = Getting Started qhp.QtCanvas3D.subprojects.gettingstarted.indexTitle = Qt Canvas 3D Getting Started -- cgit v1.2.3