From 4b22aa1904337e595cca0b6f46b445d555db7d6b Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 30 Jan 2015 11:28:20 +0100 Subject: Texture API refactoring * Added LoadTextureDataJob * QAbstractTextureProvider: maximum layers property * Automatic QAbstractTextureProvider::TextureFormat added * material-qml should work perfectly with that patch. Change-Id: I3f92f13b783155798772086304a30126a4fc687d Reviewed-by: Sean Harmer --- src/plugins/sceneparsers/assimp/assimpparser.cpp | 2 +- .../quick3drenderer/items/quick3dtexture.cpp | 6 +- src/render/backend/jobs/loadtexturedatajob.cpp | 131 +++++++++++++ src/render/backend/jobs/loadtexturedatajob_p.h | 80 ++++++++ src/render/backend/jobs/render-jobs.pri | 6 +- src/render/backend/meshdatamanager.cpp | 10 +- src/render/backend/meshdatamanager_p.h | 2 +- src/render/backend/qgraphicscontext.cpp | 1 + src/render/backend/qrenderaspect.cpp | 12 +- src/render/backend/rendertexture.cpp | 209 +++++++++++++++------ src/render/backend/rendertexture_p.h | 29 ++- src/render/backend/rendertextureimage.cpp | 94 ++++++++- src/render/backend/rendertextureimage_p.h | 48 ++++- src/render/backend/texturedatamanager.cpp | 30 ++- src/render/backend/texturedatamanager_p.h | 13 +- src/render/frontend/qabstracttextureimage.cpp | 3 + src/render/frontend/qabstracttextureprovider.cpp | 37 +++- src/render/frontend/qabstracttextureprovider.h | 6 + src/render/frontend/qabstracttextureprovider_p.h | 1 + src/render/frontend/qtextureimage.cpp | 15 +- src/render/io/texturedata.cpp | 22 +-- src/render/io/texturedata.h | 22 +-- 22 files changed, 663 insertions(+), 116 deletions(-) create mode 100644 src/render/backend/jobs/loadtexturedatajob.cpp create mode 100644 src/render/backend/jobs/loadtexturedatajob_p.h (limited to 'src') diff --git a/src/plugins/sceneparsers/assimp/assimpparser.cpp b/src/plugins/sceneparsers/assimp/assimpparser.cpp index c29226fad..aeb27a3ab 100644 --- a/src/plugins/sceneparsers/assimp/assimpparser.cpp +++ b/src/plugins/sceneparsers/assimp/assimpparser.cpp @@ -594,7 +594,7 @@ void AssimpParser::loadEmbeddedTexture(uint textureIndex) { aiTexture *assimpTexture = m_scene->m_aiScene->mTextures[textureIndex]; QAbstractTextureProvider *texture = new QTexture2D(); - TexImageDataPtr textureData(new TexImageData(0, 0)); + TexImageDataPtr textureData(new TexImageData()); bool isCompressed = assimpTexture->mHeight == 0; uint textureSize = assimpTexture->mWidth * diff --git a/src/quick3d/quick3drenderer/items/quick3dtexture.cpp b/src/quick3d/quick3drenderer/items/quick3dtexture.cpp index 01689b432..172da793d 100644 --- a/src/quick3d/quick3drenderer/items/quick3dtexture.cpp +++ b/src/quick3d/quick3drenderer/items/quick3dtexture.cpp @@ -211,9 +211,9 @@ void Quick3DTextureCubeMapExtension::loadFace(const QUrl &faceUrl, QAbstractText // parentTexture()->setStatus(QAbstractTextureProvider::Loading); if (img.load(source)) { - TexImageDataPtr dataPtr(new TexImageData(0, 0)); + TexImageDataPtr dataPtr(new TexImageData()); - dataPtr->setCubeFace(static_cast(face)); +// dataPtr->setCubeFace(static_cast(face)); if (parentTexture()->height() != img.height()) parentTexture()->setHeight(img.height()); if (parentTexture()->width() != img.width()) @@ -224,7 +224,7 @@ void Quick3DTextureCubeMapExtension::loadFace(const QUrl &faceUrl, QAbstractText if (format != parentTexture()->format()) parentTexture()->setFormat(format); dataPtr->setImage(img); - parentTexture()->addImageData(dataPtr); +// parentTexture()->addImageData(dataPtr); // parentTexture()->setStatus(QAbstractTextureProvider::Loaded); } else { diff --git a/src/render/backend/jobs/loadtexturedatajob.cpp b/src/render/backend/jobs/loadtexturedatajob.cpp new file mode 100644 index 000000000..fde19a678 --- /dev/null +++ b/src/render/backend/jobs/loadtexturedatajob.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "loadtexturedatajob_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3D { + +namespace Render { + +LoadTextureDataJob::LoadTextureDataJob(const QNodeId &textureId) + : m_textureId(textureId) +{ +} + +LoadTextureDataJob::~LoadTextureDataJob() +{ +} + +void LoadTextureDataJob::run() +{ + qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread(); + + RenderTexture *txt = m_renderer->textureManager()->lookupResource(m_textureId); + + if (txt != Q_NULLPTR) { + // Load update each TextureImage + Q_FOREACH (HTextureImage texImgHandle, txt->textureImages()) { + RenderTextureImage *texImg = m_renderer->textureImageManager()->data(texImgHandle); + if (texImg != Q_NULLPTR && texImg->isDirty() && !texImg->dataFunctor().isNull()) { + QTextureDataFunctorPtr functor = texImg->dataFunctor(); + TextureDataManager::Locker locker(m_renderer->textureDataManager()); + HTextureData textureDataHandle = m_renderer->textureDataManager()->textureDataFromFunctor(functor); + locker.unlock(); + + TexImageData *data = Q_NULLPTR; + // Texture data handle isn't null == there's already a matching TextureData + if (!textureDataHandle.isNull()) { + data = m_renderer->textureDataManager()->data(textureDataHandle); + } else { + TexImageDataPtr dataPtr = functor->operator ()(); + if (dataPtr.isNull()) { + qCDebug(Jobs) << Q_FUNC_INFO << "Texture has no raw data"; + } else { + // Save the TexImageDataPtr with it's functor as a key + textureDataHandle = m_renderer->textureDataManager()->acquire(); + data = m_renderer->textureDataManager()->data(textureDataHandle); + locker.relock(); + *data = *(dataPtr.data()); + m_renderer->textureDataManager()->addTextureDataForFunctor(textureDataHandle, functor); + } + } + + // Set texture size of texture if the first layer / level / face has a valid size + // otherwise assume the size was set on the texture itself + if (texImg->layer() == 0 && texImg->mipmapLevel() == 0 && + texImg->face() == QAbstractTextureProvider::CubeMapPositiveX) { + + if (data == Q_NULLPTR) { + qWarning() << "Texture data is null, texture data failed to load"; + } else { + // Set the size of the texture based on the layer 0 / level 0 + // if the functor provides something valid. Otherwise we assume the texture + // already has the correct size + if (data->width() != -1 && data->height() != -1 && data->depth() != -1) { + txt->setSize(data->width(), data->height(), data->depth()); + } + // Set the format of the texture if the texture format is set to Automatic + if (txt->format() == QAbstractTextureProvider::Automatic) { + txt->setFormat(static_cast(data->format())); + } + } + } + // Set the textureDataHandle on the texture image + texImg->setTextureDataHandle(textureDataHandle); + } + } + // Tell the renderer to reload the TextureImage for the Texture + // next frame + txt->requestTextureDataUpdate(); + } +} + +} // Render + +} // Qt3D + +QT_END_NAMESPACE diff --git a/src/render/backend/jobs/loadtexturedatajob_p.h b/src/render/backend/jobs/loadtexturedatajob_p.h new file mode 100644 index 000000000..5506d2efd --- /dev/null +++ b/src/render/backend/jobs/loadtexturedatajob_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_LOADTEXTUREDATAJOB_H +#define QT3D_RENDER_LOADTEXTUREDATAJOB_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3D { + +namespace Render { + +class Renderer; + +class LoadTextureDataJob : public QAspectJob +{ +public: + LoadTextureDataJob(const QNodeId &textureId); + ~LoadTextureDataJob(); + inline void setRenderer(Renderer *renderer) { m_renderer = renderer; } + +protected: + void run() Q_DECL_FINAL; + +private: + QNodeId m_textureId; + Renderer *m_renderer; +}; + +typedef QSharedPointer LoadTextureDataJobPtr; + +} // Render + +} // Qt3D + +QT_END_NAMESPACE + +#endif // QT3D_RENDER_LOADTEXTUREDATAJOB_H diff --git a/src/render/backend/jobs/render-jobs.pri b/src/render/backend/jobs/render-jobs.pri index 4b1b750fc..fefc18001 100644 --- a/src/render/backend/jobs/render-jobs.pri +++ b/src/render/backend/jobs/render-jobs.pri @@ -8,7 +8,8 @@ HEADERS += \ $$PWD/renderviewjobutils_p.h \ $$PWD/loadscenejob_p.h \ $$PWD/framecleanupjob_p.h \ - $$PWD/framepreparationjob_p.h + $$PWD/framepreparationjob_p.h \ + $$PWD/loadtexturedatajob_p.h SOURCES += \ $$PWD/updateworldtransformjob.cpp \ @@ -18,4 +19,5 @@ SOURCES += \ $$PWD/renderviewjobutils.cpp \ $$PWD/loadscenejob.cpp \ $$PWD/framecleanupjob.cpp \ - $$PWD/framepreparationjob.cpp + $$PWD/framepreparationjob.cpp \ + $$PWD/loadtexturedatajob.cpp diff --git a/src/render/backend/meshdatamanager.cpp b/src/render/backend/meshdatamanager.cpp index 13266e5a5..02a00d31a 100644 --- a/src/render/backend/meshdatamanager.cpp +++ b/src/render/backend/meshdatamanager.cpp @@ -63,9 +63,13 @@ QHash MeshDataManager::meshesPending() HMeshData MeshDataManager::meshDataFromFunctor(QAbstractMeshFunctorPtr functor) const { - Q_FOREACH (const QAbstractMeshFunctorPtr &ptr, m_meshFunctors.keys()) { - if (*ptr == *functor) - return m_meshFunctors.value(ptr); + QHash::const_iterator it = m_meshFunctors.begin(); + const QHash::const_iterator end = m_meshFunctors.end(); + + while (it != end) { + if (*it.key() == *functor) + return it.value(); + ++it; } return HMeshData(); } diff --git a/src/render/backend/meshdatamanager_p.h b/src/render/backend/meshdatamanager_p.h index e7251cca7..4df9f39b5 100644 --- a/src/render/backend/meshdatamanager_p.h +++ b/src/render/backend/meshdatamanager_p.h @@ -62,7 +62,7 @@ namespace Render { class MeshDataManager : public QResourceManager { public: diff --git a/src/render/backend/qgraphicscontext.cpp b/src/render/backend/qgraphicscontext.cpp index 9376b9e07..0ff0ad556 100644 --- a/src/render/backend/qgraphicscontext.cpp +++ b/src/render/backend/qgraphicscontext.cpp @@ -373,6 +373,7 @@ int QGraphicsContext::activateTexture(TextureScope scope, RenderTexture *tex, in if (m_activeTextures[onUnit] != tex) { QOpenGLTexture* glTex = tex->getOrCreateGLTexture(); glTex->bind(onUnit); + m_activeTextures[onUnit] = tex; } int err = m_gl->functions()->glGetError(); diff --git a/src/render/backend/qrenderaspect.cpp b/src/render/backend/qrenderaspect.cpp index 7e1ce5e53..f61d3e2b7 100644 --- a/src/render/backend/qrenderaspect.cpp +++ b/src/render/backend/qrenderaspect.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -88,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -191,7 +193,7 @@ void QRenderAspect::registerBackendTypes() registerBackendType(QBackendNodeFunctorPtr(new Render::RenderNodeFunctor(d->m_renderer->transformManager()))); registerBackendType(QBackendNodeFunctorPtr(new Render::RenderNodeFunctor(d->m_renderer->materialManager()))); registerBackendType(QBackendNodeFunctorPtr(new Render::RenderNodeFunctor(d->m_renderer->techniqueManager()))); - registerBackendType(QBackendNodeFunctorPtr(new Render::RenderTextureFunctor(d->m_renderer->textureManager(), d->m_renderer->textureImageManager()))); + registerBackendType(QBackendNodeFunctorPtr(new Render::RenderTextureFunctor(d->m_renderer->textureManager(), d->m_renderer->textureImageManager(), d->m_renderer->textureDataManager()))); registerBackendType(QBackendNodeFunctorPtr(new Render::RenderNodeFunctor(d->m_renderer->shaderManager()))); registerBackendType(QBackendNodeFunctorPtr(new Render::RenderNodeFunctor(d->m_renderer->effectManager()))); registerBackendType(QBackendNodeFunctorPtr(new Render::RenderNodeFunctor(d->m_renderer->criterionManager()))); @@ -215,7 +217,7 @@ void QRenderAspect::registerBackendTypes() registerBackendType(QBackendNodeFunctorPtr(new Render::FrameGraphComponentFunctor(d->m_renderer))); registerBackendType(QBackendNodeFunctorPtr(new Render::RenderNodeFunctor(d->m_renderer->parameterManager()))); registerBackendType(QBackendNodeFunctorPtr(new Render::RenderShaderDataFunctor(d->m_renderer->shaderDataManager()))); - registerBackendType(QBackendNodeFunctorPtr(new Render::RenderNodeFunctor(d->m_renderer->textureImageManager()))); + registerBackendType(QBackendNodeFunctorPtr(new Render::RenderTextureImageFunctor(d->m_renderer->textureManager(), d->m_renderer->textureImageManager(), d->m_renderer->textureDataManager()))); } void QRenderAspect::renderInitialize(QOpenGLContext *context) @@ -259,6 +261,12 @@ QVector QRenderAspect::jobsToExecute(qint64 time) jobs.append(loadMeshJob); } + QVector texturesPending = d->m_renderer->textureDataManager()->texturesPending(); + Q_FOREACH (const QNodeId &textureId, texturesPending) { + Render::LoadTextureDataJobPtr loadTextureJob(new Render::LoadTextureDataJob(textureId)); + loadTextureJob->setRenderer(d->m_renderer); + jobs.append(loadTextureJob); + } // TO DO: Have 2 jobs queue // One for urgent jobs that are mandatory for the rendering of a frame // Another for jobs that can span across multiple frames (Scene/Mesh loading) diff --git a/src/render/backend/rendertexture.cpp b/src/render/backend/rendertexture.cpp index b34ceb454..737bccdda 100644 --- a/src/render/backend/rendertexture.cpp +++ b/src/render/backend/rendertexture.cpp @@ -51,6 +51,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -63,9 +64,10 @@ RenderTexture::RenderTexture() , m_width(1) , m_height(1) , m_depth(1) + , m_layers(1) , m_generateMipMaps(false) , m_target(QAbstractTextureProvider::Target2D) - , m_format(QAbstractTextureProvider::RGBA8U) + , m_format(QAbstractTextureProvider::RGBA8_UNorm) , m_magnificationFilter(QAbstractTextureProvider::Nearest) , m_minificationFilter(QAbstractTextureProvider::Nearest) , m_wrapModeX(QTextureWrapMode::ClampToEdge) @@ -76,10 +78,12 @@ RenderTexture::RenderTexture() , m_comparisonMode(QAbstractTextureProvider::CompareNone) , m_isDirty(false) , m_filtersAndWrapUpdated(false) + , m_dataUploadRequired(false) , m_lock(new QMutex()) , m_textureDNA(0) , m_textureManager(Q_NULLPTR) , m_textureImageManager(Q_NULLPTR) + , m_textureDataManager(Q_NULLPTR) { // We need backend -> frontend notifications to update the status of the texture } @@ -97,9 +101,10 @@ void RenderTexture::cleanup() m_width = 1; m_height = 1; m_depth = 1; + m_layers = 1; m_generateMipMaps = false; m_target = QAbstractTextureProvider::Target2D; - m_format = QAbstractTextureProvider::RGBA8U; + m_format = QAbstractTextureProvider::RGBA8_UNorm; m_magnificationFilter = QAbstractTextureProvider::Nearest; m_minificationFilter = QAbstractTextureProvider::Nearest; m_wrapModeX = QTextureWrapMode::ClampToEdge; @@ -110,12 +115,15 @@ void RenderTexture::cleanup() m_comparisonMode = QAbstractTextureProvider::CompareNone; m_isDirty = false; m_filtersAndWrapUpdated = false; + m_dataUploadRequired = false; + m_textureDNA = 0; m_textureImages.clear(); - m_imageData.clear(); m_textureManager = Q_NULLPTR; m_textureImageManager = Q_NULLPTR; + m_textureDataManager = Q_NULLPTR; } +// AspectThread void RenderTexture::updateFromPeer(QNode *peer) { QAbstractTextureProvider *texture = static_cast(peer); @@ -137,17 +145,11 @@ void RenderTexture::updateFromPeer(QNode *peer) m_maximumAnisotropy = texture->maximumAnisotropy(); m_comparisonFunction = texture->comparisonFunction(); m_comparisonMode = texture->comparisonMode(); - - // TO DO: This list should be filled by executing the functor of - // each TextureImage instead of reading those from the frontend directly - Q_FOREACH (TexImageDataPtr imgData, texture->imageData()) - m_imageData.append(imgData); - - Q_FOREACH (QAbstractTextureImage *textureImage, texture->textureImages()) - m_textureImages.append(m_textureImageManager->getOrAcquireHandle(textureImage->id())); + m_layers = texture->maximumLayers(); } } +// RenderTread QOpenGLTexture *RenderTexture::getOrCreateGLTexture() { // m_gl HAS to be destroyed in the OpenGL Thread @@ -176,6 +178,8 @@ QOpenGLTexture *RenderTexture::getOrCreateGLTexture() updateWrapAndFilters(); m_filtersAndWrapUpdated = false; } + if (m_dataUploadRequired) + updateAndLoadTextureImage(); return m_gl; } @@ -187,14 +191,13 @@ QOpenGLTexture *RenderTexture::getOrCreateGLTexture() return Q_NULLPTR; } - foreach (TexImageDataPtr imgData, m_imageData) { - setToGLTexture(imgData); - } // of image data in texture iteration - // Filters and WrapMode are set updateWrapAndFilters(); m_filtersAndWrapUpdated = false; + // Upload textures data the first time + updateAndLoadTextureImage(); + // Ideally we might want to abstract that and use the QGraphicsContext as a wrapper // around that. if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) { @@ -206,11 +209,25 @@ QOpenGLTexture *RenderTexture::getOrCreateGLTexture() return m_gl; } +// RenderThread QOpenGLTexture *RenderTexture::buildGLTexture() { QOpenGLTexture* glTex = new QOpenGLTexture(static_cast(m_target)); - glTex->setFormat(static_cast(m_format)); + + if (m_format == QAbstractTextureProvider::Automatic) + qWarning() << Q_FUNC_INFO << "something went wrong, format shouldn't be automatic at this point"; + + glTex->setFormat(m_format == QAbstractTextureProvider::Automatic ? + QOpenGLTexture::NoFormat : + static_cast(m_format)); glTex->setSize(m_width, m_height, m_depth); + // Set layers count if texture array + if (m_target == QAbstractTextureProvider::Target1DArray || + m_target == QAbstractTextureProvider::Target2DArray || + m_target == QAbstractTextureProvider::Target3D || + m_target == QAbstractTextureProvider::Target2DMultisampleArray || + m_target == QAbstractTextureProvider::TargetCubeMapArray) + glTex->setLayers(m_layers); if (m_generateMipMaps) glTex->setMipLevels(glTex->maximumMipLevels()); @@ -223,29 +240,33 @@ QOpenGLTexture *RenderTexture::buildGLTexture() // FIXME : make this conditional on Qt version // work-around issue in QOpenGLTexture DSA emulaation which rasies // an Invalid Enum error - if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) - ctx->functions()->glGetError(); + if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) { + int err = ctx->functions()->glGetError(); + if (err) + qWarning() << Q_FUNC_INFO << err; + } return glTex; } -void RenderTexture::setToGLTexture(TexImageDataPtr imgData) +// RenderThread +void RenderTexture::setToGLTexture(RenderTextureImage *rImg, TexImageData *imgData) { Q_ASSERT(m_gl && m_gl->isCreated() && m_gl->isStorageAllocated()); // ensure we don't accidently cause a detach / copy of the raw bytes const QByteArray& bytes(imgData->data()); if (imgData->isCompressed()) { - m_gl->setCompressedData(imgData->mipMapLevel(), - imgData->layer(), - imgData->cubeFace(), + m_gl->setCompressedData(rImg->mipmapLevel(), + rImg->layer(), + static_cast(rImg->face()), bytes.size(), bytes.constData()); } else { QOpenGLPixelTransferOptions uploadOptions; uploadOptions.setAlignment(1); - m_gl->setData(imgData->mipMapLevel(), - imgData->layer(), - imgData->cubeFace(), + m_gl->setData(rImg->mipmapLevel(), + rImg->layer(), + static_cast(rImg->face()), imgData->pixelFormat(), imgData->pixelType(), bytes.constData(), @@ -255,10 +276,14 @@ void RenderTexture::setToGLTexture(TexImageDataPtr imgData) // FIXME : make this conditional on Qt version // work-around issue in QOpenGLTexture DSA emulaation which rasies // an Invalid Enum error - if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) - ctx->functions()->glGetError(); + if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) { + int err = ctx->functions()->glGetError(); + if (err) + qWarning() << Q_FUNC_INFO << err; + } } +// RenderThread void RenderTexture::updateWrapAndFilters() { m_gl->setWrapMode(QOpenGLTexture::DirectionS, static_cast(m_wrapModeX)); @@ -280,18 +305,44 @@ void RenderTexture::updateWrapAndFilters() } } - +// RenderThread GLint RenderTexture::textureId() { return getOrCreateGLTexture()->textureId(); } +// Any Thread bool RenderTexture::isTextureReset() const { QMutexLocker lock(m_lock); return m_isDirty; } +void RenderTexture::setSize(int width, int height, int depth) +{ + if (width != m_width) { + m_width = width; + m_isDirty |= true; + } + if (height != m_height) { + m_height = height; + m_isDirty |= true; + } + if (depth != m_depth) { + m_depth = depth; + m_isDirty |= true; + } +} + +void RenderTexture::setFormat(QAbstractTextureProvider::TextureFormat format) +{ + if (format != m_format) { + m_format = format; + m_isDirty |= true; + } +} + +// ChangeArbiter/Aspect Thread void RenderTexture::sceneChangeEvent(const QSceneChangePtr &e) { // The QOpenGLTexture has to be manipulated from the RenderThread only @@ -302,74 +353,73 @@ void RenderTexture::sceneChangeEvent(const QSceneChangePtr &e) switch (e->type()) { case NodeUpdated: { if (propertyChange->propertyName() == QByteArrayLiteral("width")) { - int oldWidth = m_width; - m_width = propertyChange->value().toInt(); - m_isDirty = (oldWidth != m_width); + setSize(propertyChange->value().toInt(), m_height, m_depth); } else if (propertyChange->propertyName() == QByteArrayLiteral("height")) { - int oldHeight = m_height; - m_height = propertyChange->value().toInt(); - m_isDirty = (oldHeight != m_height); + setSize(m_width, propertyChange->value().toInt(), m_depth); } else if (propertyChange->propertyName() == QByteArrayLiteral("depth")) { - int oldDepth = m_depth; - m_depth = propertyChange->value().toInt(); - m_isDirty = (oldDepth != m_depth); + setSize(m_width, m_height, propertyChange->value().toInt()); } else if (propertyChange->propertyName() == QByteArrayLiteral("mipmaps")) { bool oldMipMaps = m_generateMipMaps; m_generateMipMaps = propertyChange->value().toBool(); - m_isDirty = (oldMipMaps != m_generateMipMaps); + m_isDirty |= (oldMipMaps != m_generateMipMaps); } else if (propertyChange->propertyName() == QByteArrayLiteral("minificationFilter")) { QAbstractTextureProvider::Filter oldMinFilter = m_minificationFilter; m_minificationFilter = static_cast(propertyChange->value().toInt()); - m_filtersAndWrapUpdated = (oldMinFilter != m_minificationFilter); + m_filtersAndWrapUpdated |= (oldMinFilter != m_minificationFilter); } else if (propertyChange->propertyName() == QByteArrayLiteral("magnificationFilter")) { QAbstractTextureProvider::Filter oldMagFilter = m_magnificationFilter; m_magnificationFilter = static_cast(propertyChange->value().toInt()); - m_filtersAndWrapUpdated = (oldMagFilter != m_magnificationFilter); + m_filtersAndWrapUpdated |= (oldMagFilter != m_magnificationFilter); } else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeX")) { QTextureWrapMode::WrapMode oldWrapModeX = m_wrapModeX; m_wrapModeX = static_cast(propertyChange->value().toInt()); - m_filtersAndWrapUpdated = (oldWrapModeX != m_wrapModeX); + m_filtersAndWrapUpdated |= (oldWrapModeX != m_wrapModeX); } else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeX")) { QTextureWrapMode::WrapMode oldWrapModeY = m_wrapModeY; m_wrapModeY = static_cast(propertyChange->value().toInt()); - m_filtersAndWrapUpdated = (oldWrapModeY != m_wrapModeY); + m_filtersAndWrapUpdated |= (oldWrapModeY != m_wrapModeY); } else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeX")) { QTextureWrapMode::WrapMode oldWrapModeZ = m_wrapModeZ; m_wrapModeZ =static_cast(propertyChange->value().toInt()); - m_filtersAndWrapUpdated = (oldWrapModeZ != m_wrapModeZ); + m_filtersAndWrapUpdated |= (oldWrapModeZ != m_wrapModeZ); } else if (propertyChange->propertyName() == QByteArrayLiteral("format")) { - QAbstractTextureProvider::TextureFormat oldFormat = m_format; - m_format = static_cast(propertyChange->value().toInt()); - m_isDirty = (oldFormat != m_format); + setFormat(static_cast(propertyChange->value().toInt())); } else if (propertyChange->propertyName() == QByteArrayLiteral("target")) { QAbstractTextureProvider::Target oldTarget = m_target; m_target = static_cast(propertyChange->value().toInt()); - m_isDirty = (oldTarget != m_target); + m_isDirty |= (oldTarget != m_target); } else if (propertyChange->propertyName() == QByteArrayLiteral("maximumAnisotropy")) { float oldMaximumAnisotropy = m_maximumAnisotropy; m_maximumAnisotropy = propertyChange->value().toFloat(); - m_filtersAndWrapUpdated = !qFuzzyCompare(oldMaximumAnisotropy, m_maximumAnisotropy); + m_filtersAndWrapUpdated |= !qFuzzyCompare(oldMaximumAnisotropy, m_maximumAnisotropy); } else if (propertyChange->propertyName() == QByteArrayLiteral("comparisonFunction")) { QAbstractTextureProvider::ComparisonFunction oldComparisonFunction = m_comparisonFunction; m_comparisonFunction = propertyChange->value().value(); - m_filtersAndWrapUpdated = (oldComparisonFunction != m_comparisonFunction); + m_filtersAndWrapUpdated |= (oldComparisonFunction != m_comparisonFunction); } else if (propertyChange->propertyName() == QByteArrayLiteral("comparisonMode")) { QAbstractTextureProvider::ComparisonMode oldComparisonMode = m_comparisonMode; m_comparisonMode = propertyChange->value().value(); - m_filtersAndWrapUpdated = (oldComparisonMode != m_comparisonMode); + m_filtersAndWrapUpdated |= (oldComparisonMode != m_comparisonMode); + } else if (propertyChange->propertyName() == QByteArrayLiteral("maximumLayers")) { + int oldLayers = m_layers; + m_layers = propertyChange->value().toInt(); + m_isDirty |= (oldLayers != m_layers); } } break; case NodeAdded: { - if (propertyChange->propertyName() == QByteArrayLiteral("textureImage")) - m_textureImages.append(m_textureImageManager->getOrAcquireHandle(propertyChange->value().value())); + if (propertyChange->propertyName() == QByteArrayLiteral("textureImage")) { + m_textureImages.append(m_textureImageManager->lookupHandle(propertyChange->value().value())); + } } break; case NodeRemoved: { - if (propertyChange->propertyName() == QByteArrayLiteral("textureImage")) - m_textureImages.removeOne(m_textureImageManager->getOrAcquireHandle(propertyChange->value().value())); + if (propertyChange->propertyName() == QByteArrayLiteral("textureImage")) { + m_textureImages.removeOne(m_textureImageManager->lookupHandle(propertyChange->value().value())); + // If a TextureImage is removed from a Texture, the texture image data remains on GPU + } } break; @@ -384,20 +434,68 @@ TextureDNA RenderTexture::dna() const return m_textureDNA; } +// AspectThread void RenderTexture::setTextureManager(TextureManager *manager) { m_textureManager = manager; } +// AspectThread void RenderTexture::setTextureImageManager(TextureImageManager *manager) { m_textureImageManager = manager; } +void RenderTexture::setTextureDataManager(TextureDataManager *manager) +{ + m_textureDataManager = manager; +} + +// RenderThread +void RenderTexture::updateAndLoadTextureImage() +{ + Q_FOREACH (HTextureImage t, m_textureImages) { + RenderTextureImage *img = m_textureImageManager->data(t); + if (img != Q_NULLPTR && img->isDirty()) { + TexImageData *data = m_textureDataManager->data(img->textureDataHandle()); + if (data != Q_NULLPTR) { + setToGLTexture(img, data); + img->unsetDirty(); + } + } + } + m_dataUploadRequired = false; +} + +void RenderTexture::addTextureImageData(HTextureImage handle) +{ + m_textureImages.append(handle); +} + +void RenderTexture::removeTextureImageData(HTextureImage handle) +{ + m_textureImages.removeOne(handle); +} + +void RenderTexture::requestTextureDataUpdate() +{ + m_dataUploadRequired = true; +} + +// Will request a new jobs, if one of the texture data has changed +// after the job was executed, requestTextureDataUpdate will be called +// Called by RenderTextureImages +void RenderTexture::addToPendingTextureJobs() +{ + m_textureDataManager->addToPendingTextures(peerUuid()); +} + RenderTextureFunctor::RenderTextureFunctor(TextureManager *textureManager, - TextureImageManager *textureImageManager) + TextureImageManager *textureImageManager, + TextureDataManager *textureDataManager) : m_textureManager(textureManager) , m_textureImageManager(textureImageManager) + , m_textureDataManager(textureDataManager) { } @@ -407,6 +505,7 @@ QBackendNode *RenderTextureFunctor::create(QNode *frontend, const QBackendNodeFa backend->setFactory(factory); backend->setTextureManager(m_textureManager); backend->setTextureImageManager(m_textureImageManager); + backend->setTextureDataManager(m_textureDataManager); backend->setPeer(frontend); return backend; } diff --git a/src/render/backend/rendertexture_p.h b/src/render/backend/rendertexture_p.h index 4386be4f1..fb86ef10f 100644 --- a/src/render/backend/rendertexture_p.h +++ b/src/render/backend/rendertexture_p.h @@ -61,6 +61,7 @@ namespace Render { class TextureManager; class TextureImageManager; +class TextureDataManager; typedef uint TextureDNA; @@ -84,17 +85,31 @@ public: void setTextureManager(TextureManager *manager); void setTextureImageManager(TextureImageManager *manager); + void setTextureDataManager(TextureDataManager *manager); + + void updateAndLoadTextureImage(); + void addTextureImageData(HTextureImage handle); + void removeTextureImageData(HTextureImage handle); + + void requestTextureDataUpdate(); + void addToPendingTextureJobs(); + void setSize(int width, int height, int depth); + void setFormat(QAbstractTextureProvider::TextureFormat format); + + inline QVector textureImages() const { return m_textureImages; } + inline QAbstractTextureProvider::TextureFormat format() const { return m_format; } private: QOpenGLTexture *m_gl; QOpenGLTexture *buildGLTexture(); - void setToGLTexture(TexImageDataPtr imgData); + void setToGLTexture(RenderTextureImage *rImg, TexImageData *imgData); void updateWrapAndFilters(); int m_width; int m_height; int m_depth; + int m_layers; bool m_generateMipMaps; QAbstractTextureProvider::Target m_target; QAbstractTextureProvider::TextureFormat m_format; @@ -107,14 +122,18 @@ private: QAbstractTextureProvider::ComparisonFunction m_comparisonFunction; QAbstractTextureProvider::ComparisonMode m_comparisonMode; - QList m_imageData; - QList m_textureImages; + QVector m_textureImages; + bool m_isDirty; bool m_filtersAndWrapUpdated; + bool m_dataUploadRequired; + bool m_formatWasSpecified; + QMutex *m_lock; TextureDNA m_textureDNA; TextureManager *m_textureManager; TextureImageManager *m_textureImageManager; + TextureDataManager *m_textureDataManager; void updateDNA(); }; @@ -123,7 +142,8 @@ class RenderTextureFunctor : public QBackendNodeFunctor { public: explicit RenderTextureFunctor(TextureManager *textureManager, - TextureImageManager *textureImageManager); + TextureImageManager *textureImageManager, + TextureDataManager *textureDataManager); QBackendNode *create(QNode *frontend, const QBackendNodeFactory *factory) const Q_DECL_FINAL; QBackendNode *get(QNode *frontend) const Q_DECL_FINAL; @@ -132,6 +152,7 @@ public: private: TextureManager *m_textureManager; TextureImageManager *m_textureImageManager; + TextureDataManager *m_textureDataManager; }; } // namespace Render diff --git a/src/render/backend/rendertextureimage.cpp b/src/render/backend/rendertextureimage.cpp index e3011e189..f113533fb 100644 --- a/src/render/backend/rendertextureimage.cpp +++ b/src/render/backend/rendertextureimage.cpp @@ -41,6 +41,8 @@ #include "rendertextureimage_p.h" #include +#include +#include QT_BEGIN_NAMESPACE @@ -53,7 +55,10 @@ RenderTextureImage::RenderTextureImage() , m_layer(0) , m_mipmapLevel(0) , m_face(QAbstractTextureProvider::CubeMapPositiveX) - , m_isDirty(true) + , m_dirty(true) + , m_textureManager(Q_NULLPTR) + , m_textureImageManager(Q_NULLPTR) + , m_textureDataManager(Q_NULLPTR) { } @@ -61,9 +66,13 @@ void RenderTextureImage::cleanup() { m_layer = 0; m_mipmapLevel = 0; - m_isDirty = true; + m_dirty = true; m_face = QAbstractTextureProvider::CubeMapPositiveX; m_functor.reset(); + m_textureManager = Q_NULLPTR; + m_textureImageManager = Q_NULLPTR; + m_textureDataManager = Q_NULLPTR; + m_referencedTextures.clear(); } void RenderTextureImage::updateFromPeer(QNode *peer) @@ -73,6 +82,18 @@ void RenderTextureImage::updateFromPeer(QNode *peer) m_mipmapLevel = textureImage->mipmapLevel(); m_face = textureImage->cubeMapFace(); m_functor = textureImage->dataFunctor(); + // Notify the RenderTexture that we are one of its TextureImage + if (!peer->parentNode()) { + qWarning() << "Not QAbstractTextureProvider parent found"; + } else { + m_textureProviderId = peer->parentNode()->id(); + m_textureProvider = m_textureManager->lookupHandle(m_textureProviderId); + RenderTexture *txt = m_textureManager->data(m_textureProvider); + // Notify the RenderTexture that it has a new RenderTextureImage and needs an update + txt->addTextureImageData(m_textureImageManager->lookupHandle(peerUuid())); + if (txt != Q_NULLPTR) + txt->addToPendingTextureJobs(); + } } void RenderTextureImage::sceneChangeEvent(const QSceneChangePtr &e) @@ -82,18 +103,79 @@ void RenderTextureImage::sceneChangeEvent(const QSceneChangePtr &e) if (e->type() == NodeUpdated) { if (propertyChange->propertyName() == QByteArrayLiteral("layer")) { m_layer = propertyChange->value().toInt(); - m_isDirty = true; + m_dirty = true; } else if (propertyChange->propertyName() == QByteArrayLiteral("mipmapLevel")) { m_mipmapLevel = propertyChange->value().toInt(); - m_isDirty = true; + m_dirty = true; } else if (propertyChange->propertyName() == QByteArrayLiteral("cubeMapFace")) { m_face = static_cast(propertyChange->value().toInt()); - m_isDirty = true; + m_dirty = true; } else if (propertyChange->propertyName() == QByteArrayLiteral("dataFunctor")) { m_functor = propertyChange->value().value(); - m_isDirty = true; + m_dirty = true; } } + if (m_dirty) {// Notify the RenderTexture that we were updated and request it to schedule an update job + RenderTexture *txt = m_textureManager->data(m_textureProvider); + if (txt != Q_NULLPTR) + txt->addToPendingTextureJobs(); + } +} + +void RenderTextureImage::setTextureManager(TextureManager *manager) +{ + m_textureManager = manager; +} + +void RenderTextureImage::setTextureImageManager(TextureImageManager *manager) +{ + m_textureImageManager = manager; +} + +void RenderTextureImage::setTextureDataManager(TextureDataManager *manager) +{ + m_textureDataManager = manager; +} + +void RenderTextureImage::unsetDirty() +{ + m_dirty = false; +} + +// Called by LoadDataTextureJob when the texture data has been successfully load +void RenderTextureImage::setTextureDataHandle(HTextureData handle) +{ + m_textureDataHandle = handle; +} + +RenderTextureImageFunctor::RenderTextureImageFunctor(TextureManager *textureManager, + TextureImageManager *textureImageManager, + TextureDataManager *textureDataManager) + : m_textureManager(textureManager) + , m_textureImageManager(textureImageManager) + , m_textureDataManager(textureDataManager) +{ +} + +QBackendNode *RenderTextureImageFunctor::create(QNode *frontend, const QBackendNodeFactory *factory) const +{ + RenderTextureImage *backend = m_textureImageManager->getOrCreateResource(frontend->id()); + backend->setFactory(factory); + backend->setTextureManager(m_textureManager); + backend->setTextureImageManager(m_textureImageManager); + backend->setTextureDataManager(m_textureDataManager); + backend->setPeer(frontend); + return backend; +} + +QBackendNode *RenderTextureImageFunctor::get(QNode *frontend) const +{ + return m_textureImageManager->lookupResource(frontend->id()); +} + +void RenderTextureImageFunctor::destroy(QNode *frontend) const +{ + m_textureImageManager->releaseResource(frontend->id()); } } // Render diff --git a/src/render/backend/rendertextureimage_p.h b/src/render/backend/rendertextureimage_p.h index 9b1a77086..cda5216b7 100644 --- a/src/render/backend/rendertextureimage_p.h +++ b/src/render/backend/rendertextureimage_p.h @@ -46,6 +46,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -53,6 +54,10 @@ namespace Qt3D { namespace Render { +class TextureManager; +class TextureImageManager; +class TextureDataManager; + class RenderTextureImage : public QBackendNode { public: @@ -64,15 +69,54 @@ public: int m_layer; int m_mipmapLevel; QAbstractTextureProvider::CubeMapFace m_face; - bool m_isDirty; + bool m_dirty; + + inline int layer() const { return m_layer; } + inline int mipmapLevel() const { return m_mipmapLevel; } + inline QAbstractTextureProvider::CubeMapFace face() const { return m_face; } - inline bool isDirty() const { return m_isDirty; } + void setTextureManager(TextureManager *manager); + void setTextureImageManager(TextureImageManager *manager); + void setTextureDataManager(TextureDataManager *manager); + void unsetDirty(); + + inline bool isDirty() const { return m_dirty; } inline QTextureDataFunctorPtr textureDataFunctor() const { return m_functor; } + void setTextureDataHandle(HTextureData handle); + + inline HTextureData textureDataHandle() const { return m_textureDataHandle; } + inline QTextureDataFunctorPtr dataFunctor() const { return m_functor; } + private: QTextureDataFunctorPtr m_functor; + HTextureData m_textureDataHandle; + TextureManager *m_textureManager; + TextureImageManager *m_textureImageManager; + TextureDataManager *m_textureDataManager; + QList m_referencedTextures; + HTexture m_textureProvider; + QNodeId m_textureProviderId; }; +class RenderTextureImageFunctor : public QBackendNodeFunctor +{ +public: + explicit RenderTextureImageFunctor(TextureManager *textureManager, + TextureImageManager *textureImageManager, + TextureDataManager *textureDataManager); + + QBackendNode *create(QNode *frontend, const QBackendNodeFactory *factory) const Q_DECL_FINAL; + QBackendNode *get(QNode *frontend) const Q_DECL_FINAL; + void destroy(QNode *frontend) const Q_DECL_FINAL; + +private: + TextureManager *m_textureManager; + TextureImageManager *m_textureImageManager; + TextureDataManager *m_textureDataManager; +}; + + } // Render } // Qt3D diff --git a/src/render/backend/texturedatamanager.cpp b/src/render/backend/texturedatamanager.cpp index 528ade8e3..30c8cf370 100644 --- a/src/render/backend/texturedatamanager.cpp +++ b/src/render/backend/texturedatamanager.cpp @@ -47,10 +47,34 @@ namespace Qt3D { namespace Render { -void Qt3D::Render::TextureDataManager::addTextureData(Qt3D::QAbstractTextureProvider *texture) + +void TextureDataManager::addToPendingTextures(const QNodeId &textureId) +{ + m_texturesPending.append(textureId); +} + +QVector TextureDataManager::texturesPending() +{ + QVector textureIds = m_texturesPending; + m_texturesPending.clear(); + return textureIds; +} + +HTextureData TextureDataManager::textureDataFromFunctor(QTextureDataFunctorPtr functor) const +{ + QHash::const_iterator it = m_textureDataFunctors.begin(); + const QHash::const_iterator end = m_textureDataFunctors.end(); + while (it != end) { + if (*it.key() == *functor) + return it.value(); + ++it; + } + return HTextureData(); +} + +void TextureDataManager::addTextureDataForFunctor(HTextureData textureDataHandle, QTextureDataFunctorPtr functor) { - if (!contains(texture->id()) && !m_texturesPending.contains(texture)) - m_texturesPending.append(texture); + m_textureDataFunctors.insert(functor, textureDataHandle); } } // Render diff --git a/src/render/backend/texturedatamanager_p.h b/src/render/backend/texturedatamanager_p.h index d920e5e59..3c5411068 100644 --- a/src/render/backend/texturedatamanager_p.h +++ b/src/render/backend/texturedatamanager_p.h @@ -58,19 +58,20 @@ namespace Render { class TextureDataManager : public QResourceManager { public: TextureDataManager() {} + void addToPendingTextures(const QNodeId &textureId); - void addTextureData(QAbstractTextureProvider *texture); - - QList texturesPending() const { return m_texturesPending; } - void clearTexturesPending() { m_texturesPending.clear(); } + QVector texturesPending(); + HTextureData textureDataFromFunctor(QTextureDataFunctorPtr functor) const; + void addTextureDataForFunctor(HTextureData textureDataHandle, QTextureDataFunctorPtr functor); private: - QList m_texturesPending; + QVector m_texturesPending; + QHash m_textureDataFunctors; }; } // Render diff --git a/src/render/frontend/qabstracttextureimage.cpp b/src/render/frontend/qabstracttextureimage.cpp index bbb437056..5c749eb2e 100644 --- a/src/render/frontend/qabstracttextureimage.cpp +++ b/src/render/frontend/qabstracttextureimage.cpp @@ -60,6 +60,9 @@ namespace Qt3D { executed by Aspect jobs in the backend. Qt3D::QAbstractTextureImage should be subclassed to provide a functor and eventual additional properties needed by the functor to load actual data. + + \note: QAbstractTextureImage should never be shared. Expect crashes, undefined + behavior at best if this rule is not respected. */ /*! diff --git a/src/render/frontend/qabstracttextureprovider.cpp b/src/render/frontend/qabstracttextureprovider.cpp index 6d720906a..5547d73f4 100644 --- a/src/render/frontend/qabstracttextureprovider.cpp +++ b/src/render/frontend/qabstracttextureprovider.cpp @@ -51,7 +51,7 @@ namespace Qt3D { QAbstractTextureProviderPrivate::QAbstractTextureProviderPrivate(QAbstractTextureProvider *qq) : QNodePrivate(qq) , m_target(QAbstractTextureProvider::Target2D) - , m_format(QAbstractTextureProvider::RGBA8U) + , m_format(QAbstractTextureProvider::Automatic) , m_width(1) , m_height(1) , m_depth(1) @@ -62,6 +62,7 @@ QAbstractTextureProviderPrivate::QAbstractTextureProviderPrivate(QAbstractTextur , m_maximumAnisotropy(1.0f) , m_comparisonFunction(QAbstractTextureProvider::CompareLessEqual) , m_comparisonMode(QAbstractTextureProvider::CompareNone) + , m_maximumLayers(1) { } @@ -83,7 +84,7 @@ void QAbstractTextureProvider::copy(const QNode *ref) d_func()->m_maximumAnisotropy = t->d_func()->m_maximumAnisotropy; d_func()->m_comparisonFunction = t->d_func()->m_comparisonFunction; d_func()->m_comparisonMode = t->d_func()->m_comparisonMode; - // TO DO: Copy TexImageDataPtr + d_func()->m_maximumLayers = t->d_func()->m_maximumLayers; } /*! @@ -193,6 +194,32 @@ int QAbstractTextureProvider::depth() const return d->m_depth; } +/*! + Sets the maximum layers count to \a maximumLayers, by defaults, the maximum + layer count is 1. + + \note this has a meaning only for texture providers that + have 3D or array target formats. + */ +void QAbstractTextureProvider::setMaximumLayers(int maximumLayers) +{ + Q_D(QAbstractTextureProvider); + if (d->m_maximumLayers != maximumLayers) { + d->m_maximumLayers = maximumLayers; + emit maximumLayersChanged(); + } +} + +/*! + \return return the maximum layers count of the texture provider. + \note this has a meaning only for texture providers that have 3D or array target formats. + */ +int QAbstractTextureProvider::maximumLayers() const +{ + Q_D(const QAbstractTextureProvider); + return d->m_maximumLayers; +} + /*! Sets the format of the texture provider to \a format. */ @@ -258,7 +285,7 @@ bool QAbstractTextureProvider::setFromQImage(QImage img, int layer) return false; } - TexImageDataPtr dataPtr(new TexImageData(0, layer)); + TexImageDataPtr dataPtr(new TexImageData()); dataPtr->setImage(img); addImageData(dataPtr); setStatus(Loaded); @@ -279,6 +306,7 @@ QList QAbstractTextureProvider::imageData() const /*! Adds a new Qt3D::QAbstractTextureImage \a texture image to the texture provider. + \note: Qt3D::QAbstractTextureImage should never be shared by several Qt3D::QAbstractTextureProvider */ void QAbstractTextureProvider::addTextureImage(QAbstractTextureImage *textureImage) { @@ -286,6 +314,9 @@ void QAbstractTextureProvider::addTextureImage(QAbstractTextureImage *textureIma if (!d->m_textureImages.contains(textureImage)) { d->m_textureImages.append(textureImage); + + if (textureImage->parent() && textureImage->parent() != this) + qWarning() << "A QAbstractTextureImage was shared, expect a crash, undefined behavior at best"; // We need to add it as a child of the current node if it has been declared inline // Or not previously added as a child of the current node so that // 1) The backend gets notified about it's creation diff --git a/src/render/frontend/qabstracttextureprovider.h b/src/render/frontend/qabstracttextureprovider.h index ed60b20c3..e0021298f 100644 --- a/src/render/frontend/qabstracttextureprovider.h +++ b/src/render/frontend/qabstracttextureprovider.h @@ -76,6 +76,7 @@ class QT3DRENDERERSHARED_EXPORT QAbstractTextureProvider : public QNode Q_PROPERTY(float maximumAnisotropy READ maximumAnisotropy WRITE setMaximumAnisotropy NOTIFY maximumAnisotropyChanged) Q_PROPERTY(ComparisonFunction comparisonFunction READ comparisonFunction WRITE setComparisonFunction NOTIFY comparisonFunctionChanged) Q_PROPERTY(ComparisonMode comparisonMode READ comparisonMode WRITE setComparisonMode NOTIFY comparisonModeChanged) + Q_PROPERTY(int maximumLayers READ maximumLayers WRITE setMaximumLayers NOTIFY maximumLayersChanged) public: @@ -101,6 +102,7 @@ public: enum TextureFormat { NoFormat = 0, // GL_NONE + Automatic = 1, // The Qt3D engine automatically determines the best format // Unsigned normalized formats R8_UNorm = 0x8229, // GL_R8 @@ -301,6 +303,9 @@ public: int height() const; int depth() const; + void setMaximumLayers(int maximumLayers); + int maximumLayers() const; + Q_SIGNALS: void formatChanged(); void statusChanged(); @@ -313,6 +318,7 @@ Q_SIGNALS: void maximumAnisotropyChanged(); void comparisonFunctionChanged(); void comparisonModeChanged(); + void maximumLayersChanged(); protected: explicit QAbstractTextureProvider(QNode *parent = 0); diff --git a/src/render/frontend/qabstracttextureprovider_p.h b/src/render/frontend/qabstracttextureprovider_p.h index e40e1c106..b5e906aa8 100644 --- a/src/render/frontend/qabstracttextureprovider_p.h +++ b/src/render/frontend/qabstracttextureprovider_p.h @@ -73,6 +73,7 @@ public : QAbstractTextureProvider::ComparisonFunction m_comparisonFunction; QAbstractTextureProvider::ComparisonMode m_comparisonMode; QList m_textureImages; + int m_maximumLayers; }; } // QT3D diff --git a/src/render/frontend/qtextureimage.cpp b/src/render/frontend/qtextureimage.cpp index c3fc92098..4ff15d70e 100644 --- a/src/render/frontend/qtextureimage.cpp +++ b/src/render/frontend/qtextureimage.cpp @@ -69,7 +69,20 @@ public: // Will be executed from within a QAspectJob TexImageDataPtr operator ()() Q_DECL_FINAL { - return TexImageDataPtr(); + TexImageDataPtr dataPtr; + if (m_url.isLocalFile() || m_url.scheme() == QStringLiteral("qrc")) { + QString source = m_url.toString().replace(QStringLiteral("qrc"), QStringLiteral("")); + QImage img; + if (img.load(source)) { + dataPtr.reset(new TexImageData()); + dataPtr->setImage(img); + } else { + qWarning() << "Failed to load image : " << source; + } + } else { + qWarning() << "implement loading from remote URLs"; + } + return dataPtr; } bool operator ==(const QTextureDataFunctor &other) const Q_DECL_FINAL diff --git a/src/render/io/texturedata.cpp b/src/render/io/texturedata.cpp index 9331e865e..582e0259d 100644 --- a/src/render/io/texturedata.cpp +++ b/src/render/io/texturedata.cpp @@ -48,25 +48,25 @@ QT_BEGIN_NAMESPACE namespace Qt3D { -TexImageData::TexImageData(int level, int layer) : - m_layer(layer), - m_mipMapLevel(level), - m_cubeFace(QOpenGLTexture::CubeMapPositiveX), - m_isCompressed(false) +TexImageData::TexImageData() + : m_width(-1) + , m_height(-1) + , m_depth(-1) + , m_isCompressed(false) + , m_format(QOpenGLTexture::RGBA8_UNorm) { } -void TexImageData::setCubeFace(QOpenGLTexture::CubeMapFace face) -{ - m_cubeFace = face; -} - void TexImageData::setImage(const QImage &image) { QImage glImage = image.convertToFormat(QImage::Format_RGBA8888); - + m_width = image.width(); + m_height = image.height(); + m_depth = 1; QByteArray imageBytes((const char*) glImage.constBits(), glImage.byteCount()); setData(imageBytes, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); + m_format = image.hasAlphaChannel() ? QOpenGLTexture::RGBA8_UNorm : + QOpenGLTexture::RGB8_UNorm; } void TexImageData::setData(const QByteArray &data, QOpenGLTexture::PixelFormat fmt, QOpenGLTexture::PixelType ptype) diff --git a/src/render/io/texturedata.h b/src/render/io/texturedata.h index 530faeecc..b69d62d89 100644 --- a/src/render/io/texturedata.h +++ b/src/render/io/texturedata.h @@ -54,22 +54,18 @@ namespace Qt3D { class QT3DRENDERERSHARED_EXPORT TexImageData { public: - TexImageData(int level, int layer); + TexImageData(); - QOpenGLTexture::CubeMapFace cubeFace() const - { return m_cubeFace; } - - void setCubeFace(QOpenGLTexture::CubeMapFace face); - - int layer() const - { return m_layer; } - - int mipMapLevel() const - { return m_mipMapLevel; } + ~TexImageData() {} bool isCompressed() const { return m_isCompressed; } + inline int width() const { return m_width; } + inline int height() const { return m_height; } + inline int depth() const { return m_depth; } + inline QOpenGLTexture::TextureFormat format() const { return m_format; } + void setImage(const QImage &); void setData(const QByteArray &data, @@ -87,13 +83,13 @@ public: { return m_pixelType; } private: - int m_layer, m_mipMapLevel; - QOpenGLTexture::CubeMapFace m_cubeFace; + int m_width, m_height, m_depth; QOpenGLTexture::PixelFormat m_pixelFormat; QOpenGLTexture::PixelType m_pixelType; bool m_isCompressed; QByteArray m_data; + QOpenGLTexture::TextureFormat m_format; }; typedef QSharedPointer TexImageDataPtr; -- cgit v1.2.3