diff options
Diffstat (limited to 'src/render')
183 files changed, 8130 insertions, 3434 deletions
diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp index 92f44c511..2f13b27ea 100644 --- a/src/render/backend/commandexecuter.cpp +++ b/src/render/backend/commandexecuter.cpp @@ -251,13 +251,9 @@ QJsonObject parameterPackToJson(const Render::ShaderParameterPack &pack) for (auto it = uniforms.cbegin(), end = uniforms.cend(); it != end; ++it) { QJsonObject uniformObj; uniformObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(it.key())); - const Render::QUniformValue::UniformType type = it.value().type(); - uniformObj.insert(QLatin1String("value"), - type == Render::QUniformValue::Value - ? typeToJsonValue(it.value().value()) - : typeToJsonValue(it.value().textureId())); + const Render::UniformValue::ValueType type = it.value().valueType(); uniformObj.insert(QLatin1String("type"), - type == Render::QUniformValue::Value + type == Render::UniformValue::ScalarValue ? QLatin1String("value") : QLatin1String("texture")); uniformsArray.push_back(uniformObj); diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index 8d922c0d1..a45f74d50 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -90,7 +90,7 @@ class AttachmentManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: AttachmentManager() {} @@ -100,7 +100,8 @@ class CameraManager : public Qt3DCore::QResourceManager< CameraLens, Qt3DCore::QNodeId, 8, - Qt3DCore::ArrayAllocatingPolicy> + Qt3DCore::ArrayAllocatingPolicy, + Qt3DCore::NonLockingPolicy> { public: CameraManager() {} @@ -111,7 +112,7 @@ class FilterKeyManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: @@ -123,7 +124,7 @@ class EffectManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: EffectManager() {} @@ -132,7 +133,9 @@ public: class Q_AUTOTEST_EXPORT EntityManager : public Qt3DCore::QResourceManager< Entity, Qt3DCore::QNodeId, - 16> + 16, + Qt3DCore::ArrayAllocatingPolicy, + Qt3DCore::NonLockingPolicy> { public: EntityManager() {} @@ -168,7 +171,7 @@ class LayerManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: LayerManager() {} @@ -179,13 +182,18 @@ class MaterialManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: MaterialManager() {} }; -class MatrixManager : public Qt3DCore::QResourceManager<QMatrix4x4, Qt3DCore::QNodeId, 16> +class MatrixManager : public Qt3DCore::QResourceManager< + QMatrix4x4, + Qt3DCore::QNodeId, + 16, + Qt3DCore::ArrayAllocatingPolicy, + Qt3DCore::NonLockingPolicy> { public: MatrixManager() {} @@ -196,7 +204,7 @@ class ShaderManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: ShaderManager() {} @@ -207,7 +215,7 @@ class TechniqueManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: TechniqueManager() {} @@ -218,7 +226,7 @@ class TextureManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: TextureManager() {} @@ -229,7 +237,7 @@ class TransformManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: TransformManager() {} @@ -238,7 +246,9 @@ public: class VAOManager : public Qt3DCore::QResourceManager< OpenGLVertexArrayObject, QPair<HGeometry, HShader>, - 16> + 16, + Qt3DCore::ArrayAllocatingPolicy, + Qt3DCore::NonLockingPolicy> { public: VAOManager() {} @@ -249,7 +259,7 @@ class RenderTargetManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 8, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: RenderTargetManager() {} @@ -260,7 +270,7 @@ class RenderPassManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: RenderPassManager() {} @@ -272,7 +282,7 @@ class ParameterManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: ParameterManager() {} @@ -283,7 +293,7 @@ class ShaderDataManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: ShaderDataManager() {} @@ -294,7 +304,7 @@ class GLBufferManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { }; @@ -303,7 +313,7 @@ class TextureImageManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { }; @@ -312,7 +322,7 @@ class AttributeManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 20, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { }; @@ -321,7 +331,7 @@ class GeometryManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { }; @@ -330,7 +340,7 @@ class ObjectPickerManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { }; @@ -350,7 +360,7 @@ class LightManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: LightManager() {} @@ -361,7 +371,7 @@ class ComputeCommandManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { public: ComputeCommandManager() {} @@ -372,7 +382,7 @@ class RenderStateManager : public Qt3DCore::QResourceManager< Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> + Qt3DCore::NonLockingPolicy> { }; @@ -396,6 +406,8 @@ Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Geometry, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::ObjectPicker, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::BoundingVolumeDebug, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::ComputeCommand, Q_REQUIRES_CLEANUP) +Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Parameter, Q_REQUIRES_CLEANUP) +Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Transform, Q_REQUIRES_CLEANUP) QT_END_NAMESPACE diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp index 66e526d41..8472f73de 100644 --- a/src/render/backend/nodemanagers.cpp +++ b/src/render/backend/nodemanagers.cpp @@ -42,6 +42,7 @@ #include <Qt3DRender/private/managers_p.h> #include <Qt3DRender/private/scenemanager_p.h> #include <Qt3DRender/private/buffermanager_p.h> +#include <Qt3DRender/private/gltexturemanager_p.h> #include <Qt3DRender/private/texturedatamanager_p.h> #include <Qt3DRender/private/geometryrenderermanager_p.h> @@ -64,7 +65,10 @@ NodeManagers::NodeManagers() , m_effectManager(new EffectManager()) , m_renderPassManager(new RenderPassManager()) , m_textureManager(new TextureManager()) + , m_textureImageManager(new TextureImageManager()) , m_textureDataManager(new TextureDataManager()) + , m_textureImageDataManager(new TextureImageDataManager()) + , m_glTextureManager(new GLTextureManager(m_textureImageManager, m_textureDataManager, m_textureImageDataManager)) , m_layerManager(new LayerManager()) , m_filterKeyManager(new FilterKeyManager()) , m_frameGraphManager(new FrameGraphManager()) @@ -75,7 +79,6 @@ NodeManagers::NodeManagers() , m_parameterManager(new ParameterManager()) , m_shaderDataManager(new ShaderDataManager()) , m_glBufferManager(new GLBufferManager()) - , m_textureImageManager(new TextureImageManager()) , m_bufferManager(new BufferManager()) , m_attributeManager(new AttributeManager()) , m_geometryManager(new GeometryManager()) @@ -98,8 +101,10 @@ NodeManagers::~NodeManagers() delete m_techniqueManager; delete m_effectManager; delete m_renderPassManager; + delete m_glTextureManager; delete m_textureManager; delete m_textureDataManager; + delete m_textureImageDataManager; delete m_layerManager; delete m_filterKeyManager; delete m_frameGraphManager; diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h index 0675df5d9..7e1259a1d 100644 --- a/src/render/backend/nodemanagers_p.h +++ b/src/render/backend/nodemanagers_p.h @@ -90,8 +90,10 @@ class TextureImageManager; class FilterKeyManager; class FrameGraphManager; class TransformManager; +class GLTextureManager; class TextureManager; class TextureDataManager; +class TextureImageDataManager; class LayerManager; class LightManager; class ComputeCommandManager; @@ -176,8 +178,10 @@ public: inline TechniqueManager *techniqueManager() const Q_DECL_NOEXCEPT { return m_techniqueManager; } inline EffectManager *effectManager() const Q_DECL_NOEXCEPT { return m_effectManager; } inline RenderPassManager *renderPassManager() const Q_DECL_NOEXCEPT { return m_renderPassManager; } + inline GLTextureManager *glTextureManager() const Q_DECL_NOEXCEPT { return m_glTextureManager; } inline TextureManager *textureManager() const Q_DECL_NOEXCEPT { return m_textureManager; } inline TextureDataManager *textureDataManager() const Q_DECL_NOEXCEPT { return m_textureDataManager; } + inline TextureImageDataManager *textureImageDataManager() const Q_DECL_NOEXCEPT { return m_textureImageDataManager; } inline LayerManager *layerManager() const Q_DECL_NOEXCEPT { return m_layerManager; } inline FilterKeyManager *filterKeyManager() const Q_DECL_NOEXCEPT { return m_filterKeyManager; } inline FrameGraphManager *frameGraphManager() const Q_DECL_NOEXCEPT { return m_frameGraphManager; } @@ -210,7 +214,10 @@ private: EffectManager *m_effectManager; RenderPassManager *m_renderPassManager; TextureManager *m_textureManager; + TextureImageManager *m_textureImageManager; TextureDataManager *m_textureDataManager; + TextureImageDataManager *m_textureImageDataManager; + GLTextureManager *m_glTextureManager; LayerManager *m_layerManager; FilterKeyManager *m_filterKeyManager; FrameGraphManager *m_frameGraphManager; @@ -221,7 +228,6 @@ private: ParameterManager *m_parameterManager; ShaderDataManager *m_shaderDataManager; GLBufferManager *m_glBufferManager; - TextureImageManager *m_textureImageManager; BufferManager *m_bufferManager; AttributeManager *m_attributeManager; GeometryManager *m_geometryManager; diff --git a/src/render/backend/platformsurfacefilter_p.h b/src/render/backend/platformsurfacefilter_p.h index e95c45d67..ec10327fe 100644 --- a/src/render/backend/platformsurfacefilter_p.h +++ b/src/render/backend/platformsurfacefilter_p.h @@ -82,7 +82,6 @@ public: template<class T> void setSurface(T *surface) { - Q_ASSERT(surface); if (m_obj == surface) return; diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri index 256cba78e..9dc208f8b 100644 --- a/src/render/backend/render-backend.pri +++ b/src/render/backend/render-backend.pri @@ -7,7 +7,6 @@ HEADERS += \ $$PWD/renderthread_p.h \ $$PWD/renderconfiguration_p.h \ $$PWD/renderer_p.h \ - $$PWD/quniformvalue_p.h \ $$PWD/renderview_p.h \ $$PWD/rendercommand_p.h \ $$PWD/renderqueue_p.h \ @@ -36,13 +35,15 @@ HEADERS += \ $$PWD/stringtoint_p.h \ $$PWD/backendnode_p.h \ $$PWD/rendertargetoutput_p.h \ - $$PWD/commandexecuter_p.h + $$PWD/commandexecuter_p.h \ + $$PWD/uniform_p.h \ + $$PWD/shaderparameterpack_p.h \ + $$PWD/renderviewbuilder_p.h SOURCES += \ $$PWD/renderthread.cpp \ $$PWD/renderconfiguration.cpp \ $$PWD/renderer.cpp \ - $$PWD/quniformvalue.cpp \ $$PWD/renderview.cpp \ $$PWD/rendercommand.cpp \ $$PWD/renderqueue.cpp \ @@ -66,5 +67,8 @@ SOURCES += \ $$PWD/rendertargetoutput.cpp \ $$PWD/attachmentpack.cpp \ $$PWD/commandexecuter.cpp \ - $$PWD/openglvertexarrayobject.cpp + $$PWD/openglvertexarrayobject.cpp \ + $$PWD/uniform.cpp \ + $$PWD/shaderparameterpack.cpp \ + $$PWD/renderviewbuilder.cpp diff --git a/src/render/backend/rendercommand_p.h b/src/render/backend/rendercommand_p.h index dc65ac7ed..012cdbe9a 100644 --- a/src/render/backend/rendercommand_p.h +++ b/src/render/backend/rendercommand_p.h @@ -53,7 +53,7 @@ // #include <qglobal.h> -#include <Qt3DRender/private/quniformvalue_p.h> +#include <Qt3DRender/private/shaderparameterpack_p.h> #include <Qt3DRender/private/handle_types_p.h> #include <Qt3DRender/qgeometryrenderer.h> #include <QOpenGLShaderProgram> diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 49f2f4434..4176cdbb2 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -75,10 +75,13 @@ #include <Qt3DRender/private/managers_p.h> #include <Qt3DRender/private/buffermanager_p.h> #include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DRender/private/gltexturemanager_p.h> +#include <Qt3DRender/private/gltexture_p.h> #include <Qt3DRender/private/geometryrenderermanager_p.h> #include <Qt3DRender/private/openglvertexarrayobject_p.h> #include <Qt3DRender/private/platformsurfacefilter_p.h> #include <Qt3DRender/private/loadbufferjob_p.h> +#include <Qt3DRender/private/rendercapture_p.h> #include <Qt3DRender/qcameralens.h> #include <Qt3DCore/private/qeventfilterservice_p.h> @@ -149,15 +152,21 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_changeSet(0) , m_lastFrameCorrect(0) , m_glContext(nullptr) - , m_pickBoundingVolumeJob(PickBoundingVolumeJobPtr::create(this)) + , m_pickBoundingVolumeJob(PickBoundingVolumeJobPtr::create()) , m_time(0) , m_settings(nullptr) - , m_framePreparationJob(Render::FramePreparationJobPtr::create()) + , m_updateShaderDataTransformJob(Render::UpdateShaderDataTransformJobPtr::create()) , m_cleanupJob(Render::FrameCleanupJobPtr::create()) , m_worldTransformJob(Render::UpdateWorldTransformJobPtr::create()) , m_expandBoundingVolumeJob(Render::ExpandBoundingVolumeJobPtr::create()) , m_calculateBoundingVolumeJob(Render::CalculateBoundingVolumeJobPtr::create()) , m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create()) + , m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this)) + , m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create()) + , m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering)) + , m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering)) + , m_shaderGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyShaders(); }, JobTypes::DirtyShaderGathering)) + , m_ownedContext(false) #ifdef QT3D_JOBS_RUN_STATS , m_commandExecuter(new Qt3DRender::Debug::CommandExecuter(this)) #endif @@ -173,10 +182,10 @@ Renderer::Renderer(QRenderAspect::RenderType type) m_updateWorldBoundingVolumeJob->addDependency(m_worldTransformJob); m_updateWorldBoundingVolumeJob->addDependency(m_calculateBoundingVolumeJob); m_expandBoundingVolumeJob->addDependency(m_updateWorldBoundingVolumeJob); - m_framePreparationJob->addDependency(m_worldTransformJob); + m_updateShaderDataTransformJob->addDependency(m_worldTransformJob); // All world stuff depends on the RenderEntity's localBoundingVolume - m_pickBoundingVolumeJob->addDependency(m_framePreparationJob); + m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob); m_defaultRenderStateSet = new RenderStateSet; m_defaultRenderStateSet->addState(RenderStateSet::createState<DepthTest>(GL_LESS)); @@ -219,11 +228,13 @@ void Renderer::setNodeManagers(NodeManagers *managers) { m_nodesManager = managers; - m_framePreparationJob->setManagers(m_nodesManager); + m_updateShaderDataTransformJob->setManagers(m_nodesManager); m_cleanupJob->setManagers(m_nodesManager); m_calculateBoundingVolumeJob->setManagers(m_nodesManager); m_pickBoundingVolumeJob->setManagers(m_nodesManager); m_updateWorldBoundingVolumeJob->setManager(m_nodesManager->renderNodesManager()); + m_sendRenderCaptureJob->setManagers(m_nodesManager); + m_updateMeshTriangleListJob->setManagers(m_nodesManager); } NodeManagers *Renderer::nodeManagers() const @@ -267,6 +278,7 @@ void Renderer::initialize() qCDebug(Backend) << "OpenGL context created with actual format" << ctx->format(); else qCWarning(Backend) << Q_FUNC_INFO << "OpenGL context creation failed"; + m_ownedContext = true; } // Note: we don't have a surface at this point @@ -316,6 +328,12 @@ void Renderer::shutdown() void Renderer::releaseGraphicsResources() { // Clean up the graphics context and any resources + const QVector<GLTexture*> activeTextures = m_nodesManager->glTextureManager()->activeResources(); + for (GLTexture *tex : activeTextures) + tex->destroyGLTexture(); + + // TO DO: Do the same thing with buffers + m_graphicsContext.reset(nullptr); qCDebug(Backend) << Q_FUNC_INFO << "Renderer properly shutdown"; } @@ -353,7 +371,6 @@ void Renderer::setSceneRoot(QBackendNodeFactory *factory, Entity *sgRoot) qCDebug(Backend) << Q_FUNC_INFO << "DUMPING SCENE"; // Set the scene root on the jobs - m_framePreparationJob->setRoot(m_renderSceneRoot); m_worldTransformJob->setRoot(m_renderSceneRoot); m_expandBoundingVolumeJob->setRoot(m_renderSceneRoot); m_calculateBoundingVolumeJob->setRoot(m_renderSceneRoot); @@ -437,15 +454,26 @@ void Renderer::doRender() clearDirtyBits(changesToUnset); { // Scoped to destroy surfaceLock - QSurface *surface = renderViews.first()->surface(); + QSurface *surface = nullptr; + for (const Render::RenderView *rv: renderViews) { + surface = rv->surface(); + if (surface) + break; + } + SurfaceLocker surfaceLock(surface); const bool surfaceIsValid = (surface && surfaceLock.isSurfaceValid()); - if (surfaceIsValid && m_graphicsContext->beginDrawing(surface)) { + if (surfaceIsValid) { + // Reset state for each draw if we don't have complete control of the context + if (!m_ownedContext) + m_graphicsContext->setCurrentStateSet(nullptr); + if (m_graphicsContext->beginDrawing(surface)) { // 1) Execute commands for buffer uploads, texture updates, shader loading first updateGLResources(); // 2) Update VAO and copy data into commands to allow concurrent submission prepareCommandsSubmission(renderViews); preprocessingComplete = true; + } } } // 2) Proceed to next frame and start preparing frame n + 1 @@ -676,51 +704,6 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView // Prepare the ShaderParameterPack based on the active uniforms of the shader shader->prepareUniforms(command->m_parameterPack); - // TO DO: The step below could be performed by the RenderCommand builder job - { // Scoped to show extent - if ((command->m_isValid = !command->m_attributes.empty()) == false) - continue; - - // Update the draw command with what's going to be needed for the drawing - uint primitiveCount = rGeometryRenderer->vertexCount(); - uint estimatedCount = 0; - Attribute *indexAttribute = nullptr; - - const QVector<Qt3DCore::QNodeId> attributeIds = rGeometry->attributes(); - for (Qt3DCore::QNodeId attributeId : attributeIds) { - Attribute *attribute = m_nodesManager->attributeManager()->lookupResource(attributeId); - if (attribute->attributeType() == QAttribute::IndexAttribute) - indexAttribute = attribute; - else if (command->m_attributes.contains(attribute->nameId())) - estimatedCount = qMax(attribute->count(), estimatedCount); - } - - // Update the draw command with all the information required for the drawing - if ((command->m_drawIndexed = (indexAttribute != nullptr)) == true) { - command->m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType()); - command->m_indexAttributeByteOffset = indexAttribute->byteOffset(); - } - - // Use the count specified by the GeometryRender - // If not specify use the indexAttribute count if present - // Otherwise tries to use the count from the attribute with the highest count - if (primitiveCount == 0) { - if (indexAttribute) - primitiveCount = indexAttribute->count(); - else - primitiveCount = estimatedCount; - } - - command->m_primitiveCount = primitiveCount; - command->m_primitiveType = rGeometryRenderer->primitiveType(); - command->m_primitiveRestartEnabled = rGeometryRenderer->primitiveRestartEnabled(); - command->m_restartIndexValue = rGeometryRenderer->restartIndexValue(); - command->m_firstInstance = rGeometryRenderer->firstInstance(); - command->m_instanceCount = rGeometryRenderer->instanceCount(); - command->m_firstVertex = rGeometryRenderer->firstVertex(); - command->m_indexOffset = rGeometryRenderer->indexOffset(); - command->m_verticesPerPatch = rGeometryRenderer->verticesPerPatch(); - } } else if (command->m_type == RenderCommand::Compute) { Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command->m_shader); Q_ASSERT(shader); @@ -747,51 +730,160 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView m_dirtyGeometry.clear(); } -void Renderer::updateGLResources() +// Executed in a job +void Renderer::lookForDirtyBuffers() { - // TO DO: The loops could be performed in a job so that we only - // have the actual dirty elements - const QVector<HBuffer> activeBufferHandles = m_nodesManager->bufferManager()->activeHandles(); for (HBuffer handle: activeBufferHandles) { Buffer *buffer = m_nodesManager->bufferManager()->data(handle); - // Perform data upload - if (buffer->isDirty()) { - // Forces creation if it doesn't exit - if (!m_graphicsContext->hasGLBufferForBuffer(buffer)) - m_graphicsContext->glBufferForRenderBuffer(buffer); - else // Otherwise update the glBuffer - m_graphicsContext->updateBuffer(buffer); - buffer->unsetDirty(); - } + if (buffer->isDirty()) + m_dirtyBuffers.push_back(handle); } +} - const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles(); - for (HTechnique techniqueHandle : activeTechniques) { - Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle); - // If api of the renderer matches the one from the technique - if (*contextInfo() == *technique->graphicsApiFilter()) { - const auto passIds = technique->renderPasses(); - for (const QNodeId passId : passIds) { - RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId); - HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram()); - Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle); - if (shader != nullptr && !shader->isLoaded()) - m_graphicsContext->loadShader(shader); +// Executed in a job +void Renderer::lookForDirtyTextures() +{ + const QVector<HTexture> activeTextureHandles = m_nodesManager->textureManager()->activeHandles(); + for (HTexture handle: activeTextureHandles) { + Texture *texture = m_nodesManager->textureManager()->data(handle); + // Dirty meaning that something has changed on the texture + // either properties, parameters, generator or a texture image + if (texture->dirtyFlags() != Texture::NotDirty) + m_dirtyTextures.push_back(handle); + } +} + +// Executed in a job +void Renderer::lookForDirtyShaders() +{ + if (isRunning()) { + const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles(); + for (HTechnique techniqueHandle : activeTechniques) { + Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle); + // If api of the renderer matches the one from the technique + if (*contextInfo() == *technique->graphicsApiFilter()) { + const auto passIds = technique->renderPasses(); + for (const QNodeId passId : passIds) { + RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId); + HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram()); + Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle); + if (shader != nullptr && !shader->isLoaded()) + m_dirtyShaders.push_back(shaderHandle); + } } } } +} - const QVector<HTexture> activeTextureHandles = m_nodesManager->textureManager()->activeHandles(); +void Renderer::updateGLResources() +{ + const QVector<HBuffer> dirtyBufferHandles = std::move(m_dirtyBuffers); + for (HBuffer handle: dirtyBufferHandles) { + Buffer *buffer = m_nodesManager->bufferManager()->data(handle); + // Perform data upload + // Forces creation if it doesn't exit + if (!m_graphicsContext->hasGLBufferForBuffer(buffer)) + m_graphicsContext->glBufferForRenderBuffer(buffer); + else // Otherwise update the glBuffer + m_graphicsContext->updateBuffer(buffer); + buffer->unsetDirty(); + } + + const QVector<HShader> dirtyShaderHandles = std::move(m_dirtyShaders); + for (HShader handle: dirtyShaderHandles) { + Shader *shader = m_nodesManager->shaderManager()->data(handle); + // Compile shader + m_graphicsContext->loadShader(shader); + } + + const QVector<HTexture> activeTextureHandles = std::move(m_dirtyTextures); for (HTexture handle: activeTextureHandles) { Texture *texture = m_nodesManager->textureManager()->data(handle); - if (texture->isDirty()) { - // Upload/Update texture - texture->getOrCreateGLTexture(); + // Upload/Update texture + updateTexture(texture); + } +} + +void Renderer::updateTexture(Texture *texture) +{ + // For implementing unique, non-shared, non-cached textures. + // for now, every texture is shared by default + + bool isUnique = false; + + // TO DO: Update the vector once per frame (or in a job) + const QVector<HAttachment> activeRenderTargetOutputs = m_nodesManager->attachmentManager()->activeHandles(); + // A texture is unique if it's being reference by a render target output + for (const HAttachment attachmentHandle : activeRenderTargetOutputs) { + RenderTargetOutput *attachment = m_nodesManager->attachmentManager()->data(attachmentHandle); + if (attachment->textureUuid() == texture->peerId()) { + isUnique = true; + break; } } + + // Try to find the associated GLTexture for the backend Texture + GLTextureManager *glTextureManager = m_nodesManager->glTextureManager(); + GLTexture *glTexture = glTextureManager->lookupResource(texture->peerId()); + + // No GLTexture associated yet -> create it + if (glTexture == nullptr) { + if (isUnique) + glTextureManager->createUnique(texture); + else + glTextureManager->getOrCreateShared(texture); + texture->unsetDirty(); + return; + } + + // if this texture is a shared texture, we might need to look for a new TextureImpl + // and abandon the old one + if (glTextureManager->isShared(glTexture)) { + glTextureManager->abandon(glTexture, texture); + // Check if a shared texture should become unique + if (isUnique) + glTextureManager->createUnique(texture); + else + glTextureManager->getOrCreateShared(texture); + texture->unsetDirty(); + return; + } + + // this texture node is the only one referring to the GLTexture. + // we could thus directly modify the texture. Instead, for non-unique textures, + // we first see if there is already a matching texture present. + if (!isUnique) { + GLTexture *newSharedTex = glTextureManager->findMatchingShared(texture); + if (newSharedTex && newSharedTex != glTexture) { + glTextureManager->abandon(glTexture, texture); + glTextureManager->adoptShared(newSharedTex, texture); + texture->unsetDirty(); + return; + } + } + + // we hold a reference to a unique or exclusive access to a shared texture + // we can thus modify the texture directly. + const Texture::DirtyFlags dirtyFlags = texture->dirtyFlags(); + + if (dirtyFlags.testFlag(Texture::DirtyProperties) && + !glTextureManager->setProperties(glTexture, texture->properties())) + qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setProperties failed, should be non-shared"; + + if (dirtyFlags.testFlag(Texture::DirtyParameters) && + !glTextureManager->setParameters(glTexture, texture->parameters())) + qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setParameters failed, should be non-shared"; + + if (dirtyFlags.testFlag(Texture::DirtyGenerators) && + !glTextureManager->setImages(glTexture, texture->textureImages())) + qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerators failed, should be non-shared"; + + // Unset the dirty flag on the texture + texture->unsetDirty(); } + // Happens in RenderThread context when all RenderViewJobs are done // Returns the id of the last bound FBO Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Render::RenderView *> &renderViews) @@ -809,7 +901,12 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren // We might not want to render on the default FBO uint lastBoundFBOId = m_graphicsContext->boundFrameBufferObject(); QSurface *surface = nullptr; - QSurface *previousSurface = renderViews.first()->surface(); + QSurface *previousSurface = nullptr; + for (const Render::RenderView *rv: renderViews) { + previousSurface = rv->surface(); + if (previousSurface) + break; + } QSurface *lastUsedSurface = nullptr; for (int i = 0; i < renderViewsCount; ++i) { @@ -902,6 +999,14 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren // executeCommands takes care of restoring the stateset to the value // of gc->currentContext() at the moment it was called (either // renderViewStateSet or m_defaultRenderStateSet) + if (!renderView->renderCaptureNodeId().isNull()) { + QSize size = m_graphicsContext->renderTargetSize(renderView->surfaceSize() * renderView->devicePixelRatio()); + QImage image = m_graphicsContext->readFramebuffer(size); + Render::RenderCapture *renderCapture = + static_cast<Render::RenderCapture*>(m_nodesManager->frameGraphManager()->lookupNode(renderView->renderCaptureNodeId())); + renderCapture->addRenderCapture(image); + addRenderCaptureSendRequest(renderView->renderCaptureNodeId()); + } frameElapsed = timer.elapsed() - frameElapsed; qCDebug(Rendering) << Q_FUNC_INFO << "Submitted Renderview " << i + 1 << "/" << renderViewsCount << "in " << frameElapsed << "ms"; @@ -989,14 +1094,11 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() for (const QAspectJobPtr &bufferJob : bufferJobs) m_calculateBoundingVolumeJob->addDependency(bufferJob); - // Add jobs - renderBinJobs.push_back(m_framePreparationJob); - renderBinJobs.push_back(m_expandBoundingVolumeJob); - renderBinJobs.push_back(m_updateWorldBoundingVolumeJob); - renderBinJobs.push_back(m_calculateBoundingVolumeJob); - renderBinJobs.push_back(m_worldTransformJob); - renderBinJobs.push_back(m_cleanupJob); - renderBinJobs.append(bufferJobs); + // Set values on pickBoundingVolumeJob + m_pickBoundingVolumeJob->setFrameGraphRoot(frameGraphRoot()); + m_pickBoundingVolumeJob->setRenderSettings(settings()); + m_pickBoundingVolumeJob->setMouseEvents(pendingPickingEvents()); + // Traverse the current framegraph. For each leaf node create a // RenderView and set its configuration then create a job to @@ -1006,6 +1108,29 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() FrameGraphVisitor visitor(this, m_nodesManager->frameGraphManager()); visitor.traverse(frameGraphRoot(), &renderBinJobs); + // Set dependencies of resource gatherer + for (const QAspectJobPtr &jobPtr : renderBinJobs) { + jobPtr->addDependency(m_bufferGathererJob); + jobPtr->addDependency(m_textureGathererJob); + jobPtr->addDependency(m_shaderGathererJob); + } + + // Add jobs + renderBinJobs.push_back(m_updateShaderDataTransformJob); + renderBinJobs.push_back(m_updateMeshTriangleListJob); + renderBinJobs.push_back(m_expandBoundingVolumeJob); + renderBinJobs.push_back(m_updateWorldBoundingVolumeJob); + renderBinJobs.push_back(m_calculateBoundingVolumeJob); + renderBinJobs.push_back(m_worldTransformJob); + renderBinJobs.push_back(m_cleanupJob); + renderBinJobs.push_back(m_sendRenderCaptureJob); + renderBinJobs.append(bufferJobs); + + // Jobs to prepare GL Resource upload + renderBinJobs.push_back(m_bufferGathererJob); + renderBinJobs.push_back(m_textureGathererJob); + renderBinJobs.push_back(m_shaderGathererJob); + // Set target number of RenderViews m_renderQueue->setTargetRenderViewCount(visitor.leafNodeCount()); @@ -1251,6 +1376,13 @@ void Renderer::cleanGraphicsResources() const QVector<Qt3DCore::QNodeId> buffersToRelease = std::move(m_nodesManager->bufferManager()->buffersToRelease()); for (Qt3DCore::QNodeId bufferId : buffersToRelease) m_graphicsContext->releaseBuffer(bufferId); + + // Delete abandoned textures + const QVector<GLTexture*> abandonedTextures = m_nodesManager->glTextureManager()->takeAbandonedTextures(); + for (GLTexture *tex : abandonedTextures) { + tex->destroyGLTexture(); + delete tex; + } } QList<QMouseEvent> Renderer::pendingPickingEvents() const @@ -1263,6 +1395,22 @@ const GraphicsApiFilterData *Renderer::contextInfo() const return m_graphicsContext->contextInfo(); } +GraphicsContext *Renderer::graphicsContext() const +{ + return m_graphicsContext.data(); +} + +void Renderer::addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId) +{ + if (!m_pendingRenderCaptureSendRequests.contains(nodeId)) + m_pendingRenderCaptureSendRequests.push_back(nodeId); +} + +const QVector<Qt3DCore::QNodeId> Renderer::takePendingRenderCaptureSendRequests() +{ + return std::move(m_pendingRenderCaptureSendRequests); +} + // Returns a vector of jobs to be performed for dirty buffers // 1 dirty buffer == 1 job, all job can be performed in parallel QVector<Qt3DCore::QAspectJobPtr> Renderer::createRenderBufferJobs() const diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 3e6ef6ffc..cc90abe00 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -54,7 +54,7 @@ #include <Qt3DRender/qrenderaspect.h> #include <Qt3DRender/qtechnique.h> -#include <Qt3DRender/private/quniformvalue_p.h> +#include <Qt3DRender/private/shaderparameterpack_p.h> #include <Qt3DRender/private/handle_types_p.h> #include <Qt3DRender/private/abstractrenderer_p.h> #include <Qt3DCore/qaspectjob.h> @@ -65,10 +65,13 @@ #include <Qt3DRender/private/expandboundingvolumejob_p.h> #include <Qt3DRender/private/updateworldtransformjob_p.h> #include <Qt3DRender/private/calcboundingvolumejob_p.h> -#include <Qt3DRender/private/framepreparationjob_p.h> +#include <Qt3DRender/private/updateshaderdatatransformjob_p.h> #include <Qt3DRender/private/framecleanupjob_p.h> #include <Qt3DRender/private/updateworldboundingvolumejob_p.h> #include <Qt3DRender/private/platformsurfacefilter_p.h> +#include <Qt3DRender/private/sendrendercapturejob_p.h> +#include <Qt3DRender/private/genericlambdajob_p.h> +#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h> #include <QHash> #include <QMatrix4x4> @@ -83,6 +86,8 @@ #include <QScopedPointer> #include <QSemaphore> +#include <functional> + QT_BEGIN_NAMESPACE class QSurface; @@ -179,10 +184,11 @@ public: inline FrameCleanupJobPtr frameCleanupJob() const { return m_cleanupJob; } inline ExpandBoundingVolumeJobPtr expandBoundingVolumeJob() const { return m_expandBoundingVolumeJob; } - inline FramePreparationJobPtr framePreparationJob() const { return m_framePreparationJob; } + inline UpdateShaderDataTransformJobPtr updateShaderDataTransformJob() const { return m_updateShaderDataTransformJob; } inline CalculateBoundingVolumeJobPtr calculateBoundingVolumeJob() const { return m_calculateBoundingVolumeJob; } inline UpdateWorldTransformJobPtr updateWorldTransformJob() const { return m_worldTransformJob; } inline UpdateWorldBoundingVolumeJobPtr updateWorldBoundingVolumeJob() const { return m_updateWorldBoundingVolumeJob; } + inline UpdateMeshTriangleListJobPtr updateMeshTriangleListJob() const { return m_updateMeshTriangleListJob; } Qt3DCore::QAbstractFrameAdvanceService *frameAdvanceService() const Q_DECL_OVERRIDE; @@ -192,6 +198,8 @@ public: virtual RenderSettings *settings() const Q_DECL_OVERRIDE; void updateGLResources(); + void updateTexture(Texture *texture); + void prepareCommandsSubmission(const QVector<RenderView *> &renderViews); bool executeCommandsSubmission(const RenderView *rv); void updateVAOWithAttributes(Geometry *geometry, @@ -204,12 +212,15 @@ public: void setOpenGLContext(QOpenGLContext *context); const GraphicsApiFilterData *contextInfo() const; + GraphicsContext *graphicsContext() const; inline RenderStateSet *defaultRenderState() const { return m_defaultRenderStateSet; } QList<QMouseEvent> pendingPickingEvents() const; + void addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId); + const QVector<Qt3DCore::QNodeId> takePendingRenderCaptureSendRequests(); void enqueueRenderView(RenderView *renderView, int submitOrder); bool isReadyToSubmit(); @@ -278,12 +289,16 @@ private: RenderSettings *m_settings; - FramePreparationJobPtr m_framePreparationJob; + UpdateShaderDataTransformJobPtr m_updateShaderDataTransformJob; FrameCleanupJobPtr m_cleanupJob; UpdateWorldTransformJobPtr m_worldTransformJob; ExpandBoundingVolumeJobPtr m_expandBoundingVolumeJob; CalculateBoundingVolumeJobPtr m_calculateBoundingVolumeJob; UpdateWorldBoundingVolumeJobPtr m_updateWorldBoundingVolumeJob; + SendRenderCaptureJobPtr m_sendRenderCaptureJob; + UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob; + + QVector<Qt3DCore::QNodeId> m_pendingRenderCaptureSendRequests; void performDraw(RenderCommand *command); void performCompute(const RenderView *rv, RenderCommand *command); @@ -291,6 +306,20 @@ private: HVao *previousVAOHandle, OpenGLVertexArrayObject **vao); + GenericLambdaJobPtr<std::function<void ()>> m_bufferGathererJob; + GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob; + GenericLambdaJobPtr<std::function<void ()>> m_shaderGathererJob; + + void lookForDirtyBuffers(); + void lookForDirtyTextures(); + void lookForDirtyShaders(); + + QVector<HBuffer> m_dirtyBuffers; + QVector<HShader> m_dirtyShaders; + QVector<HTexture> m_dirtyTextures; + + bool m_ownedContext; + #ifdef QT3D_JOBS_RUN_STATS QScopedPointer<Qt3DRender::Debug::CommandExecuter> m_commandExecuter; friend class Qt3DRender::Debug::CommandExecuter; diff --git a/src/render/backend/rendersettings.cpp b/src/render/backend/rendersettings.cpp index 3df95c753..2cd2b1d07 100644 --- a/src/render/backend/rendersettings.cpp +++ b/src/render/backend/rendersettings.cpp @@ -56,6 +56,7 @@ RenderSettings::RenderSettings() , m_renderPolicy(QRenderSettings::OnDemand) , m_pickMethod(QPickingSettings::BoundingVolumePicking) , m_pickResultMode(QPickingSettings::NearestPick) + , m_faceOrientationPickingMode(QPickingSettings::FrontFace) , m_activeFrameGraph() { } @@ -68,6 +69,7 @@ void RenderSettings::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePt m_renderPolicy = data.renderPolicy; m_pickMethod = data.pickMethod; m_pickResultMode = data.pickResultMode; + m_faceOrientationPickingMode = data.faceOrientationPickingMode; } void RenderSettings::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -78,6 +80,8 @@ void RenderSettings::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) m_pickMethod = propertyChange->value().value<QPickingSettings::PickMethod>(); else if (propertyChange->propertyName() == QByteArrayLiteral("pickResult")) m_pickResultMode = propertyChange->value().value<QPickingSettings::PickResultMode>(); + else if (propertyChange->propertyName() == QByteArrayLiteral("faceOrientationPickingMode")) + m_faceOrientationPickingMode = propertyChange->value().value<QPickingSettings::FaceOrientationPickingMode>(); else if (propertyChange->propertyName() == QByteArrayLiteral("activeFrameGraph")) m_activeFrameGraph = propertyChange->value().value<QNodeId>(); else if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy")) diff --git a/src/render/backend/rendersettings_p.h b/src/render/backend/rendersettings_p.h index f95ec9645..37771c40b 100644 --- a/src/render/backend/rendersettings_p.h +++ b/src/render/backend/rendersettings_p.h @@ -62,7 +62,7 @@ namespace Render { class AbstractRenderer; -class RenderSettings : public BackendNode +class Q_AUTOTEST_EXPORT RenderSettings : public BackendNode { public: RenderSettings(); @@ -73,6 +73,7 @@ public: QRenderSettings::RenderPolicy renderPolicy() const { return m_renderPolicy; } QPickingSettings::PickMethod pickMethod() const { return m_pickMethod; } QPickingSettings::PickResultMode pickResultMode() const { return m_pickResultMode; } + QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode() const { return m_faceOrientationPickingMode; } private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; @@ -80,6 +81,7 @@ private: QRenderSettings::RenderPolicy m_renderPolicy; QPickingSettings::PickMethod m_pickMethod; QPickingSettings::PickResultMode m_pickResultMode; + QPickingSettings::FaceOrientationPickingMode m_faceOrientationPickingMode; Qt3DCore::QNodeId m_activeFrameGraph; }; diff --git a/src/render/backend/rendertarget_p.h b/src/render/backend/rendertarget_p.h index df73cab9a..2248edbdb 100644 --- a/src/render/backend/rendertarget_p.h +++ b/src/render/backend/rendertarget_p.h @@ -65,7 +65,7 @@ namespace Render { class RenderTargetManager; -class RenderTarget : public BackendNode +class Q_AUTOTEST_EXPORT RenderTarget : public BackendNode { public: RenderTarget(); diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index 070e50f79..ef01d27aa 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -65,7 +65,7 @@ #include <Qt3DRender/private/viewportnode_p.h> #include <Qt3DRender/private/buffermanager_p.h> #include <Qt3DRender/private/geometryrenderermanager_p.h> - +#include <Qt3DRender/private/rendercapture_p.h> #include <Qt3DRender/private/stringtoint_p.h> #include <Qt3DCore/qentity.h> #include <QtGui/qsurface.h> @@ -133,80 +133,80 @@ RenderView::StandardUniformsPFuncsHash RenderView::initializeStandardUniformSett return setters; } -QUniformValue RenderView::modelMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::modelMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue(model)); + return UniformValue(model); } -QUniformValue RenderView::viewMatrix(const QMatrix4x4 &) const +UniformValue RenderView::viewMatrix(const QMatrix4x4 &) const { - return QUniformValue(QVariant::fromValue(m_data.m_viewMatrix)); + return UniformValue(m_data.m_viewMatrix); } -QUniformValue RenderView::projectionMatrix(const QMatrix4x4 &) const +UniformValue RenderView::projectionMatrix(const QMatrix4x4 &) const { - return QUniformValue(QVariant::fromValue(m_data.m_renderCameraLens->projection())); + return UniformValue(m_data.m_renderCameraLens->projection()); } -QUniformValue RenderView::modelViewMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::modelViewMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue(m_data.m_viewMatrix * model)); + return UniformValue(m_data.m_viewMatrix * model); } -QUniformValue RenderView::viewProjectionMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::viewProjectionMatrix(const QMatrix4x4 &model) const { Q_UNUSED(model); - return QUniformValue(QVariant::fromValue(m_data.m_renderCameraLens->projection() * m_data.m_viewMatrix)); + return UniformValue(m_data.m_renderCameraLens->projection() * m_data.m_viewMatrix); } -QUniformValue RenderView::modelViewProjectionMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::modelViewProjectionMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue(m_data.m_viewProjectionMatrix * model)); + return UniformValue(m_data.m_viewProjectionMatrix * model); } -QUniformValue RenderView::inverseModelMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::inverseModelMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue(model.inverted())); + return UniformValue(model.inverted()); } -QUniformValue RenderView::inverseViewMatrix(const QMatrix4x4 &) const +UniformValue RenderView::inverseViewMatrix(const QMatrix4x4 &) const { - return QUniformValue(QVariant::fromValue(m_data.m_viewMatrix.inverted())); + return UniformValue(m_data.m_viewMatrix.inverted()); } -QUniformValue RenderView::inverseProjectionMatrix(const QMatrix4x4 &) const +UniformValue RenderView::inverseProjectionMatrix(const QMatrix4x4 &) const { QMatrix4x4 projection; if (m_data.m_renderCameraLens) projection = m_data.m_renderCameraLens->projection(); - return QUniformValue(QVariant::fromValue(projection.inverted())); + return UniformValue(projection.inverted()); } -QUniformValue RenderView::inverseModelViewMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::inverseModelViewMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue((m_data.m_viewMatrix * model).inverted())); + return UniformValue((m_data.m_viewMatrix * model).inverted()); } -QUniformValue RenderView::inverseViewProjectionMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::inverseViewProjectionMatrix(const QMatrix4x4 &model) const { Q_UNUSED(model); const auto viewProjectionMatrix = m_data.m_renderCameraLens->projection() * m_data.m_viewMatrix; - return QUniformValue(QVariant::fromValue(viewProjectionMatrix.inverted())); + return UniformValue(viewProjectionMatrix.inverted()); } -QUniformValue RenderView::inverseModelViewProjectionMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::inverseModelViewProjectionMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue((m_data.m_viewProjectionMatrix * model).inverted(0))); + return UniformValue((m_data.m_viewProjectionMatrix * model).inverted(0)); } -QUniformValue RenderView::modelNormalMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::modelNormalMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue(model.normalMatrix())); + return UniformValue(model.normalMatrix()); } -QUniformValue RenderView::modelViewNormalMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::modelViewNormalMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue((m_data.m_viewMatrix * model).normalMatrix())); + return UniformValue((m_data.m_viewMatrix * model).normalMatrix()); } // TODO: Move this somewhere global where GraphicsContext::setViewport() can use it too @@ -218,38 +218,38 @@ static QRectF resolveViewport(const QRectF &fractionalViewport, const QSize &sur fractionalViewport.height() * surfaceSize.height()); } -QUniformValue RenderView::viewportMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::viewportMatrix(const QMatrix4x4 &model) const { // TODO: Can we avoid having to pass the model matrix in to these functions? Q_UNUSED(model); QMatrix4x4 viewportMatrix; viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize)); - return QUniformValue(QVariant::fromValue(viewportMatrix)); + return UniformValue(viewportMatrix); } -QUniformValue RenderView::inverseViewportMatrix(const QMatrix4x4 &model) const +UniformValue RenderView::inverseViewportMatrix(const QMatrix4x4 &model) const { Q_UNUSED(model); QMatrix4x4 viewportMatrix; viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize)); QMatrix4x4 inverseViewportMatrix = viewportMatrix.inverted(); - return QUniformValue(QVariant::fromValue(inverseViewportMatrix)); + return UniformValue(inverseViewportMatrix); } -QUniformValue RenderView::time(const QMatrix4x4 &model) const +UniformValue RenderView::time(const QMatrix4x4 &model) const { Q_UNUSED(model); qint64 time = m_renderer->time(); float t = time / 1000000000.0f; - return QUniformValue(QVariant(t)); + return UniformValue(t); } -QUniformValue RenderView::eyePosition(const QMatrix4x4 &model) const +UniformValue RenderView::eyePosition(const QMatrix4x4 &model) const { Q_UNUSED(model); - return QUniformValue(QVariant::fromValue(m_data.m_eyePos)); + return UniformValue(m_data.m_eyePos); } RenderView::RenderView() @@ -326,7 +326,7 @@ void RenderView::sort() // sharing the same material (shader) are rendered, we can't have the case // where two uniforms, referencing the same texture eventually have 2 different // texture unit values - const QUniformValue refValue = cachedUniforms.value(it.key()); + const UniformValue refValue = cachedUniforms.value(it.key()); if (it.value() == refValue) { it = uniforms.erase(it); } else { @@ -418,13 +418,15 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit const Qt3DCore::QNodeId materialComponentId = node->componentUuid<Material>(); const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId); + HGeometry geometryHandle = m_manager->lookupHandle<Geometry, GeometryManager, HGeometry>(geometryRenderer->geometryId()); + Geometry *geometry = m_manager->data<Geometry, GeometryManager>(geometryHandle); // 1 RenderCommand per RenderPass pass on an Entity with a Mesh for (const RenderPassParameterData &passData : renderPassData) { // Add the RenderPass Parameters RenderCommand *command = new RenderCommand(); command->m_depth = m_data.m_eyePos.distanceToPoint(node->worldBoundingVolume()->center()); - command->m_geometry = m_manager->lookupHandle<Geometry, GeometryManager, HGeometry>(geometryRenderer->geometryId()); + command->m_geometry = geometryHandle; command->m_geometryRenderer = geometryRendererHandle; // For RenderPass based states we use the globally set RenderState // if no renderstates are defined as part of the pass. That means: @@ -455,6 +457,51 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit // make sure this is cleared before we leave this function setShaderAndUniforms(command, pass, globalParameters, *(node->worldTransform()), lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS))); + // Store all necessary information for actual drawing if command is valid + command->m_isValid = !command->m_attributes.empty(); + if (command->m_isValid) { + // Update the draw command with what's going to be needed for the drawing + uint primitiveCount = geometryRenderer->vertexCount(); + uint estimatedCount = 0; + Attribute *indexAttribute = nullptr; + + const QVector<Qt3DCore::QNodeId> attributeIds = geometry->attributes(); + for (Qt3DCore::QNodeId attributeId : attributeIds) { + Attribute *attribute = m_manager->attributeManager()->lookupResource(attributeId); + if (attribute->attributeType() == QAttribute::IndexAttribute) + indexAttribute = attribute; + else if (command->m_attributes.contains(attribute->nameId())) + estimatedCount = qMax(attribute->count(), estimatedCount); + } + + // Update the draw command with all the information required for the drawing + command->m_drawIndexed = (indexAttribute != nullptr); + if (command->m_drawIndexed) { + command->m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType()); + command->m_indexAttributeByteOffset = indexAttribute->byteOffset(); + } + + // Use the count specified by the GeometryRender + // If not specified use the indexAttribute count if present + // Otherwise tries to use the count from the attribute with the highest count + if (primitiveCount == 0) { + if (indexAttribute) + primitiveCount = indexAttribute->count(); + else + primitiveCount = estimatedCount; + } + + command->m_primitiveCount = primitiveCount; + command->m_primitiveType = geometryRenderer->primitiveType(); + command->m_primitiveRestartEnabled = geometryRenderer->primitiveRestartEnabled(); + command->m_restartIndexValue = geometryRenderer->restartIndexValue(); + command->m_firstInstance = geometryRenderer->firstInstance(); + command->m_instanceCount = geometryRenderer->instanceCount(); + command->m_firstVertex = geometryRenderer->firstVertex(); + command->m_indexOffset = geometryRenderer->indexOffset(); + command->m_verticesPerPatch = geometryRenderer->verticesPerPatch(); + } + buildSortingKey(command); commands.append(command); } @@ -532,27 +579,23 @@ void RenderView::updateMatrices() } } -void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, const QVariant &value) const +void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, const UniformValue &value) const { - Texture *tex = nullptr; // At this point a uniform value can only be a scalar type // or a Qt3DCore::QNodeId corresponding to a Texture // ShaderData/Buffers would be handled as UBO/SSBO and would therefore // not be in the default uniform block - if (static_cast<QMetaType::Type>(value.userType()) == qNodeIdTypeId) { - // Speed up conversion to avoid using QVariant::value() - const Qt3DCore::QNodeId texId = variant_value<Qt3DCore::QNodeId>(value); - if ((tex = m_manager->textureManager()->lookupResource(texId)) - != nullptr) { - uniformPack.setTexture(nameId, tex->peerId()); - //TextureUniform *texUniform = m_allocator->allocate<TextureUniform>(); - QUniformValue texUniform; - texUniform.setType(QUniformValue::TextureSampler); - texUniform.setTextureId(tex->peerId()); - uniformPack.setUniform(nameId, texUniform); + if (value.valueType() == UniformValue::NodeId) { + const Qt3DCore::QNodeId texId = *value.constData<Qt3DCore::QNodeId>(); + const Texture *tex = m_manager->textureManager()->lookupResource(texId); + if (tex != nullptr) { + uniformPack.setTexture(nameId, texId); + UniformValue::Texture textureValue; + textureValue.nodeId = texId; + uniformPack.setUniform(nameId, UniformValue(textureValue)); } } else { - uniformPack.setUniform(nameId, QUniformValue(value)); + uniformPack.setUniform(nameId, value); } } @@ -564,14 +607,14 @@ void RenderView::setStandardUniformValue(ShaderParameterPack &uniformPack, int g void RenderView::setUniformBlockValue(ShaderParameterPack &uniformPack, Shader *shader, const ShaderUniformBlock &block, - const QVariant &value) const + const UniformValue &value) const { Q_UNUSED(shader) - if (static_cast<QMetaType::Type>(value.userType()) == qNodeIdTypeId) { + if (value.valueType() == UniformValue::NodeId) { Buffer *buffer = nullptr; - if ((buffer = m_manager->bufferManager()->lookupResource(variant_value<Qt3DCore::QNodeId>(value))) != nullptr) { + if ((buffer = m_manager->bufferManager()->lookupResource(*value.constData<Qt3DCore::QNodeId>())) != nullptr) { BlockToUBO uniformBlockUBO; uniformBlockUBO.m_blockIndex = block.m_index; uniformBlockUBO.m_bufferID = buffer->peerId(); @@ -634,12 +677,12 @@ void RenderView::setUniformBlockValue(ShaderParameterPack &uniformPack, void RenderView::setShaderStorageValue(ShaderParameterPack &uniformPack, Shader *shader, const ShaderStorageBlock &block, - const QVariant &value) const + const UniformValue &value) const { Q_UNUSED(shader) - if (static_cast<QMetaType::Type>(value.userType()) == qNodeIdTypeId) { + if (value.valueType() == UniformValue::NodeId) { Buffer *buffer = nullptr; - if ((buffer = m_manager->bufferManager()->lookupResource(variant_value<Qt3DCore::QNodeId>(value))) != nullptr) { + if ((buffer = m_manager->bufferManager()->lookupResource(*value.constData<Qt3DCore::QNodeId>())) != nullptr) { BlockToSSBO shaderStorageBlock; shaderStorageBlock.m_blockIndex = block.m_index; shaderStorageBlock.m_bufferID = buffer->peerId(); @@ -666,8 +709,9 @@ void RenderView::setDefaultUniformBlockShaderDataValue(ShaderParameterPack &unif QHash<int, QVariant>::const_iterator activeValuesIt = builder->activeUniformNamesToValue.constBegin(); const QHash<int, QVariant>::const_iterator activeValuesEnd = builder->activeUniformNamesToValue.constEnd(); + // TO DO: Make the ShaderData store UniformValue while (activeValuesIt != activeValuesEnd) { - setUniformValue(uniformPack, activeValuesIt.key(), activeValuesIt.value()); + setUniformValue(uniformPack, activeValuesIt.key(), UniformValue::fromVariant(activeValuesIt.value())); ++activeValuesIt; } } @@ -767,10 +811,10 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, } else if (shaderStorageBlockNamesIds.indexOf(it->nameId) != -1) { // Parameters is a SSBO setShaderStorageValue(command->m_parameterPack, shader, shader->storageBlockForBlockNameId(it->nameId), it->value); } else { // Parameter is a struct - const QVariant &v = it->value; + const UniformValue &v = it->value; ShaderData *shaderData = nullptr; - if (static_cast<QMetaType::Type>(v.userType()) == qNodeIdTypeId && - (shaderData = m_manager->shaderDataManager()->lookupResource(variant_value<Qt3DCore::QNodeId>(v))) != nullptr) { + if (v.valueType() == UniformValue::NodeId && + (shaderData = m_manager->shaderDataManager()->lookupResource(*v.constData<Qt3DCore::QNodeId>())) != nullptr) { // Try to check if we have a struct or array matching a QShaderData parameter setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, StringToInt::lookupString(it->nameId)); } @@ -798,6 +842,7 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, if (lightIdx == MAX_LIGHTS) break; + // Note: implicit conversion of values to UniformValue setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[lightIdx], worldPos); setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[lightIdx], int(QAbstractLight::PointLight)); setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[lightIdx], QVector3D(1.0f, 1.0f, 1.0f)); @@ -816,9 +861,10 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, } if (uniformNamesIds.contains(LIGHT_COUNT_NAME_ID)) - setUniformValue(command->m_parameterPack, LIGHT_COUNT_NAME_ID, qMax(1, lightIdx)); + setUniformValue(command->m_parameterPack, LIGHT_COUNT_NAME_ID, UniformValue(qMax(1, lightIdx))); if (activeLightSources.isEmpty()) { + // Note: implicit conversion of values to UniformValue setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[0], QVector3D(10.0f, 10.0f, 0.0f)); setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[0], int(QAbstractLight::PointLight)); setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[0], QVector3D(1.0f, 1.0f, 1.0f)); diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h index 7be9903f6..41b0192c0 100644 --- a/src/render/backend/renderview_p.h +++ b/src/render/backend/renderview_p.h @@ -214,6 +214,9 @@ public: void updateMatrices(); + inline void setRenderCaptureNodeId(const Qt3DCore::QNodeId nodeId) Q_DECL_NOTHROW { m_renderCaptureNodeId = nodeId; } + inline const Qt3DCore::QNodeId renderCaptureNodeId() const Q_DECL_NOTHROW { return m_renderCaptureNodeId; } + // Helps making the size of RenderView smaller // Contains all the data needed for the actual building of the RenderView // But that aren't used later by the Renderer @@ -244,6 +247,8 @@ private: mutable QThreadStorage<UniformBlockValueBuilder*> m_localData; + Qt3DCore::QNodeId m_renderCaptureNodeId; + Renderer *m_renderer; NodeManagers *m_manager; QSize m_surfaceSize; @@ -274,39 +279,39 @@ private: QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> m_parameters; - typedef QHash<int, QUniformValue (RenderView::*)(const QMatrix4x4& model) const> StandardUniformsPFuncsHash; + typedef QHash<int, UniformValue (RenderView::*)(const QMatrix4x4& model) const> StandardUniformsPFuncsHash; static StandardUniformsPFuncsHash ms_standardUniformSetters; static StandardUniformsPFuncsHash initializeStandardUniformSetters(); - QUniformValue modelMatrix(const QMatrix4x4& model) const; - QUniformValue viewMatrix(const QMatrix4x4&) const; - QUniformValue projectionMatrix(const QMatrix4x4 &) const; - QUniformValue modelViewMatrix(const QMatrix4x4 &model) const; - QUniformValue viewProjectionMatrix(const QMatrix4x4 &model) const; - QUniformValue modelViewProjectionMatrix(const QMatrix4x4 &model) const; - QUniformValue inverseModelMatrix(const QMatrix4x4 &model) const; - QUniformValue inverseViewMatrix(const QMatrix4x4 &) const; - QUniformValue inverseProjectionMatrix(const QMatrix4x4 &) const; - QUniformValue inverseModelViewMatrix(const QMatrix4x4 &model) const; - QUniformValue inverseViewProjectionMatrix(const QMatrix4x4 &model) const; - QUniformValue inverseModelViewProjectionMatrix(const QMatrix4x4 &model) const; - QUniformValue modelNormalMatrix(const QMatrix4x4 &model) const; - QUniformValue modelViewNormalMatrix(const QMatrix4x4 &model) const; - QUniformValue viewportMatrix(const QMatrix4x4 &model) const; - QUniformValue inverseViewportMatrix(const QMatrix4x4 &model) const; - QUniformValue time(const QMatrix4x4 &model) const; - QUniformValue eyePosition(const QMatrix4x4 &model) const; - - void setUniformValue(ShaderParameterPack &uniformPack, int nameId, const QVariant &value) const; + UniformValue modelMatrix(const QMatrix4x4& model) const; + UniformValue viewMatrix(const QMatrix4x4&) const; + UniformValue projectionMatrix(const QMatrix4x4 &) const; + UniformValue modelViewMatrix(const QMatrix4x4 &model) const; + UniformValue viewProjectionMatrix(const QMatrix4x4 &model) const; + UniformValue modelViewProjectionMatrix(const QMatrix4x4 &model) const; + UniformValue inverseModelMatrix(const QMatrix4x4 &model) const; + UniformValue inverseViewMatrix(const QMatrix4x4 &) const; + UniformValue inverseProjectionMatrix(const QMatrix4x4 &) const; + UniformValue inverseModelViewMatrix(const QMatrix4x4 &model) const; + UniformValue inverseViewProjectionMatrix(const QMatrix4x4 &model) const; + UniformValue inverseModelViewProjectionMatrix(const QMatrix4x4 &model) const; + UniformValue modelNormalMatrix(const QMatrix4x4 &model) const; + UniformValue modelViewNormalMatrix(const QMatrix4x4 &model) const; + UniformValue viewportMatrix(const QMatrix4x4 &model) const; + UniformValue inverseViewportMatrix(const QMatrix4x4 &model) const; + UniformValue time(const QMatrix4x4 &model) const; + UniformValue eyePosition(const QMatrix4x4 &model) const; + + void setUniformValue(ShaderParameterPack &uniformPack, int nameId, const UniformValue &value) const; void setStandardUniformValue(ShaderParameterPack &uniformPack, int glslNameId, int nameId, const QMatrix4x4 &worldTransform) const; void setUniformBlockValue(ShaderParameterPack &uniformPack, Shader *shader, const ShaderUniformBlock &block, - const QVariant &value) const; + const UniformValue &value) const; void setShaderStorageValue(ShaderParameterPack &uniformPack, Shader *shader, const ShaderStorageBlock &block, - const QVariant &value) const; + const UniformValue &value) const; void setDefaultUniformBlockShaderDataValue(ShaderParameterPack &uniformPack, Shader *shader, ShaderData *shaderData, diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp new file mode 100644 index 000000000..34bd8e61b --- /dev/null +++ b/src/render/backend/renderviewbuilder.cpp @@ -0,0 +1,510 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderviewbuilder_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +const int RenderViewBuilder::m_optimalParallelJobCount = std::max(QThread::idealThreadCount(), 2); + +namespace { + +class SyncRenderViewCommandBuilders +{ +public: + explicit SyncRenderViewCommandBuilders(const RenderViewInitializerJobPtr &renderViewJob, + const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs, + Renderer *renderer) + : m_renderViewJob(renderViewJob) + , m_renderViewBuilderJobs(renderViewBuilderJobs) + , m_renderer(renderer) + {} + + void operator()() + { + // Append all the commands and sort them + RenderView *rv = m_renderViewJob->renderView(); + + int totalCommandCount = 0; + for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) + totalCommandCount += renderViewCommandBuilder->commands().size(); + + QVector<RenderCommand *> commands; + commands.reserve(totalCommandCount); + + // Reduction + for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) + commands += std::move(renderViewCommandBuilder->commands()); + rv->setCommands(commands); + + // Sort the commands + rv->sort(); + + // Enqueue our fully populated RenderView with the RenderThread + m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex()); + } + +private: + RenderViewInitializerJobPtr m_renderViewJob; + QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs; + Renderer *m_renderer; +}; + +class SyncFrustumCulling +{ +public: + explicit SyncFrustumCulling(const RenderViewInitializerJobPtr &renderViewJob, + const FrustumCullingJobPtr &frustumCulling) + : m_renderViewJob(renderViewJob) + , m_frustumCullingJob(frustumCulling) + {} + + void operator()() + { + RenderView *rv = m_renderViewJob->renderView(); + + // Update matrices now that all transforms have been updated + rv->updateMatrices(); + + // Frustum culling + m_frustumCullingJob->setViewProjection(rv->viewProjectionMatrix()); + } + +private: + RenderViewInitializerJobPtr m_renderViewJob; + FrustumCullingJobPtr m_frustumCullingJob; +}; + +class SyncRenderViewInitialization +{ +public: + explicit SyncRenderViewInitialization(const RenderViewInitializerJobPtr &renderViewJob, + const FrustumCullingJobPtr &frustumCullingJob, + const FilterLayerEntityJobPtr &filterEntityByLayerJob, + const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs, + const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs) + : m_renderViewJob(renderViewJob) + , m_frustumCullingJob(frustumCullingJob) + , m_filterEntityByLayerJob(filterEntityByLayerJob) + , m_materialGathererJobs(materialGathererJobs) + , m_renderViewBuilderJobs(renderViewBuilderJobs) + {} + + void operator()() + { + RenderView *rv = m_renderViewJob->renderView(); + + // Layer filtering + m_filterEntityByLayerJob->setHasLayerFilter(rv->hasLayerFilter()); + m_filterEntityByLayerJob->setLayers(rv->layerFilter()); + + // Material Parameter building + for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) { + materialGatherer->setRenderPassFilter(const_cast<RenderPassFilter *>(rv->renderPassFilter())); + materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter())); + } + + // Command builders + for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) + renderViewCommandBuilder->setRenderView(rv); + + // Set whether frustum culling is enabled or not + m_frustumCullingJob->setActive(rv->frustumCulling()); + } + +private: + RenderViewInitializerJobPtr m_renderViewJob; + FrustumCullingJobPtr m_frustumCullingJob; + FilterLayerEntityJobPtr m_filterEntityByLayerJob; + QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs; + QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs; +}; + +class SyncRenderCommandBuilding +{ +public: + explicit SyncRenderCommandBuilding(const RenderViewInitializerJobPtr &renderViewJob, + const FrustumCullingJobPtr &frustumCullingJob, + const FilterLayerEntityJobPtr &filterEntityByLayerJob, + const LightGathererPtr &lightGathererJob, + const RenderableEntityFilterPtr &renderableEntityFilterJob, + const ComputableEntityFilterPtr &computableEntityFilterJob, + const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs, + const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs) + : m_renderViewJob(renderViewJob) + , m_frustumCullingJob(frustumCullingJob) + , m_filterEntityByLayerJob(filterEntityByLayerJob) + , m_lightGathererJob(lightGathererJob) + , m_renderableEntityFilterJob(renderableEntityFilterJob) + , m_computableEntityFilterJob(computableEntityFilterJob) + , m_materialGathererJobs(materialGathererJobs) + , m_renderViewBuilderJobs(renderViewBuilderJobs) + {} + + void operator()() + { + // Set the result of previous job computations + // for final RenderCommand building + RenderView *rv = m_renderViewJob->renderView(); + + if (!rv->noDraw()) { + // Set the light sources + rv->setLightSources(std::move(m_lightGathererJob->lights())); + + // Remove all entities from the compute and renderable vectors that aren't in the filtered layer vector + QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities(); + + // We sort the vector so that the removal can then be performed linearly + if (!rv->isCompute()) { + QVector<Entity *> renderableEntities = std::move(m_renderableEntityFilterJob->filteredEntities()); + std::sort(renderableEntities.begin(), renderableEntities.end()); + RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, filteredEntities); + + if (rv->frustumCulling()) + RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_frustumCullingJob->visibleEntities()); + + // Split among the number of command builders + const int packetSize = renderableEntities.size() / RenderViewBuilder::optimalJobCount(); + for (auto i = 0, m = RenderViewBuilder::optimalJobCount(); i < m; ++i) { + const RenderViewBuilderJobPtr renderViewCommandBuilder = m_renderViewBuilderJobs.at(i); + if (i == m - 1) + renderViewCommandBuilder->setRenderables(renderableEntities.mid(i * packetSize, packetSize + renderableEntities.size() % m)); + else + renderViewCommandBuilder->setRenderables(renderableEntities.mid(i * packetSize, packetSize)); + } + } else { + QVector<Entity *> computableEntities = std::move(m_computableEntityFilterJob->filteredEntities()); + std::sort(computableEntities.begin(), computableEntities.end()); + RenderViewBuilder::removeEntitiesNotInSubset(computableEntities, filteredEntities); + + // Split among the number of command builders + const int packetSize = computableEntities.size() / RenderViewBuilder::optimalJobCount(); + for (auto i = 0, m = RenderViewBuilder::optimalJobCount(); i < m; ++i) { + const RenderViewBuilderJobPtr renderViewCommandBuilder = m_renderViewBuilderJobs.at(i); + if (i == m - 1) + renderViewCommandBuilder->setRenderables(computableEntities.mid(i * packetSize, packetSize + computableEntities.size() % m)); + else + renderViewCommandBuilder->setRenderables(computableEntities.mid(i * packetSize, packetSize)); + } + } + + // Reduction + QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> params; + for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) + params.unite(materialGatherer->materialToPassAndParameter()); + // Set all required data on the RenderView for final processing + rv->setMaterialParameterTable(std::move(params)); + } + } + +private: + RenderViewInitializerJobPtr m_renderViewJob; + FrustumCullingJobPtr m_frustumCullingJob; + FilterLayerEntityJobPtr m_filterEntityByLayerJob; + LightGathererPtr m_lightGathererJob; + RenderableEntityFilterPtr m_renderableEntityFilterJob; + ComputableEntityFilterPtr m_computableEntityFilterJob; + QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs; + QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs; +}; + +class SetClearDrawBufferIndex +{ +public: + explicit SetClearDrawBufferIndex(const RenderViewInitializerJobPtr &renderViewJob) + : m_renderViewJob(renderViewJob) + {} + + void operator()() + { + RenderView *rv = m_renderViewJob->renderView(); + QVector<ClearBufferInfo> &clearBuffersInfo = rv->specificClearColorBufferInfo(); + const AttachmentPack &attachmentPack = rv->attachmentPack(); + for (ClearBufferInfo &clearBufferInfo : clearBuffersInfo) + clearBufferInfo.drawBufferIndex = attachmentPack.getDrawBufferIndex(clearBufferInfo.attchmentPoint); + + } + +private: + RenderViewInitializerJobPtr m_renderViewJob; +}; + +} // anonymous + +RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer) + : m_renderViewIndex(renderViewIndex) + , m_renderer(renderer) + , m_renderViewJob(RenderViewInitializerJobPtr::create()) + , m_filterEntityByLayerJob(Render::FilterLayerEntityJobPtr::create()) + , m_lightGathererJob(Render::LightGathererPtr::create()) + , m_renderableEntityFilterJob(RenderableEntityFilterPtr::create()) + , m_computableEntityFilterJob(ComputableEntityFilterPtr::create()) + , m_frustumCullingJob(Render::FrustumCullingJobPtr::create()) + , m_syncFrustumCullingJob(SynchronizerJobPtr::create(SyncFrustumCulling(m_renderViewJob, m_frustumCullingJob), JobTypes::SyncFrustumCulling)) + , m_setClearDrawBufferIndexJob(SynchronizerJobPtr::create(SetClearDrawBufferIndex(m_renderViewJob), JobTypes::ClearBufferDrawIndex)) +{ + // Init what we can here + EntityManager *entityManager = m_renderer->nodeManagers()->renderNodesManager(); + m_filterEntityByLayerJob->setManager(m_renderer->nodeManagers()); + m_renderableEntityFilterJob->setManager(entityManager); + m_computableEntityFilterJob->setManager(entityManager); + m_frustumCullingJob->setRoot(m_renderer->sceneRoot()); + m_lightGathererJob->setManager(entityManager); + m_renderViewJob->setRenderer(m_renderer); + m_renderViewJob->setFrameGraphLeafNode(leafNode); + m_renderViewJob->setSubmitOrderIndex(m_renderViewIndex); + + // RenderCommand building is the most consuming task -> split it + // Estimate the number of jobs to create based on the number of entities + m_renderViewBuilderJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); + for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { + auto renderViewCommandBuilder = Render::RenderViewBuilderJobPtr::create(); + renderViewCommandBuilder->setIndex(m_renderViewIndex); + renderViewCommandBuilder->setRenderer(m_renderer); + m_renderViewBuilderJobs.push_back(renderViewCommandBuilder); + } + + // Since Material gathering is an heavy task, we split it + const QVector<HMaterial> materialHandles = m_renderer->nodeManagers()->materialManager()->activeHandles(); + const int elementsPerJob = materialHandles.size() / RenderViewBuilder::m_optimalParallelJobCount; + const int lastRemaingElements = materialHandles.size() % RenderViewBuilder::m_optimalParallelJobCount; + m_materialGathererJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); + for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { + auto materialGatherer = Render::MaterialParameterGathererJobPtr::create(); + materialGatherer->setNodeManagers(m_renderer->nodeManagers()); + materialGatherer->setRenderer(m_renderer); + if (i == RenderViewBuilder::m_optimalParallelJobCount - 1) + materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob + lastRemaingElements)); + else + materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob)); + m_materialGathererJobs.push_back(materialGatherer); + } + + m_syncRenderViewInitializationJob = SynchronizerJobPtr::create(SyncRenderViewInitialization(m_renderViewJob, + m_frustumCullingJob, + m_filterEntityByLayerJob, + m_materialGathererJobs, + m_renderViewBuilderJobs), + JobTypes::SyncRenderViewInitialization); + + m_syncRenderCommandBuildingJob = SynchronizerJobPtr::create(SyncRenderCommandBuilding(m_renderViewJob, + m_frustumCullingJob, + m_filterEntityByLayerJob, + m_lightGathererJob, + m_renderableEntityFilterJob, + m_computableEntityFilterJob, + m_materialGathererJobs, + m_renderViewBuilderJobs), + JobTypes::SyncRenderViewCommandBuilding); + + m_syncRenderViewCommandBuildersJob = SynchronizerJobPtr::create(SyncRenderViewCommandBuilders(m_renderViewJob, + m_renderViewBuilderJobs, + m_renderer), + JobTypes::SyncRenderViewCommandBuilder); +} + +RenderViewInitializerJobPtr RenderViewBuilder::renderViewJob() const +{ + return m_renderViewJob; +} + +FilterLayerEntityJobPtr RenderViewBuilder::filterEntityByLayerJob() const +{ + return m_filterEntityByLayerJob; +} + +LightGathererPtr RenderViewBuilder::lightGathererJob() const +{ + return m_lightGathererJob; +} + +RenderableEntityFilterPtr RenderViewBuilder::renderableEntityFilterJob() const +{ + return m_renderableEntityFilterJob; +} + +ComputableEntityFilterPtr RenderViewBuilder::computableEntityFilterJob() const +{ + return m_computableEntityFilterJob; +} + +FrustumCullingJobPtr RenderViewBuilder::frustumCullingJob() const +{ + return m_frustumCullingJob; +} + +QVector<RenderViewBuilderJobPtr> RenderViewBuilder::renderViewBuilderJobs() const +{ + return m_renderViewBuilderJobs; +} + +QVector<MaterialParameterGathererJobPtr> RenderViewBuilder::materialGathererJobs() const +{ + return m_materialGathererJobs; +} + +SynchronizerJobPtr RenderViewBuilder::syncRenderViewInitializationJob() const +{ + return m_syncRenderViewInitializationJob; +} + +SynchronizerJobPtr RenderViewBuilder::syncFrustumCullingJob() const +{ + return m_syncFrustumCullingJob; +} + +SynchronizerJobPtr RenderViewBuilder::syncRenderCommandBuildingJob() const +{ + return m_syncRenderCommandBuildingJob; +} + +SynchronizerJobPtr RenderViewBuilder::syncRenderViewCommandBuildersJob() const +{ + return m_syncRenderViewCommandBuildersJob; +} + +SynchronizerJobPtr RenderViewBuilder::setClearDrawBufferIndexJob() const +{ + return m_setClearDrawBufferIndexJob; +} + +QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const +{ + QVector<Qt3DCore::QAspectJobPtr> jobs; + + jobs.reserve(m_materialGathererJobs.size() + m_renderViewBuilderJobs.size() + 11); + + // Set dependencies + m_syncFrustumCullingJob->addDependency(m_renderer->updateWorldTransformJob()); + m_syncFrustumCullingJob->addDependency(m_renderer->updateShaderDataTransformJob()); + m_syncFrustumCullingJob->addDependency(m_syncRenderViewInitializationJob); + + m_frustumCullingJob->addDependency(m_renderer->expandBoundingVolumeJob()); + m_frustumCullingJob->addDependency(m_syncFrustumCullingJob); + + m_setClearDrawBufferIndexJob->addDependency(m_syncRenderViewInitializationJob); + + m_syncRenderViewInitializationJob->addDependency(m_renderViewJob); + + m_filterEntityByLayerJob->addDependency(m_syncRenderViewInitializationJob); + + m_syncRenderCommandBuildingJob->addDependency(m_syncRenderViewInitializationJob); + for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) { + materialGatherer->addDependency(m_syncRenderViewInitializationJob); + m_syncRenderCommandBuildingJob->addDependency(materialGatherer); + } + m_syncRenderCommandBuildingJob->addDependency(m_renderableEntityFilterJob); + m_syncRenderCommandBuildingJob->addDependency(m_computableEntityFilterJob); + m_syncRenderCommandBuildingJob->addDependency(m_filterEntityByLayerJob); + m_syncRenderCommandBuildingJob->addDependency(m_lightGathererJob); + m_syncRenderCommandBuildingJob->addDependency(m_frustumCullingJob); + + for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) { + renderViewCommandBuilder->addDependency(m_syncRenderCommandBuildingJob); + m_syncRenderViewCommandBuildersJob->addDependency(renderViewCommandBuilder); + } + + m_renderer->frameCleanupJob()->addDependency(m_syncRenderViewCommandBuildersJob); + m_renderer->frameCleanupJob()->addDependency(m_setClearDrawBufferIndexJob); + + // Add jobs + jobs.push_back(m_renderViewJob); // Step 1 + jobs.push_back(m_renderableEntityFilterJob); // Step 1 + jobs.push_back(m_lightGathererJob); // Step 1 + + // Note: do it only if OpenGL 4.3+ available + jobs.push_back(m_computableEntityFilterJob); // Step 1 + + jobs.push_back(m_syncRenderViewInitializationJob); // Step 2 + + jobs.push_back(m_syncFrustumCullingJob); // Step 3 + jobs.push_back(m_filterEntityByLayerJob); // Step 3 + jobs.push_back(m_setClearDrawBufferIndexJob); // Step 3 + + for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) // Step3 + jobs.push_back(materialGatherer); + + jobs.push_back(m_frustumCullingJob); // Step 4 + jobs.push_back(m_syncRenderCommandBuildingJob); // Step 4 + + for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 5 + jobs.push_back(renderViewCommandBuilder); + + jobs.push_back(m_syncRenderViewCommandBuildersJob); // Step 6 + + return jobs; +} + +Renderer *RenderViewBuilder::renderer() const +{ + return m_renderer; +} + +int RenderViewBuilder::renderViewIndex() const +{ + return m_renderViewIndex; +} + +int RenderViewBuilder::optimalJobCount() +{ + return RenderViewBuilder::m_optimalParallelJobCount; +} + +void RenderViewBuilder::removeEntitiesNotInSubset(QVector<Entity *> &entities, QVector<Entity *> subset) +{ + // Note: assumes entities was sorted already + std::sort(subset.begin(), subset.end()); + + for (auto i = entities.size() - 1, j = subset.size() - 1; i >= 0; --i) { + while (j >= 0 && subset.at(j) > entities.at(i)) + --j; + if (j < 0 || entities.at(i) != subset.at(j)) + entities.removeAt(i); + } +} + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/backend/renderviewbuilder_p.h b/src/render/backend/renderviewbuilder_p.h new file mode 100644 index 000000000..6f09a6282 --- /dev/null +++ b/src/render/backend/renderviewbuilder_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_RENDERVIEWBUILDER_H +#define QT3DRENDER_RENDER_RENDERVIEWBUILDER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <functional> +#include <Qt3DCore/qaspectjob.h> +#include <Qt3DRender/private/filterentitybycomponentjob_p.h> +#include <Qt3DRender/private/filterlayerentityjob_p.h> +#include <Qt3DRender/private/genericlambdajob_p.h> +#include <Qt3DRender/private/materialparametergathererjob_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DRender/private/renderviewbuilderjob_p.h> +#include <Qt3DRender/private/renderview_p.h> +#include <Qt3DRender/private/frustumcullingjob_p.h> +#include <Qt3DRender/private/lightgatherer_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class Renderer; + +using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>; +using ComputableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::ComputeCommand, Render::Material>; +using RenderableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::GeometryRenderer, Render::Material>; + +class Q_AUTOTEST_EXPORT RenderViewBuilder +{ +public: + explicit RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer); + + RenderViewInitializerJobPtr renderViewJob() const; + FilterLayerEntityJobPtr filterEntityByLayerJob() const; + LightGathererPtr lightGathererJob() const; + RenderableEntityFilterPtr renderableEntityFilterJob() const; + ComputableEntityFilterPtr computableEntityFilterJob() const; + FrustumCullingJobPtr frustumCullingJob() const; + QVector<RenderViewBuilderJobPtr> renderViewBuilderJobs() const; + QVector<MaterialParameterGathererJobPtr> materialGathererJobs() const; + SynchronizerJobPtr syncRenderViewInitializationJob() const; + SynchronizerJobPtr syncFrustumCullingJob() const; + SynchronizerJobPtr syncRenderCommandBuildingJob() const; + SynchronizerJobPtr syncRenderViewCommandBuildersJob() const; + SynchronizerJobPtr setClearDrawBufferIndexJob() const; + + QVector<Qt3DCore::QAspectJobPtr> buildJobHierachy() const; + + Renderer *renderer() const; + int renderViewIndex() const; + + static int optimalJobCount(); + static void removeEntitiesNotInSubset(QVector<Entity *> &entities, QVector<Entity *> subset); + +private: + const int m_renderViewIndex; + Renderer *m_renderer; + + RenderViewInitializerJobPtr m_renderViewJob; + FilterLayerEntityJobPtr m_filterEntityByLayerJob; + LightGathererPtr m_lightGathererJob; + RenderableEntityFilterPtr m_renderableEntityFilterJob; + ComputableEntityFilterPtr m_computableEntityFilterJob; + FrustumCullingJobPtr m_frustumCullingJob; + QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs; + QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs; + + SynchronizerJobPtr m_syncRenderViewInitializationJob; + SynchronizerJobPtr m_syncFrustumCullingJob; + SynchronizerJobPtr m_syncRenderCommandBuildingJob; + SynchronizerJobPtr m_syncRenderViewCommandBuildersJob; + SynchronizerJobPtr m_setClearDrawBufferIndexJob; + + static const int m_optimalParallelJobCount; +}; + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_RENDERVIEWBUILDER_H diff --git a/src/render/backend/quniformvalue.cpp b/src/render/backend/shaderparameterpack.cpp index 09327c213..01a977aee 100644 --- a/src/render/backend/quniformvalue.cpp +++ b/src/render/backend/shaderparameterpack.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "quniformvalue_p.h" +#include "shaderparameterpack_p.h" #include <Qt3DRender/private/graphicscontext_p.h> #include <Qt3DRender/private/texture_p.h> @@ -55,42 +55,12 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { -void QUniformValue::apply(GraphicsContext *ctx, const ShaderUniform &description) const -{ - switch (m_type) { - case Value: - ctx->bindUniform(m_var, description); - break; - - case TextureSampler: - // We assume that the texture has been successfully bound and attache to a texture unit - if (m_textureIdUnit.m_textureUnit != -1) { - ctx->bindUniform(m_textureIdUnit.m_textureUnit, description); -#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) - int err = ctx->openGLContext()->functions()->glGetError(); - if (err) { - qCWarning(Render::Backend, "Error %d after setting uniform \"%s\" at location %d", - err, qUtf8Printable(description.m_name), description.m_location); - } -#endif - } else { - qCWarning(Render::Backend, "Invalid texture unit supplied for \"%s\"", - qUtf8Printable(description.m_nameId)); - } - break; - - default: - break; - } -} - - ShaderParameterPack::~ShaderParameterPack() { m_uniforms.clear(); } -void ShaderParameterPack::setUniform(const int glslNameId, const QUniformValue &val) +void ShaderParameterPack::setUniform(const int glslNameId, const UniformValue &val) { m_uniforms.insert(glslNameId, val); } diff --git a/src/render/backend/quniformvalue_p.h b/src/render/backend/shaderparameterpack_p.h index fb8158d84..c0ab05e57 100644 --- a/src/render/backend/quniformvalue_p.h +++ b/src/render/backend/shaderparameterpack_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QT3DRENDER_RENDER_QUNIFORMVALUE_H -#define QT3DRENDER_RENDER_QUNIFORMVALUE_H +#ifndef QT3DRENDER_RENDER_SHADERPARAMETERPACK_P_H +#define QT3DRENDER_RENDER_SHADERPARAMETERPACK_P_H // // W A R N I N G @@ -58,6 +58,7 @@ #include <Qt3DCore/qnodeid.h> #include <Qt3DRender/private/renderlogging_p.h> #include <Qt3DRender/private/shadervariables_p.h> +#include <Qt3DRender/private/uniform_p.h> QT_BEGIN_NAMESPACE @@ -72,118 +73,6 @@ namespace Render { class GraphicsContext; -class QUniformValue -{ -public: - enum UniformType { - Value, - TextureSampler, - Unknown - }; - - QUniformValue() - : m_type(Unknown) - , m_var() - { - } - - explicit QUniformValue(const QVariant &var, UniformType type = Value) - : m_type(type) - , m_var(var) - { - } - - void setType(UniformType type) Q_DECL_NOTHROW { m_type = type; } - UniformType type() const Q_DECL_NOTHROW { return m_type; } - bool isTexture() const Q_DECL_NOTHROW { return m_type == TextureSampler; } - - void setValue(const QVariant &value) - { - Q_ASSERT(m_type == Value); - m_var = value; - } - - QVariant value() const - { - Q_ASSERT(m_type == Value); - return m_var; - } - - void setTextureUnit(int textureUnit) - { - Q_ASSERT(m_type == TextureSampler); - m_textureIdUnit.m_textureUnit = textureUnit; - } - - int textureUnit() const - { - Q_ASSERT(m_type == TextureSampler); - return m_textureIdUnit.m_textureUnit; - } - - void setTextureId(Qt3DCore::QNodeId textureId) - { - Q_ASSERT(m_type == TextureSampler); - m_textureIdUnit.m_textureId = textureId; - } - - Qt3DCore::QNodeId textureId() const - { - Q_ASSERT(m_type == TextureSampler); - return m_textureIdUnit.m_textureId; - } - - bool operator ==(const QUniformValue &other) - { - if (other.m_type != m_type) - return false; - - switch (m_type) { - case Value: - return other.m_var == m_var; - case TextureSampler: - return other.m_textureIdUnit == m_textureIdUnit; - default: - break; - } - return false; - } - - bool operator !=(const QUniformValue &other) - { - return !operator ==(other); - } - - void apply(GraphicsContext *ctx, const ShaderUniform &description) const; - -protected: - struct TextureIdUnit { - Qt3DCore::QNodeId m_textureId; - int m_textureUnit; - - TextureIdUnit() - : m_textureId() - , m_textureUnit(-1) - {} - - bool operator == (const TextureIdUnit &other) const Q_DECL_NOTHROW - { - return (other.m_textureId == m_textureId) && (other.m_textureUnit == m_textureUnit); - } - - bool operator !=(const TextureIdUnit &other) const Q_DECL_NOTHROW - { - return !operator ==(other); - } - }; - - // TODO: Replace QVariant with our own union of GLSL types as we don't - // need the full flexibility of QVariant on the backend - UniformType m_type; - QVariant m_var; - TextureIdUnit m_textureIdUnit; -}; - struct BlockToUBO { int m_blockIndex; Qt3DCore::QNodeId m_bufferID; @@ -199,14 +88,14 @@ struct BlockToSSBO { QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, BlockToSSBO, Q_PRIMITIVE_TYPE) -typedef QHash<int, QUniformValue> PackUniformHash; +typedef QHash<int, UniformValue> PackUniformHash; class ShaderParameterPack { public: ~ShaderParameterPack(); - void setUniform(const int glslNameId, const QUniformValue &val); + void setUniform(const int glslNameId, const UniformValue &val); void setTexture(const int glslNameId, Qt3DCore::QNodeId id); void setUniformBuffer(BlockToUBO blockToUBO); void setShaderStorageBuffer(BlockToSSBO blockToSSBO); @@ -214,7 +103,7 @@ public: inline PackUniformHash &uniforms() { return m_uniforms; } inline const PackUniformHash &uniforms() const { return m_uniforms; } - QUniformValue uniform(const int glslNameId) const { return m_uniforms.value(glslNameId); } + UniformValue uniform(const int glslNameId) const { return m_uniforms.value(glslNameId); } struct NamedTexture { @@ -249,4 +138,4 @@ QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, ShaderParameterPack::NamedTexture, Q QT_END_NAMESPACE -#endif // QT3DRENDER_RENDER_QUNIFORMVALUE_H +#endif // QT3DRENDER_RENDER_SHADERPARAMETERPACK_P_H diff --git a/src/render/backend/transform.cpp b/src/render/backend/transform.cpp index ef6942f54..636c2d103 100644 --- a/src/render/backend/transform.cpp +++ b/src/render/backend/transform.cpp @@ -59,6 +59,15 @@ Transform::Transform() { } +void Transform::cleanup() +{ + m_rotation = QQuaternion(); + m_scale = QVector3D(); + m_translation = QVector3D(); + m_transformMatrix = QMatrix4x4(); + QBackendNode::setEnabled(false); +} + void Transform::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) { const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QTransformData>>(change); @@ -74,6 +83,21 @@ QMatrix4x4 Transform::transformMatrix() const return m_transformMatrix; } +QVector3D Transform::scale() const +{ + return m_scale; +} + +QQuaternion Transform::rotation() const +{ + return m_rotation; +} + +QVector3D Transform::translation() const +{ + return m_translation; +} + void Transform::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { // TODO: Flag the matrix as dirty and update all matrices batched in a job diff --git a/src/render/backend/transform_p.h b/src/render/backend/transform_p.h index a36005d2d..4b58e3cae 100644 --- a/src/render/backend/transform_p.h +++ b/src/render/backend/transform_p.h @@ -65,12 +65,17 @@ namespace Render { class Renderer; class TransformManager; -class Transform : public BackendNode +class Q_AUTOTEST_EXPORT Transform : public BackendNode { public: Transform(); + void cleanup(); QMatrix4x4 transformMatrix() const; + QVector3D scale() const; + QQuaternion rotation() const; + QVector3D translation() const; + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; void updateMatrix(); diff --git a/src/render/backend/triangleboundingvolume_p.h b/src/render/backend/triangleboundingvolume_p.h index 5ce0f1574..cc394041b 100644 --- a/src/render/backend/triangleboundingvolume_p.h +++ b/src/render/backend/triangleboundingvolume_p.h @@ -108,6 +108,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::Render::TriangleBoundingVolume*) +Q_DECLARE_METATYPE(Qt3DRender::Render::TriangleBoundingVolume*) // LCOV_EXCL_LINE #endif // QT3DRENDER_RENDER_TRIANGLEBOUNDINGVOLUME_P_H diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp new file mode 100644 index 000000000..0369f3f5e --- /dev/null +++ b/src/render/backend/uniform.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "uniform_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +namespace { + +const int qNodeIdTypeId = qMetaTypeId<Qt3DCore::QNodeId>(); + +// glUniform*fv/glUniform*iv/glUniform*uiv -> only handles sizeof(float)/sizeof(int) +int byteSizeForMetaType(int type) +{ + switch (type) { + case QMetaType::Bool: + case QMetaType::Int: + case QMetaType::UInt: + case QMetaType::ULongLong: + case QMetaType::LongLong: + case QMetaType::Long: + case QMetaType::ULong: + case QMetaType::Short: + case QMetaType::UShort: + case QMetaType::Char: + case QMetaType::UChar: + return sizeof(int); + + case QMetaType::Float: + case QMetaType::Double: // Assumes conversion to float + return sizeof(float); + + case QMetaType::QPoint: + case QMetaType::QSize: + return 2 * sizeof(int); + + case QMetaType::QRect: + return 4 * sizeof(int); + + case QMetaType::QPointF: + case QMetaType::QSizeF: + case QMetaType::QVector2D: + return 2 * sizeof(float); + + case QMetaType::QVector3D: + return 3 * sizeof(float); + + case QMetaType::QRectF: + case QMetaType::QVector4D: + case QMetaType::QColor: + return 4 * sizeof(float); + + case QMetaType::QMatrix4x4: + return 16 * sizeof(float); + default: + Q_UNREACHABLE(); + return -1; + } +} + +} // anonymous + +UniformValue UniformValue::fromVariant(const QVariant &variant) +{ + // Texture/Buffer case + if (variant.userType() == qNodeIdTypeId) + return UniformValue(variant.value<Qt3DCore::QNodeId>()); + + UniformValue v; + switch (variant.userType()) { + case QMetaType::Bool: + v.data<bool>()[0] = variant.toBool(); + break; + case QMetaType::Int: + case QMetaType::UInt: + case QMetaType::Long: + case QMetaType::LongLong: + case QMetaType::Short: + case QMetaType::ULong: + case QMetaType::ULongLong: + case QMetaType::UShort: + case QMetaType::Char: + case QMetaType::UChar: + v.data<int>()[0] = variant.toInt(); + break; + case QMetaType::Float: + case QMetaType::Double: // Convert double to floats + v.m_data[0] = variant.toFloat(); + break; + case QMetaType::QPoint: { + const QPoint p = variant.toPoint(); + v.data<int>()[0] = p.x(); + v.data<int>()[1] = p.y(); + break; + } + case QMetaType::QSize: { + const QSize s = variant.toSize(); + v.data<int>()[0] = s.width(); + v.data<int>()[1] = s.height(); + break; + } + case QMetaType::QRect: { + const QRect r = variant.toRect(); + v.data<int>()[0] = r.x(); + v.data<int>()[1] = r.y(); + v.data<int>()[2] = r.width(); + v.data<int>()[3] = r.height(); + break; + } + case QMetaType::QSizeF: { + const QSizeF s = variant.toSize(); + v.m_data[0] = s.width(); + v.m_data[1] = s.height(); + break; + } + case QMetaType::QPointF: { + const QPointF p = variant.toPointF(); + v.m_data[0] = p.x(); + v.m_data[1] = p.y(); + break; + } + case QMetaType::QRectF: { + const QRectF r = variant.toRect(); + v.m_data[0] = r.x(); + v.m_data[1] = r.y(); + v.m_data[2] = r.width(); + v.m_data[3] = r.height(); + break; + } + case QMetaType::QVector2D: { + const QVector2D vec2 = variant.value<QVector2D>(); + v.m_data[0] = vec2.x(); + v.m_data[1] = vec2.y(); + break; + } + case QMetaType::QVector3D: { + const QVector3D vec3 = variant.value<QVector3D>(); + v.m_data[0] = vec3.x(); + v.m_data[1] = vec3.y(); + v.m_data[2] = vec3.z(); + break; + } + case QMetaType::QVector4D: { + const QVector4D vec4 = variant.value<QVector4D>(); + v.m_data[0] = vec4.x(); + v.m_data[1] = vec4.y(); + v.m_data[2] = vec4.z(); + v.m_data[3] = vec4.w(); + break; + } + case QMetaType::QColor: { + const QColor col = variant.value<QColor>(); + v.m_data[0] = col.redF(); + v.m_data[1] = col.greenF(); + v.m_data[2] = col.blueF(); + v.m_data[3] = col.alphaF(); + break; + } + case QMetaType::QMatrix4x4: { + const QMatrix4x4 mat44 = variant.value<QMatrix4x4>(); + // Use constData because we want column-major layout + v.m_data.resize(16); + memcpy(v.data<float>(), mat44.constData(), 16 * sizeof(float)); + break; + } + case QMetaType::QVariantList: { + const QVariantList variants = variant.toList(); + if (variants.size() < 1) + break; + + const int listEntryType = variants.first().userType(); + const int stride = byteSizeForMetaType(listEntryType) / sizeof(float); + // Resize v.m_data + v.m_data.resize(stride * variants.size()); + + int idx = 0; + for (const QVariant &variant : variants) { + Q_ASSERT_X(variant.userType() == listEntryType, + Q_FUNC_INFO, + "Uniform array doesn't contain elements of the same type"); + UniformValue vi = UniformValue::fromVariant(variant); + memcpy(v.data<float>() + idx, vi.data<float>(), stride * sizeof(float)); + idx += stride; + } + break; + } + + default: + Q_UNREACHABLE(); + } + return v; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h new file mode 100644 index 000000000..56a50aea2 --- /dev/null +++ b/src/render/backend/uniform_p.h @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_UNIFORM_P_H +#define QT3DRENDER_RENDER_UNIFORM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qt3drender_global.h> +#include <Qt3DCore/qnodeid.h> + +#include <QMatrix4x4> +#include <QVector2D> +#include <QVector3D> +#include <QColor> + +#include <QDebug> +#include <string.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +enum UniformType { + Float = 0, + Vec2, + Vec3, + Vec4, + Double, + DVec2, + DVec3, + DVec4, + Int, + IVec2, + IVec3, + IVec4, + UInt, + UIVec2, + UIVec3, + UIVec4, + Bool, + BVec2, + BVec3, + BVec4, + Mat2, + Mat3, + Mat4, + Mat2x3, + Mat3x2, + Mat2x4, + Mat4x2, + Mat3x4, + Mat4x3, + Sampler, + Unknown +}; + +class Q_AUTOTEST_EXPORT UniformValue +{ +public: + enum ValueType { + ScalarValue, + NodeId, + TextureValue, + BufferValue + }; + + struct Texture { + int textureId = 0; // Set first so that glUniform1iv will work + Qt3DCore::QNodeId nodeId; + }; + + // UniformValue implicitely converts doubles to floats to ensure + // correct rendering behavior for the cases where Qt3D parameters created from + // a double or QVariant(double) are used to fill uniform values that in reality + // should be floats. This occur especially with QML where qreal might be double + // and not float. Otherwise, at when filling the uniforms, calling constData<float> + // on something that contains a double will result in wrong values + + UniformValue() + : m_data(4) + { + memset(m_data.data(), 0, m_data.size() * sizeof(float)); + } + + UniformValue(int i) : UniformValue() { data<int>()[0] = i; } + UniformValue(uint i) : UniformValue() { data<uint>()[0] = i; } + UniformValue(float f) : UniformValue() { data<float>()[0] = f; } + UniformValue(double d) : UniformValue() { data<float>()[0] = d; } // Double to float conversion + UniformValue(bool b) : UniformValue() { data<bool>()[0] = b; } + UniformValue(const QVector2D &vec2) : UniformValue() { memcpy(m_data.data(), &vec2, sizeof(QVector2D)); } + UniformValue(const QVector3D &vec3) : UniformValue() { memcpy(m_data.data(), &vec3, sizeof(QVector3D)); } + UniformValue(const QVector4D &vec4) : m_data(4) { memcpy(m_data.data(), &vec4, sizeof(QVector4D)); } + + UniformValue(const QMatrix3x3 &mat33) + : m_data(9) + { + // Use constData because we want column-major layout + memcpy(m_data.data(), mat33.constData(), 9 * sizeof(float)); + } + + UniformValue(const QMatrix4x4 &mat44) + : m_data(16) + { + // Use constData because we want column-major layout + memcpy(m_data.data(), mat44.constData(), 16 * sizeof(float)); + } + + // For nodes which will later be replaced by a Texture or Buffer + UniformValue(Qt3DCore::QNodeId id) + : UniformValue() + { + m_valueType = NodeId; + memcpy(m_data.data(), &id, sizeof(Qt3DCore::QNodeId)); + } + + // For textures + UniformValue(UniformValue::Texture t) + : UniformValue() + { + m_valueType = TextureValue; + memcpy(m_data.data(), &t, sizeof(Texture)); + } + + ValueType valueType() const { return m_valueType; } + + static UniformValue fromVariant(const QVariant &variant); + + template<typename T> + const T *constData() const + { + return reinterpret_cast<const T *>(m_data.constData()); + } + + template<typename T> + T *data() + { + return reinterpret_cast<T *>(m_data.data()); + } + + bool operator==(const UniformValue &other) const + { + return other.m_data == m_data; + } + + bool operator!=(const UniformValue &other) const + { + return !(*this == other); + } +private: + // Allocate 4 floats on stack + // For larger elements, heap allocation will be used + QVarLengthArray<float, 4> m_data; + + ValueType m_valueType = ScalarValue; +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Qt3DRender::Render::UniformType) // LCOV_EXCL_LINE + +#endif // QT3DRENDER_RENDER_UNIFORM_P_H diff --git a/src/render/framegraph/framegraph.pri b/src/render/framegraph/framegraph.pri index 1e4ca3a60..d40da198f 100644 --- a/src/render/framegraph/framegraph.pri +++ b/src/render/framegraph/framegraph.pri @@ -41,7 +41,10 @@ HEADERS += \ $$PWD/qrendersurfaceselector.h \ $$PWD/qrendersurfaceselector_p.h \ $$PWD/rendersurfaceselector_p.h \ - $$PWD/qdispatchcompute_p.h + $$PWD/qdispatchcompute_p.h \ + $$PWD/qrendercapture.h \ + $$PWD/qrendercapture_p.h \ + $$PWD/rendercapture_p.h SOURCES += \ $$PWD/cameraselectornode.cpp \ @@ -72,4 +75,6 @@ SOURCES += \ $$PWD/qdispatchcompute.cpp \ $$PWD/dispatchcompute.cpp \ $$PWD/qrendersurfaceselector.cpp \ - $$PWD/rendersurfaceselector.cpp + $$PWD/rendersurfaceselector.cpp \ + $$PWD/qrendercapture.cpp \ + $$PWD/rendercapture.cpp diff --git a/src/render/framegraph/framegraphnode.cpp b/src/render/framegraph/framegraphnode.cpp index 9bd069832..dcf3cfacc 100644 --- a/src/render/framegraph/framegraphnode.cpp +++ b/src/render/framegraph/framegraphnode.cpp @@ -55,8 +55,9 @@ FrameGraphNode::FrameGraphNode() { } -FrameGraphNode::FrameGraphNode(FrameGraphNodeType nodeType) - : m_nodeType(nodeType) +FrameGraphNode::FrameGraphNode(FrameGraphNodeType nodeType, QBackendNode::Mode mode) + : BackendNode(mode) + , m_nodeType(nodeType) , m_manager(nullptr) { } diff --git a/src/render/framegraph/framegraphnode_p.h b/src/render/framegraph/framegraphnode_p.h index 1de955abc..a29fb8070 100644 --- a/src/render/framegraph/framegraphnode_p.h +++ b/src/render/framegraph/framegraphnode_p.h @@ -89,7 +89,8 @@ public: FrustumCulling, Lighting, ComputeDispatch, - Surface + Surface, + RenderCapture }; FrameGraphNodeType nodeType() const { return m_nodeType; } @@ -109,7 +110,7 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; protected: - FrameGraphNode(FrameGraphNodeType nodeType); + FrameGraphNode(FrameGraphNodeType nodeType, QBackendNode::Mode mode = QBackendNode::ReadOnly); void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_OVERRIDE; private: diff --git a/src/render/framegraph/framegraphvisitor.cpp b/src/render/framegraph/framegraphvisitor.cpp index 3afde9574..d31e9cddd 100644 --- a/src/render/framegraph/framegraphvisitor.cpp +++ b/src/render/framegraph/framegraphvisitor.cpp @@ -43,15 +43,7 @@ #include "framegraphnode_p.h" #include <Qt3DRender/private/renderer_p.h> #include <Qt3DRender/private/managers_p.h> -#include <Qt3DRender/private/filterentitybycomponentjob_p.h> -#include <Qt3DRender/private/filterlayerentityjob_p.h> -#include <Qt3DRender/private/genericlambdajob_p.h> -#include <Qt3DRender/private/materialparametergathererjob_p.h> -#include <Qt3DRender/private/nodemanagers_p.h> -#include <Qt3DRender/private/renderviewbuilderjob_p.h> -#include <Qt3DRender/private/renderview_p.h> -#include <Qt3DRender/private/frustumcullingjob_p.h> -#include <Qt3DRender/private/lightgatherer_p.h> +#include <Qt3DRender/private/renderviewbuilder_p.h> #include <QThreadPool> QT_BEGIN_NAMESPACE @@ -106,271 +98,8 @@ void FrameGraphVisitor::visit(Render::FrameGraphNode *node) // TODO: Pass in only framegraph config that has changed from previous // index RenderViewJob. if (fgChildIds.empty()) { - // 1) Prepare parameter pack for all possible Pass Filter / Technique Filter - // At most 1 of each per RenderView -> not very frequent -> doesn't need to be in a job - - // 1) Update all the ShaderData - - // 1) RenderView initialization from - // 2) One job to filter out the Entities in a layers (no dependency) - // 2) -> One job to filter out only the Entities with a QDispatchCompute - // 2) -> One job to filter out only the Entities with a GeometryRenderer - // 2) -> n job to create all ParameterInfoList for each Material - // 2) -> One job to perform frustrum culling of layered filtered entities - - // -> 3) Merge Parameter pack 1 / 2 + Material - // -> 4) n job to prepare the commands - // -> One job to sort the RenderCommands - // -> One job to set the active uniforms / build the ParameterPack - - // GenericLambdaJob will be used to sync data between jobs and their dependencies - // Prefer linear iteration over tree traversal - - const int currentRenderViewIndex = m_renderviewIndex++; - const int optimalParallelJobCount = std::max(QThread::idealThreadCount(), 2); - auto renderViewJob = RenderViewInitializerJobPtr::create(); - auto filterEntityByLayer = Render::FilterLayerEntityJobPtr::create(); - auto lightGatherer = Render::LightGathererPtr::create(); - auto renderableEntityFilterer = Render::FilterEntityByComponentJobPtr<Render::GeometryRenderer, Render::Material>::create(); - - // Note: do it only if OpenGL 4.3+ available - auto computeEntityFilterer = Render::FilterEntityByComponentJobPtr<Render::ComputeCommand, Render::Material>::create(); - - auto frustumCulling = Render::FrustumCullingJobPtr::create(); - - // Copy for lambda capture - Renderer *renderer = m_renderer; - - // Init what we can here - EntityManager *entityManager = m_renderer->nodeManagers()->renderNodesManager(); - filterEntityByLayer->setManager(m_renderer->nodeManagers()); - renderableEntityFilterer->setManager(entityManager); - computeEntityFilterer->setManager(entityManager); - frustumCulling->setRoot(m_renderer->sceneRoot()); - lightGatherer->setManager(entityManager); - renderViewJob->setRenderer(m_renderer); - renderViewJob->setFrameGraphLeafNode(node); - renderViewJob->setSubmitOrderIndex(currentRenderViewIndex); - - // RenderCommand building is the most consuming task -> split it - QVector<Render::RenderViewBuilderJobPtr> renderViewCommandBuilders; - // Estimate the number of jobs to create based on the number of entities - renderViewCommandBuilders.reserve(optimalParallelJobCount); - for (auto i = 0; i < optimalParallelJobCount; ++i) { - auto renderViewCommandBuilder = Render::RenderViewBuilderJobPtr::create(); - renderViewCommandBuilder->setIndex(currentRenderViewIndex); - renderViewCommandBuilder->setRenderer(m_renderer); - renderViewCommandBuilders.push_back(renderViewCommandBuilder); - } - - // Since Material gathering is an heavy task, we split it - QVector<Render::MaterialParameterGathererJobPtr> materialGatherers; - { // Scoped to avoid copy in lambdas - const QVector<HMaterial> materialHandles = m_renderer->nodeManagers()->materialManager()->activeHandles(); - const int elementsPerJob = materialHandles.size() / optimalParallelJobCount; - const int lastRemaingElements = materialHandles.size() % optimalParallelJobCount; - materialGatherers.reserve(optimalParallelJobCount); - for (auto i = 0; i < optimalParallelJobCount; ++i) { - auto materialGatherer = Render::MaterialParameterGathererJobPtr::create(); - materialGatherer->setNodeManagers(m_renderer->nodeManagers()); - materialGatherer->setRenderer(m_renderer); - if (i == optimalParallelJobCount - 1) - materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob + lastRemaingElements)); - else - materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob)); - materialGatherers.push_back(materialGatherer); - } - } - - // Copy shared ptr -> this is called once the FrameGraphBranch was used to fill initial data in the RenderView - auto syncRenderViewInitialization = [=] () { - RenderView *rv = renderViewJob->renderView(); - - // Layer filtering - filterEntityByLayer->setHasLayerFilter(rv->hasLayerFilter()); - - if (rv->hasLayerFilter()) - filterEntityByLayer->setLayers(rv->layerFilter()); - - // Material Parameter building - for (const auto materialGatherer : qAsConst(materialGatherers)) { - materialGatherer->setRenderPassFilter(const_cast<RenderPassFilter *>(rv->renderPassFilter())); - materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter())); - } - - // Command builders - for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders)) - renderViewCommandBuilder->setRenderView(rv); - - // Set whether frustum culling is enabled or not - frustumCulling->setActive(rv->frustumCulling()); - }; - - // Copy shared ptr -> this is called once the FrameGraphBranch was used to fill initial data in the RenderView - auto syncFrustumCulling = [=] () { - RenderView *rv = renderViewJob->renderView(); - - // Update matrices now that all transforms have been updated - rv->updateMatrices(); - - // Frustum culling - frustumCulling->setViewProjection(rv->viewProjectionMatrix()); - }; - - // Copy shared ptr -> this is called after filtering / culling / parameter setting has been performed - auto syncForRenderCommandBuilding = [=] () { - // Set the result of previous job computations - // for final RenderCommand building - RenderView *rv = renderViewJob->renderView(); - - if (!rv->noDraw()) { - // Set the light sources - rv->setLightSources(std::move(lightGatherer->lights())); - - // Remove all entities from the compute and renderable vectors that aren't in the filtered layer vector - const QVector<Entity *> filteredEntities = filterEntityByLayer->filteredEntities(); - - // Note: this could further be improved if needed - // Set the renderable and computable entities - if (!rv->isCompute()) { - QVector<Entity *> renderableEntities = std::move(renderableEntityFilterer->filteredEntities()); - - for (auto i = renderableEntities.size() - 1; i >= 0; --i) { - if (!filteredEntities.contains(renderableEntities.at(i))) - renderableEntities.removeAt(i); - } - - if (rv->frustumCulling()) { - const QVector<Entity *> visibleEntities = frustumCulling->visibleEntities(); - for (auto i = renderableEntities.size() - 1; i >= 0; --i) { - if (!visibleEntities.contains(renderableEntities.at(i))) - renderableEntities.removeAt(i); - } - } - // Split among the number of command builders - const int packetSize = renderableEntities.size() / optimalParallelJobCount; - for (auto i = 0; i < optimalParallelJobCount; ++i) { - const RenderViewBuilderJobPtr renderViewCommandBuilder = renderViewCommandBuilders.at(i); - if (i == optimalParallelJobCount - 1) - renderViewCommandBuilder->setRenderables(renderableEntities.mid(i * packetSize, packetSize + renderableEntities.size() % optimalParallelJobCount)); - else - renderViewCommandBuilder->setRenderables(renderableEntities.mid(i * packetSize, packetSize)); - } - - } else { - QVector<Entity *> computableEntities = std::move(computeEntityFilterer->filteredEntities()); - for (auto i = computableEntities.size() - 1; i >= 0; --i) { - if (!filteredEntities.contains(computableEntities.at(i))) - computableEntities.removeAt(i); - } - // Split among the number of command builders - const int packetSize = computableEntities.size() / optimalParallelJobCount; - for (auto i = 0; i < optimalParallelJobCount; ++i) { - const RenderViewBuilderJobPtr renderViewCommandBuilder = renderViewCommandBuilders.at(i); - if (i == optimalParallelJobCount - 1) - renderViewCommandBuilder->setRenderables(computableEntities.mid(i * packetSize, packetSize + computableEntities.size() % optimalParallelJobCount)); - else - renderViewCommandBuilder->setRenderables(computableEntities.mid(i * packetSize, packetSize)); - } - } - - // Reduction - QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> params; - for (const auto materialGatherer : qAsConst(materialGatherers)) - params.unite(materialGatherer->materialToPassAndParameter()); - // Set all required data on the RenderView for final processing - rv->setMaterialParameterTable(std::move(params)); - } - }; - - // Called after each RenderViewBuilder has built its RenderCommands - auto syncRenderViewCommandBuilders = [=] () { - // Append all the commands and sort them - RenderView *rv = renderViewJob->renderView(); - - int totalCommandCount = 0; - for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders)) - totalCommandCount += renderViewCommandBuilder->commands().size(); - - QVector<RenderCommand *> commands; - commands.reserve(totalCommandCount); - - // Reduction - for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders)) - commands += std::move(renderViewCommandBuilder->commands()); - rv->setCommands(commands); - - // Sort the commands - rv->sort(); - - // Enqueue our fully populated RenderView with the RenderThread - renderer->enqueueRenderView(rv, currentRenderViewIndex); - }; - - auto setClearBufferDrawIndex = [=] () { - RenderView *rv = renderViewJob->renderView(); - QVector<ClearBufferInfo> &clearBuffersInfo = rv->specificClearColorBufferInfo(); - const AttachmentPack &attachmentPack = rv->attachmentPack(); - for (ClearBufferInfo &clearBufferInfo : clearBuffersInfo) - clearBufferInfo.drawBufferIndex = attachmentPack.getDrawBufferIndex(clearBufferInfo.attchmentPoint); - }; - - auto syncRenderViewCommandBuildingJob = GenericLambdaJobPtr<decltype(syncForRenderCommandBuilding)>::create(syncForRenderCommandBuilding); - auto syncRenderViewInitializationJob = GenericLambdaJobPtr<decltype(syncRenderViewInitialization)>::create(syncRenderViewInitialization); - auto syncRenderViewCommandBuildersJob = GenericLambdaJobPtr<decltype(syncRenderViewCommandBuilders)>::create(syncRenderViewCommandBuilders); - auto syncFrustumCullingJob = GenericLambdaJobPtr<decltype(syncFrustumCulling)>::create(syncFrustumCulling); - auto setClearBufferDrawIndexJob = GenericLambdaJobPtr<decltype(setClearBufferDrawIndex)>::create(setClearBufferDrawIndex); - - // Set dependencies - syncFrustumCullingJob->addDependency(renderer->updateWorldTransformJob()); - syncFrustumCullingJob->addDependency(syncRenderViewInitializationJob); - - frustumCulling->addDependency(renderer->expandBoundingVolumeJob()); - frustumCulling->addDependency(syncFrustumCullingJob); - - setClearBufferDrawIndexJob->addDependency(syncRenderViewInitializationJob); - - syncRenderViewInitializationJob->addDependency(renderViewJob); - - filterEntityByLayer->addDependency(syncRenderViewInitializationJob); - - syncRenderViewCommandBuildingJob->addDependency(syncRenderViewInitializationJob); - for (const auto materialGatherer : qAsConst(materialGatherers)) { - materialGatherer->addDependency(syncRenderViewInitializationJob); - syncRenderViewCommandBuildingJob->addDependency(materialGatherer); - } - syncRenderViewCommandBuildingJob->addDependency(renderableEntityFilterer); - syncRenderViewCommandBuildingJob->addDependency(computeEntityFilterer); - syncRenderViewCommandBuildingJob->addDependency(filterEntityByLayer); - syncRenderViewCommandBuildingJob->addDependency(lightGatherer); - syncRenderViewCommandBuildingJob->addDependency(frustumCulling); - - for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders)) { - renderViewCommandBuilder->addDependency(syncRenderViewCommandBuildingJob); - syncRenderViewCommandBuildersJob->addDependency(renderViewCommandBuilder); - } - renderer->frameCleanupJob()->addDependency(syncRenderViewCommandBuildersJob); - renderer->frameCleanupJob()->addDependency(setClearBufferDrawIndexJob); - - // Add jobs - m_jobs->push_back(renderViewJob); - m_jobs->push_back(filterEntityByLayer); - m_jobs->push_back(renderableEntityFilterer); - m_jobs->push_back(computeEntityFilterer); - m_jobs->push_back(syncRenderViewInitializationJob); - m_jobs->push_back(syncRenderViewCommandBuildingJob); - m_jobs->push_back(frustumCulling); - m_jobs->push_back(lightGatherer); - m_jobs->push_back(syncRenderViewCommandBuildersJob); - m_jobs->push_back(syncFrustumCullingJob); - m_jobs->push_back(setClearBufferDrawIndexJob); - - for (const auto materialGatherer : qAsConst(materialGatherers)) - m_jobs->push_back(materialGatherer); - - for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders)) - m_jobs->push_back(renderViewCommandBuilder); - + RenderViewBuilder builder(node, m_renderviewIndex++, m_renderer); + m_jobs->append(builder.buildJobHierachy()); } } diff --git a/src/render/framegraph/qclearbuffers.h b/src/render/framegraph/qclearbuffers.h index d45af9ce0..91828c222 100644 --- a/src/render/framegraph/qclearbuffers.h +++ b/src/render/framegraph/qclearbuffers.h @@ -74,7 +74,7 @@ public: ColorDepthStencilBuffer = ColorBuffer | DepthStencilBuffer, AllBuffers = 0xFFFFFFFF }; - Q_ENUM(BufferType) + Q_ENUM(BufferType) // LCOV_EXCL_LINE Q_DECLARE_FLAGS(BufferTypeFlags, BufferType) BufferType buffers() const; diff --git a/src/render/framegraph/qnodraw.cpp b/src/render/framegraph/qnodraw.cpp index 21634d1cb..46756557e 100644 --- a/src/render/framegraph/qnodraw.cpp +++ b/src/render/framegraph/qnodraw.cpp @@ -44,19 +44,42 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { /*! - * \class Qt3DRender::QNoDraw - * \inmodule Qt3DRender - * - * \brief When a QNoDraw node is present in a FrameGraph branch, this - * prevents the renderer from rendering any primitive. - * - * QNoDraw should be used when the FrameGraph needs to set up some render - * states or clear some buffers without requiring any mesh to be drawn. It has - * the same effect as having a Qt3DRender::QRenderPassFilter that matches none of - * available Qt3DRender::QRenderPass instances of the scene without the overhead cost - * of actually performing the filtering. - * - * \since 5.5 + \class Qt3DRender::QNoDraw + \inmodule Qt3DRender + + \brief When a Qt3DRender::QNoDraw node is present in a FrameGraph branch, this + prevents the renderer from rendering any primitive. + + Qt3DRender::QNoDraw should be used when the FrameGraph needs to set up some render + states or clear some buffers without requiring any mesh to be drawn. It has + the same effect as having a Qt3DRender::QRenderPassFilter that matches none of + available Qt3DRender::QRenderPass instances of the scene without the overhead cost + of actually performing the filtering. + + When disabled, a Qt3DRender::QNoDraw node won't prevent the scene from + being rendered. Toggling the enabled property is therefore a way to make a + Qt3DRender::QNoDraw active or inactive. + + Qt3DRender::QNoDraw is usually used as a child of a + Qt3DRendeR::QClearBuffers node to prevent from drawing the scene when there + are multiple render passes. + + \code + Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); + Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(viewport); + + Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers(cameraSelector); + clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthBuffer); + + Qt3DRender::QNoDraw *noDraw = new Qt3DRender::QNoDraw(clearBuffers); + + Qt3DRender::QRenderPassFilter *mainPass = new Qt3DRender::QRenderPassFilter(cameraSelector); + .... + Qt3DRender::QRenderPassFilter *previewPass = new Qt3DRender::QRenderPassFilter(cameraSelector); + .... + \endcode + + \since 5.5 */ /*! @@ -66,7 +89,39 @@ namespace Qt3DRender { \inqmlmodule Qt3D.Render \since 5.5 \brief When a NoDraw node is present in a FrameGraph branch, this - * prevents the renderer from rendering any primitive. + prevents the renderer from rendering any primitive. + + NoDraw should be used when the FrameGraph needs to set up some render + states or clear some buffers without requiring any mesh to be drawn. It has + the same effect as having a Qt3DRender::QRenderPassFilter that matches none + of available Qt3DRender::QRenderPass instances of the scene without the + overhead cost of actually performing the filtering. + + When disabled, a NoDraw node won't prevent the scene from being rendered. + Toggling the enabled property is therefore a way to make a NoDraw active or + inactive. + + NoDraw is usually used as a child of a ClearBuffers node to prevent from + drawing the scene when there are multiple render passes. + + \code + + Viewport { + CameraSelector { + ClearBuffers { + buffers: ClearBuffers.ColorDepthBuffer + NoDraw { } // Prevents from drawing anything + } + RenderPassFilter { + ... + } + RenderPassFilter { + ... + } + } + } + + \endcode */ /*! diff --git a/src/render/framegraph/qrendercapture.cpp b/src/render/framegraph/qrendercapture.cpp new file mode 100644 index 000000000..c4a42ff8a --- /dev/null +++ b/src/render/framegraph/qrendercapture.cpp @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <Qt3DRender/qrendercapture.h> +#include <Qt3DRender/private/qrendercapture_p.h> +#include <Qt3DCore/QSceneChange> +#include <Qt3DCore/QPropertyUpdatedChange> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +/*! + * \class Qt3DRender::QRenderCapture + * \inmodule Qt3DRender + * + * \brief Frame graph node for render capture + * + * The QRenderCapture is used to capture rendering into an image at any render stage. + * Capturing must be initiated by the user and one image is returned per capture request. + * User can issue multiple render capture requests simultaniously, but only one request + * is served per QRenderCapture instance per frame. + * + * \since 5.8 + */ + +/*! + * \qmltype RenderCapture + * \instantiates Qt3DRender::QRenderCapture + * \inherits FrameGraphNode + * \inqmlmodule Qt3D.Render + * \since 5.8 + * \brief Capture rendering + */ + +/*! + * \class Qt3DRender::QRenderCaptureReply + * \inmodule Qt3DRender + * + * \brief Receives the result of render capture request. + * + * An object, which receives the image from QRenderCapture::requestCapture. + * + * \since 5.8 + */ + +/*! + * \qmltype RenderCaptureReply + * \instantiates Qt3DRender::QRenderCaptureReply + * \inherits QObject + * \inqmlmodule Qt3D.Render + * \since 5.8 + * \brief Receives render capture result. + */ + +/*! + * \qmlproperty variant Qt3D.Render::RenderCaptureReply::image + * + * Holds the image, which was produced as a result of render capture. + */ + +/*! + * \qmlproperty int Qt3D.Render::RenderCaptureReply::captureId + * + * Holds the captureId, which was passed to the renderCapture. + */ + +/*! + * \qmlproperty bool Qt3D.Render::RenderCaptureReply::complete + * + * Holds the complete state of the render capture. + */ + +/*! + * \qmlmethod void Qt3D.Render::RenderCaptureReply::saveToFile(fileName) + * + * Saves the render capture result as an image to \a fileName. + */ + +/*! + * \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture(int captureId) + * + * Used to request render capture. User can specify a \a captureId to identify + * the request. The requestId does not have to be unique. Only one render capture result + * is produced per requestCapture call even if the frame graph has multiple leaf nodes. + * The function returns a QRenderCaptureReply object, which receives the captured image + * when it is done. The user is reponsible for deallocating the returned object. + */ + +/*! + * \internal + */ +QRenderCaptureReplyPrivate::QRenderCaptureReplyPrivate() + : QObjectPrivate() + , m_captureId(0) + , m_complete(false) +{ + +} + +/*! + * The constructor creates an instance with the specified \a parent. + */ +QRenderCaptureReply::QRenderCaptureReply(QObject *parent) + : QObject(* new QRenderCaptureReplyPrivate, parent) +{ + +} + +/*! + * \property QRenderCaptureReply::image + * + * Holds the image, which was produced as a result of render capture. + */ +QImage QRenderCaptureReply::image() const +{ + Q_D(const QRenderCaptureReply); + return d->m_image; +} + +/*! + * \property QRenderCaptureReply::captureId + * + * Holds the captureId, which was passed to the renderCapture. + */ +int QRenderCaptureReply::captureId() const +{ + Q_D(const QRenderCaptureReply); + return d->m_captureId; +} + +/*! + * \property QRenderCaptureReply::complete + * + * Holds the complete state of the render capture. + */ +bool QRenderCaptureReply::isComplete() const +{ + Q_D(const QRenderCaptureReply); + return d->m_complete; +} + +/*! + * Saves the render capture result as an image to \a fileName. + */ +void QRenderCaptureReply::saveToFile(const QString &fileName) const +{ + Q_D(const QRenderCaptureReply); + if (d->m_complete) + d->m_image.save(fileName); +} + +/*! + * \internal + */ +QRenderCapturePrivate::QRenderCapturePrivate() + : QFrameGraphNodePrivate() +{ +} + +/*! + * \internal + */ +QRenderCaptureReply *QRenderCapturePrivate::createReply(int captureId) +{ + QRenderCaptureReply *reply = new QRenderCaptureReply(); + reply->d_func()->m_captureId = captureId; + m_waitingReplies.push_back(reply); + return reply; +} + +/*! + * \internal + */ +QRenderCaptureReply *QRenderCapturePrivate::takeReply(int captureId) +{ + QRenderCaptureReply *reply = nullptr; + for (int i = 0; i < m_waitingReplies.size(); ++i) { + if (m_waitingReplies[i]->captureId() == captureId) { + reply = m_waitingReplies[i]; + m_waitingReplies.remove(i); + break; + } + } + return reply; +} + +/*! + * \internal + */ +void QRenderCapturePrivate::setImage(QRenderCaptureReply *reply, const QImage &image) +{ + reply->d_func()->m_complete = true; + reply->d_func()->m_image = image; +} + +/*! + * The constructor creates an instance with the specified \a parent. + */ +QRenderCapture::QRenderCapture(Qt3DCore::QNode *parent) + : QFrameGraphNode(*new QRenderCapturePrivate, parent) +{ +} + +/*! + * Used to request render capture. User can specify a \a captureId to identify + * the request. The requestId does not have to be unique. Only one render capture result + * is produced per requestCapture call even if the frame graph has multiple leaf nodes. + * The function returns a QRenderCaptureReply object, which receives the captured image + * when it is done. The user is reponsible for deallocating the returned object. + */ +QRenderCaptureReply *QRenderCapture::requestCapture(int captureId) +{ + Q_D(QRenderCapture); + QRenderCaptureReply *reply = d->createReply(captureId); + + Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(id())); + change->setPropertyName(QByteArrayLiteral("renderCaptureRequest")); + change->setValue(QVariant::fromValue(captureId)); + d->notifyObservers(change); + + return reply; +} + +/*! + * \internal + */ +void QRenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) +{ + Q_D(QRenderCapture); + Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change); + if (propertyChange->type() == Qt3DCore::PropertyUpdated) { + if (propertyChange->propertyName() == QByteArrayLiteral("renderCaptureData")) { + RenderCaptureDataPtr data = propertyChange->value().value<RenderCaptureDataPtr>(); + QRenderCaptureReply *reply = d->takeReply(data.data()->captureId); + if (reply) { + d->setImage(reply, data.data()->image); + emit reply->completeChanged(true); + } + } + } +} + +/*! + * \internal + */ +Qt3DCore::QNodeCreatedChangeBasePtr QRenderCapture::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QRenderCaptureInitData>::create(this); + QRenderCaptureInitData &data = creationChange->data; + data.captureId = 0; + return creationChange; +} + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/framegraph/qrendercapture.h b/src/render/framegraph/qrendercapture.h new file mode 100644 index 000000000..f3be273f3 --- /dev/null +++ b/src/render/framegraph/qrendercapture.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRENDERCAPTURE_H +#define QRENDERCAPTURE_H + +#include <Qt3DRender/QFrameGraphNode> +#include <QImage> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QRenderCapturePrivate; +class QRenderCaptureReplyPrivate; + +class QT3DRENDERSHARED_EXPORT QRenderCaptureReply : public QObject +{ + Q_OBJECT + Q_PROPERTY(QImage image READ image CONSTANT) + Q_PROPERTY(int captureId READ captureId CONSTANT) + Q_PROPERTY(bool complete READ isComplete NOTIFY completeChanged) + +public: + + QImage image() const; + int captureId() const; + bool isComplete() const; + + Q_INVOKABLE void saveToFile(const QString &fileName) const; + +Q_SIGNALS: + void completeChanged(bool isComplete); + +private: + Q_DECLARE_PRIVATE(QRenderCaptureReply) + + QRenderCaptureReply(QObject *parent = nullptr); + + friend class QRenderCapturePrivate; +}; + +class QT3DRENDERSHARED_EXPORT QRenderCapture : public QFrameGraphNode +{ + Q_OBJECT +public: + explicit QRenderCapture(Qt3DCore::QNode *parent = nullptr); + + Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture(int captureId); + +protected: + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; + +private: + Q_DECLARE_PRIVATE(QRenderCapture) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QRENDERCAPTURE_H diff --git a/src/render/framegraph/qrendercapture_p.h b/src/render/framegraph/qrendercapture_p.h new file mode 100644 index 000000000..0d7c2d3af --- /dev/null +++ b/src/render/framegraph/qrendercapture_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRENDERCAPTURE_P_H +#define QRENDERCAPTURE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DRender/qrendercapture.h> +#include <Qt3DRender/private/qframegraphnode_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QRenderCapturePrivate : public QFrameGraphNodePrivate +{ +public: + QRenderCapturePrivate(); + QVector<QRenderCaptureReply *> m_waitingReplies; + + QRenderCaptureReply *createReply(int captureId); + QRenderCaptureReply *takeReply(int captureId); + void setImage(QRenderCaptureReply *reply, const QImage &image); + + Q_DECLARE_PUBLIC(QRenderCapture) +}; + +class QRenderCaptureReplyPrivate : public QObjectPrivate +{ +public: + QRenderCaptureReplyPrivate(); + + QImage m_image; + int m_captureId; + bool m_complete; + + Q_DECLARE_PUBLIC(QRenderCaptureReply) +}; + +// used by initializeFromPeer +struct QRenderCaptureInitData +{ + int captureId; +}; + +// used by backend to send render capture to frontend +struct RenderCaptureData +{ + QImage image; + int captureId; +}; + +typedef QSharedPointer<RenderCaptureData> RenderCaptureDataPtr; + +} // Qt3DRender + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Qt3DRender::RenderCaptureDataPtr) // LCOV_EXCL_LINE + +#endif // QRENDERCAPTURE_P_H diff --git a/src/render/framegraph/qrendersurfaceselector.cpp b/src/render/framegraph/qrendersurfaceselector.cpp index 27d06e264..2de878933 100644 --- a/src/render/framegraph/qrendersurfaceselector.cpp +++ b/src/render/framegraph/qrendersurfaceselector.cpp @@ -216,7 +216,6 @@ void QRenderSurfaceSelector::setSurface(QObject *surfaceObject) QWindow *window = qobject_cast<QWindow *>(surfaceObject); if (window) { surface = static_cast<QSurface *>(window); - setSurfacePixelRatio(window->devicePixelRatio()); } else { QOffscreenSurface *offscreen = qobject_cast<QOffscreenSurface *>(surfaceObject); if (offscreen) @@ -269,10 +268,10 @@ void QRenderSurfaceSelector::setSurface(QObject *surfaceObject) } }); d->m_screenConn = QObject::connect(window, &QWindow::screenChanged, [=] (QScreen *screen) { - if (screen && surfacePixelRatio() != screen->devicePixelRatio()) { - setSurfacePixelRatio(screen->devicePixelRatio()); - } + if (screen && surfacePixelRatio() != screen->devicePixelRatio()) + setSurfacePixelRatio(screen->devicePixelRatio()); }); + setSurfacePixelRatio(window->devicePixelRatio()); } break; @@ -302,6 +301,8 @@ QSize QRenderSurfaceSelector::externalRenderTargetSize() const void QRenderSurfaceSelector::setSurfacePixelRatio(float ratio) { Q_D(QRenderSurfaceSelector); + if (d->m_surfacePixelRatio == ratio) + return; d->m_surfacePixelRatio = ratio; emit surfacePixelRatioChanged(ratio); } @@ -318,8 +319,10 @@ float QRenderSurfaceSelector::surfacePixelRatio() const void QRenderSurfaceSelector::setExternalRenderTargetSize(const QSize &size) { Q_D(QRenderSurfaceSelector); - d->setExternalRenderTargetSize(size); - emit externalRenderTargetSizeChanged(size); + if (size != d->m_externalRenderTargetSize) { + d->setExternalRenderTargetSize(size); + emit externalRenderTargetSizeChanged(size); + } } Qt3DCore::QNodeCreatedChangeBasePtr QRenderSurfaceSelector::createNodeCreationChange() const diff --git a/src/render/framegraph/qrendersurfaceselector.h b/src/render/framegraph/qrendersurfaceselector.h index ea8b93e8d..eae221800 100644 --- a/src/render/framegraph/qrendersurfaceselector.h +++ b/src/render/framegraph/qrendersurfaceselector.h @@ -57,7 +57,7 @@ class QT3DRENDERSHARED_EXPORT QRenderSurfaceSelector : public Qt3DRender::QFrame { Q_OBJECT Q_PROPERTY(QObject *surface READ surface WRITE setSurface NOTIFY surfaceChanged) - Q_PROPERTY(QSize externalRenderTargetSize READ externalRenderTargetSize NOTIFY externalRenderTargetSizeChanged) + Q_PROPERTY(QSize externalRenderTargetSize READ externalRenderTargetSize WRITE setExternalRenderTargetSize NOTIFY externalRenderTargetSizeChanged) Q_PROPERTY(float surfacePixelRatio READ surfacePixelRatio WRITE setSurfacePixelRatio NOTIFY surfacePixelRatioChanged) public: @@ -66,12 +66,12 @@ public: QObject *surface() const; QSize externalRenderTargetSize() const; - void setExternalRenderTargetSize(const QSize &size); float surfacePixelRatio() const; public Q_SLOTS: void setSurface(QObject *surfaceObject); void setSurfacePixelRatio(float ratio); + void setExternalRenderTargetSize(const QSize &size); Q_SIGNALS: void surfaceChanged(QObject *surface); diff --git a/src/render/framegraph/qrendertargetselector.h b/src/render/framegraph/qrendertargetselector.h index a92fe1335..68fbe2666 100644 --- a/src/render/framegraph/qrendertargetselector.h +++ b/src/render/framegraph/qrendertargetselector.h @@ -83,6 +83,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(QVector<Qt3DRender::QRenderTargetOutput::AttachmentPoint>) +Q_DECLARE_METATYPE(QVector<Qt3DRender::QRenderTargetOutput::AttachmentPoint>) // LCOV_EXCL_LINE #endif // QT3DRENDER_QRENDERTARGETSELECTOR_H diff --git a/src/render/framegraph/qsortcriterion.h b/src/render/framegraph/qsortcriterion.h index bf2821550..230f111f9 100644 --- a/src/render/framegraph/qsortcriterion.h +++ b/src/render/framegraph/qsortcriterion.h @@ -61,7 +61,7 @@ public: BackToFront = (1 << 1), Material = (1 << 2) }; - Q_ENUM(SortType) + Q_ENUM(SortType) // LCOV_EXCL_LINE SortType sort() const; diff --git a/src/render/framegraph/qsortpolicy.h b/src/render/framegraph/qsortpolicy.h index 010fa461b..2d96bdbd6 100644 --- a/src/render/framegraph/qsortpolicy.h +++ b/src/render/framegraph/qsortpolicy.h @@ -61,7 +61,7 @@ public: BackToFront = (1 << 1), Material = (1 << 2) }; - Q_ENUM(SortType) + Q_ENUM(SortType) // LCOV_EXCL_LINE QVector<SortType> sortTypes() const; QVector<int> sortTypesInt() const; diff --git a/src/render/framegraph/rendercapture.cpp b/src/render/framegraph/rendercapture.cpp new file mode 100644 index 000000000..f123fd74c --- /dev/null +++ b/src/render/framegraph/rendercapture.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <Qt3DRender/private/qrendercapture_p.h> +#include <Qt3DRender/private/rendercapture_p.h> +#include <Qt3DCore/qpropertyupdatedchange.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +RenderCapture::RenderCapture() + : FrameGraphNode(FrameGraphNode::RenderCapture, QBackendNode::ReadWrite) +{ + +} + +void RenderCapture::requestCapture(int captureId) +{ + QMutexLocker lock(&m_mutex); + m_requestedCaptures.push_back(captureId); +} + +bool RenderCapture::wasCaptureRequested() const +{ + return m_requestedCaptures.size() > 0 && isEnabled(); +} + +void RenderCapture::acknowledgeCaptureRequest() +{ + m_acknowledgedCaptures.push_back(m_requestedCaptures.takeFirst()); +} + +void RenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e); + if (propertyChange->propertyName() == QByteArrayLiteral("renderCaptureRequest")) { + requestCapture(propertyChange->value().toInt()); + } + } + markDirty(AbstractRenderer::AllDirty); + FrameGraphNode::sceneChangeEvent(e); +} + +// called by render thread +void RenderCapture::addRenderCapture(const QImage &image) +{ + QMutexLocker lock(&m_mutex); + auto data = RenderCaptureDataPtr::create(); + data.data()->captureId = m_acknowledgedCaptures.takeFirst(); + data.data()->image = image; + m_renderCaptureData.push_back(data); +} + +// called by send render capture job thread +void RenderCapture::sendRenderCaptures() +{ + QMutexLocker lock(&m_mutex); + + for (const RenderCaptureDataPtr data : m_renderCaptureData) { + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("renderCaptureData"); + e->setValue(QVariant::fromValue(data)); + notifyObservers(e); + } + m_renderCaptureData.clear(); +} + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/framegraph/rendercapture_p.h b/src/render/framegraph/rendercapture_p.h new file mode 100644 index 000000000..e2b87474c --- /dev/null +++ b/src/render/framegraph/rendercapture_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERCAPTURE_P_H +#define RENDERCAPTURE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DRender/private/qrendercapture_p.h> +#include <Qt3DRender/private/framegraphnode_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class Q_AUTOTEST_EXPORT RenderCapture : public FrameGraphNode +{ +public: + RenderCapture(); + + void requestCapture(int captureId); + bool wasCaptureRequested() const; + void acknowledgeCaptureRequest(); + void addRenderCapture(const QImage &image); + void sendRenderCaptures(); + +protected: + virtual void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e); + +private: + + QVector<int> m_requestedCaptures; + QVector<int> m_acknowledgedCaptures; + QVector<RenderCaptureDataPtr> m_renderCaptureData; + QMutex m_mutex; +}; + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // RENDERCAPTURE_P_H diff --git a/src/render/frontend/qcamera.h b/src/render/frontend/qcamera.h index 9c2997ba0..f5bd49fa2 100644 --- a/src/render/frontend/qcamera.h +++ b/src/render/frontend/qcamera.h @@ -87,7 +87,7 @@ public: TranslateViewCenter, DontTranslateViewCenter }; - Q_ENUM(CameraTranslationOption) + Q_ENUM(CameraTranslationOption) // LCOV_EXCL_LINE QCameraLens *lens() const; Qt3DCore::QTransform *transform() const; diff --git a/src/render/frontend/qcameralens.h b/src/render/frontend/qcameralens.h index 6739369dc..ad414cada 100644 --- a/src/render/frontend/qcameralens.h +++ b/src/render/frontend/qcameralens.h @@ -77,7 +77,7 @@ public: FrustumProjection, CustomProjection }; - Q_ENUM(ProjectionType) + Q_ENUM(ProjectionType) // LCOV_EXCL_LINE ProjectionType projectionType() const; float nearPlane() const; diff --git a/src/render/frontend/qpickingsettings.cpp b/src/render/frontend/qpickingsettings.cpp index e1c403ba3..f4fd2c683 100644 --- a/src/render/frontend/qpickingsettings.cpp +++ b/src/render/frontend/qpickingsettings.cpp @@ -70,12 +70,15 @@ QPickingSettingsPrivate::QPickingSettingsPrivate() : Qt3DCore::QNodePrivate() , m_pickMethod(QPickingSettings::BoundingVolumePicking) , m_pickResultMode(QPickingSettings::NearestPick) + , m_faceOrientationPickingMode(QPickingSettings::FrontFace) { } QPickingSettings::QPickingSettings(Qt3DCore::QNode *parent) : Qt3DCore::QNode(*new QPickingSettingsPrivate, parent) { + // Block all notifications for this class as it should have been a QObject + blockNotifications(true); } /*! \internal */ @@ -102,6 +105,15 @@ QPickingSettings::PickResultMode QPickingSettings::pickResultMode() const } /*! + * \return the back facing picking flag + */ +QPickingSettings::FaceOrientationPickingMode QPickingSettings::faceOrientationPickingMode() const +{ + Q_D(const QPickingSettings); + return d->m_faceOrientationPickingMode; +} + +/*! * \enum Qt3DRender::QPickingSettings::PickMethod * * Specifies the picking method. @@ -176,6 +188,20 @@ void QPickingSettings::setPickResultMode(QPickingSettings::PickResultMode pickRe emit pickResultModeChanged(pickResultMode); } +/*! + * Sets whether back facing faces are picked or not + * \param faceOrientationPickingMode + */ +void QPickingSettings::setFaceOrientationPickingMode(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode) +{ + Q_D(QPickingSettings); + if (d->m_faceOrientationPickingMode == faceOrientationPickingMode) + return; + + d->m_faceOrientationPickingMode = faceOrientationPickingMode; + emit faceOrientationPickingModeChanged(faceOrientationPickingMode); +} + } // namespace Qt3Drender QT_END_NAMESPACE diff --git a/src/render/frontend/qpickingsettings.h b/src/render/frontend/qpickingsettings.h index a530a4b33..655bf952a 100644 --- a/src/render/frontend/qpickingsettings.h +++ b/src/render/frontend/qpickingsettings.h @@ -49,11 +49,14 @@ namespace Qt3DRender { class QPickingSettingsPrivate; +// TO DO: Qt 6 -> Make this a QObject + class QT3DRENDERSHARED_EXPORT QPickingSettings : public Qt3DCore::QNode { Q_OBJECT Q_PROPERTY(PickMethod pickMethod READ pickMethod WRITE setPickMethod NOTIFY pickMethodChanged) Q_PROPERTY(PickResultMode pickResultMode READ pickResultMode WRITE setPickResultMode NOTIFY pickResultModeChanged) + Q_PROPERTY(FaceOrientationPickingMode faceOrientationPickingMode READ faceOrientationPickingMode WRITE setFaceOrientationPickingMode NOTIFY faceOrientationPickingModeChanged) public: explicit QPickingSettings(Qt3DCore::QNode *parent = nullptr); @@ -63,24 +66,34 @@ public: BoundingVolumePicking, TrianglePicking }; - Q_ENUM(PickMethod) + Q_ENUM(PickMethod) // LCOV_EXCL_LINE enum PickResultMode { NearestPick, AllPicks }; - Q_ENUM(PickResultMode) + Q_ENUM(PickResultMode) // LCOV_EXCL_LINE + + enum FaceOrientationPickingMode { + FrontFace = 0x01, + BackFace = 0x02, + FrontAndBackFace = 0x03 + }; + Q_ENUM(FaceOrientationPickingMode) // LCOV_EXCL_LINE PickMethod pickMethod() const; PickResultMode pickResultMode() const; + FaceOrientationPickingMode faceOrientationPickingMode() const; public Q_SLOTS: void setPickMethod(PickMethod pickMethod); void setPickResultMode(PickResultMode pickResultMode); + void setFaceOrientationPickingMode(FaceOrientationPickingMode faceOrientationPickingMode); Q_SIGNALS: void pickMethodChanged(QPickingSettings::PickMethod pickMethod); void pickResultModeChanged(QPickingSettings::PickResultMode pickResult); + void faceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode); protected: Q_DECLARE_PRIVATE(QPickingSettings) diff --git a/src/render/frontend/qpickingsettings_p.h b/src/render/frontend/qpickingsettings_p.h index 57c989606..039b6a435 100644 --- a/src/render/frontend/qpickingsettings_p.h +++ b/src/render/frontend/qpickingsettings_p.h @@ -65,6 +65,7 @@ public: QPickingSettings::PickMethod m_pickMethod; QPickingSettings::PickResultMode m_pickResultMode; + QPickingSettings::FaceOrientationPickingMode m_faceOrientationPickingMode; }; } // namespace Qt3Drender diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 00dd9c327..1952a55c2 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -76,7 +76,7 @@ #include <Qt3DRender/qcomputecommand.h> #include <Qt3DRender/qrendersurfaceselector.h> #include <Qt3DRender/qrendersettings.h> - +#include <Qt3DRender/qrendercapture.h> #include <Qt3DRender/private/cameraselectornode_p.h> #include <Qt3DRender/private/layerfilternode_p.h> #include <Qt3DRender/private/filterkey_p.h> @@ -119,6 +119,7 @@ #include <Qt3DRender/private/rendersurfaceselector_p.h> #include <Qt3DRender/private/rendersettings_p.h> #include <Qt3DRender/private/backendnode_p.h> +#include <Qt3DRender/private/rendercapture_p.h> #include <Qt3DCore/qentity.h> #include <Qt3DCore/qtransform.h> @@ -195,8 +196,8 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType<QGeometryRenderer>(QSharedPointer<Render::GeometryRendererFunctor>::create(m_renderer, m_nodeManagers->geometryRendererManager())); // Textures - q->registerBackendType<QAbstractTexture>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager(), m_nodeManagers->textureDataManager())); - q->registerBackendType<QAbstractTextureImage>(QSharedPointer<Render::TextureImageFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager(), m_nodeManagers->textureDataManager())); + q->registerBackendType<QAbstractTexture>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager())); + q->registerBackendType<QAbstractTextureImage>(QSharedPointer<Render::TextureImageFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager())); // Material system q->registerBackendType<QEffect>(QSharedPointer<Render::NodeFunctor<Render::Effect, Render::EffectManager> >::create(m_renderer, m_nodeManagers->effectManager())); @@ -207,7 +208,7 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType<QRenderPass>(QSharedPointer<Render::NodeFunctor<Render::RenderPass, Render::RenderPassManager> >::create(m_renderer, m_nodeManagers->renderPassManager())); q->registerBackendType<QShaderData>(QSharedPointer<Render::RenderShaderDataFunctor>::create(m_renderer, m_nodeManagers)); q->registerBackendType<QShaderProgram>(QSharedPointer<Render::NodeFunctor<Render::Shader, Render::ShaderManager> >::create(m_renderer, m_nodeManagers->shaderManager())); - q->registerBackendType<QTechnique>(QSharedPointer<Render::NodeFunctor<Render::Technique, Render::TechniqueManager> >::create(m_renderer, m_nodeManagers->techniqueManager())); + q->registerBackendType<QTechnique>(QSharedPointer<Render::TechniqueFunctor>::create(m_renderer, m_nodeManagers)); // Framegraph q->registerBackendType<QFrameGraphNode>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::FrameGraphNode, QFrameGraphNode> >::create(m_renderer, m_nodeManagers->frameGraphManager())); @@ -224,6 +225,7 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType<QSortPolicy>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::SortPolicy, QSortPolicy> >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType<QTechniqueFilter>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::TechniqueFilter, QTechniqueFilter> >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType<QViewport>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ViewportNode, QViewport> >::create(m_renderer, m_nodeManagers->frameGraphManager())); + q->registerBackendType<QRenderCapture>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderCapture, QRenderCapture> >::create(m_renderer, m_nodeManagers->frameGraphManager())); // Picking q->registerBackendType<QObjectPicker>(QSharedPointer<Render::NodeFunctor<Render::ObjectPicker, Render::ObjectPickerManager> >::create(m_renderer, m_nodeManagers->objectPickerManager())); @@ -279,6 +281,7 @@ void QRenderAspectPrivate::unregisterBackendTypes() unregisterBackendType<QSortPolicy>(); unregisterBackendType<QTechniqueFilter>(); unregisterBackendType<QViewport>(); + unregisterBackendType<QRenderCapture>(); // Picking unregisterBackendType<QObjectPicker>(); @@ -367,9 +370,16 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) Render::NodeManagers *manager = d->m_renderer->nodeManagers(); - const QVector<QNodeId> texturesPending = std::move(manager->textureDataManager()->texturesPending()); - for (const QNodeId textureId : texturesPending) { - auto loadTextureJob = Render::LoadTextureDataJobPtr::create(textureId); + // Launch texture generator jobs + const QVector<QTextureImageDataGeneratorPtr> pendingImgGen = manager->textureImageDataManager()->pendingGenerators(); + for (const QTextureImageDataGeneratorPtr &imgGen : pendingImgGen) { + auto loadTextureJob = Render::LoadTextureDataJobPtr::create(imgGen); + loadTextureJob->setNodeManagers(manager); + jobs.append(loadTextureJob); + } + const QVector<QTextureGeneratorPtr> pendingTexGen = manager->textureDataManager()->pendingGenerators(); + for (const QTextureGeneratorPtr &texGen : pendingTexGen) { + auto loadTextureJob = Render::LoadTextureDataJobPtr::create(texGen); loadTextureJob->setNodeManagers(manager); jobs.append(loadTextureJob); } diff --git a/src/render/frontend/qrendersettings.cpp b/src/render/frontend/qrendersettings.cpp index d9ce3c3c9..aa10a7ef3 100644 --- a/src/render/frontend/qrendersettings.cpp +++ b/src/render/frontend/qrendersettings.cpp @@ -71,6 +71,14 @@ namespace Qt3DRender { \l{Qt 3D Render Framegraph}{FrameGraph}. */ +/*! + \enum QRenderSettings::RenderPolicy + + This enum type describes types of render policies available. + \value Always Always try to render (default) + \value OnDemand Only render when something changes +*/ + /*! \internal */ QRenderSettingsPrivate::QRenderSettingsPrivate() : Qt3DCore::QComponentPrivate() @@ -87,6 +95,8 @@ void QRenderSettingsPrivate::init() q, SLOT(_q_onPickingMethodChanged(QPickingSettings::PickMethod))); QObject::connect(&m_pickingSettings, SIGNAL(pickResultModeChanged(QPickingSettings::PickResultMode)), q, SLOT(_q_onPickResultModeChanged(QPickingSettings::PickResultMode))); + QObject::connect(&m_pickingSettings, SIGNAL(faceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode)), + q, SLOT(_q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode))); } /*! \internal */ @@ -101,6 +111,12 @@ void QRenderSettingsPrivate::_q_onPickResultModeChanged(QPickingSettings::PickRe notifyPropertyChange("pickResultMode", pickResultMode); } +/*! \internal */ +void QRenderSettingsPrivate::_q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode) +{ + notifyPropertyChange("faceOrientationPickingMode", faceOrientationPickingMode); +} + QRenderSettings::QRenderSettings(Qt3DCore::QNode *parent) : QRenderSettings(*new QRenderSettingsPrivate, parent) {} @@ -228,6 +244,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QRenderSettings::createNodeCreationChange() data.renderPolicy = d->m_renderPolicy; data.pickMethod = d->m_pickingSettings.pickMethod(); data.pickResultMode = d->m_pickingSettings.pickResultMode(); + data.faceOrientationPickingMode = d->m_pickingSettings.faceOrientationPickingMode(); return creationChange; } diff --git a/src/render/frontend/qrendersettings.h b/src/render/frontend/qrendersettings.h index 4a0d99383..71da7c562 100644 --- a/src/render/frontend/qrendersettings.h +++ b/src/render/frontend/qrendersettings.h @@ -68,7 +68,7 @@ public: OnDemand, Always }; - Q_ENUM(RenderPolicy) + Q_ENUM(RenderPolicy) // LCOV_EXCL_LINE QPickingSettings* pickingSettings(); QFrameGraphNode *activeFrameGraph() const; @@ -89,6 +89,7 @@ protected: private: Q_PRIVATE_SLOT(d_func(), void _q_onPickingMethodChanged(QPickingSettings::PickMethod)) Q_PRIVATE_SLOT(d_func(), void _q_onPickResultModeChanged(QPickingSettings::PickResultMode)) + Q_PRIVATE_SLOT(d_func(), void _q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode)) Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; }; diff --git a/src/render/frontend/qrendersettings_p.h b/src/render/frontend/qrendersettings_p.h index efbd7f8f1..f05124296 100644 --- a/src/render/frontend/qrendersettings_p.h +++ b/src/render/frontend/qrendersettings_p.h @@ -72,6 +72,7 @@ public: void _q_onPickingMethodChanged(QPickingSettings::PickMethod pickMethod); void _q_onPickResultModeChanged(QPickingSettings::PickResultMode pickResultMode); + void _q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode); Q_DECLARE_PUBLIC(QRenderSettings) }; @@ -82,6 +83,7 @@ struct QRenderSettingsData QRenderSettings::RenderPolicy renderPolicy; QPickingSettings::PickMethod pickMethod; QPickingSettings::PickResultMode pickResultMode; + QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode; }; } // namespace Qt3Drender diff --git a/src/render/frontend/qrendertargetoutput.h b/src/render/frontend/qrendertargetoutput.h index 1f78dd279..f2feea536 100644 --- a/src/render/frontend/qrendertargetoutput.h +++ b/src/render/frontend/qrendertargetoutput.h @@ -58,7 +58,7 @@ class QT3DRENDERSHARED_EXPORT QRenderTargetOutput : public Qt3DCore::QNode Q_PROPERTY(QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged) Q_PROPERTY(int mipLevel READ mipLevel WRITE setMipLevel NOTIFY mipLevelChanged) Q_PROPERTY(int layer READ layer WRITE setLayer NOTIFY layerChanged) - Q_PROPERTY(QAbstractTexture::CubeMapFace face READ face WRITE setFace NOTIFY faceChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture::CubeMapFace face READ face WRITE setFace NOTIFY faceChanged) public: enum AttachmentPoint { @@ -82,7 +82,7 @@ public: Stencil, DepthStencil }; - Q_ENUM(AttachmentPoint) + Q_ENUM(AttachmentPoint) // LCOV_EXCL_LINE explicit QRenderTargetOutput(Qt3DCore::QNode *parent = nullptr); ~QRenderTargetOutput(); @@ -119,6 +119,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QRenderTargetOutput::AttachmentPoint) +Q_DECLARE_METATYPE(Qt3DRender::QRenderTargetOutput::AttachmentPoint) // LCOV_EXCL_LINE #endif // QT3DRENDER_QRENDERTARGETOUTPUT_H diff --git a/src/render/frontend/sphere_p.h b/src/render/frontend/sphere_p.h index de93faa05..a30a12741 100644 --- a/src/render/frontend/sphere_p.h +++ b/src/render/frontend/sphere_p.h @@ -163,6 +163,6 @@ inline bool intersects(const Sphere &a, const Sphere &b) QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::Render::Sphere) +Q_DECLARE_METATYPE(Qt3DRender::Render::Sphere) // LCOV_EXCL_LINE #endif // QT3DRENDER_RENDER_SPHERE_H diff --git a/src/render/geometry/attribute.cpp b/src/render/geometry/attribute.cpp index 85c69cdb7..7e1ea79dd 100644 --- a/src/render/geometry/attribute.cpp +++ b/src/render/geometry/attribute.cpp @@ -53,7 +53,7 @@ namespace Render { Attribute::Attribute() : BackendNode(ReadOnly) , m_nameId(0) - , m_vertexDataType(QAttribute::Float) + , m_vertexBaseType(QAttribute::Float) , m_vertexSize(1) , m_count(0) , m_byteStride(0) @@ -70,7 +70,7 @@ Attribute::~Attribute() void Attribute::cleanup() { - m_vertexDataType = QAttribute::Float; + m_vertexBaseType = QAttribute::Float; m_vertexSize = 1; m_count = 0; m_byteStride = 0; @@ -90,8 +90,8 @@ void Attribute::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &ch m_bufferId = data.bufferId; m_name = data.name; m_nameId = StringToInt::lookupId(m_name); - m_vertexDataType = data.dataType; - m_vertexSize = data.dataSize; + m_vertexBaseType = data.vertexBaseType; + m_vertexSize = data.vertexSize; m_count = data.count; m_byteStride = data.byteStride; m_byteOffset = data.byteOffset; @@ -112,7 +112,7 @@ void Attribute::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) m_nameId = StringToInt::lookupId(m_name); m_attributeDirty = true; } else if (propertyName == QByteArrayLiteral("vertexBaseType")) { - m_vertexDataType = static_cast<QAttribute::VertexBaseType>(propertyChange->value().value<int>()); + m_vertexBaseType = static_cast<QAttribute::VertexBaseType>(propertyChange->value().value<int>()); m_attributeDirty = true; } else if (propertyName == QByteArrayLiteral("vertexSize")) { m_vertexSize = propertyChange->value().value<uint>(); diff --git a/src/render/geometry/attribute_p.h b/src/render/geometry/attribute_p.h index 6364639dd..1b639f42f 100644 --- a/src/render/geometry/attribute_p.h +++ b/src/render/geometry/attribute_p.h @@ -73,7 +73,7 @@ public: inline Qt3DCore::QNodeId bufferId() const { return m_bufferId; } inline QString name() const { return m_name; } inline int nameId() const { return m_nameId; } - inline QAttribute::VertexBaseType vertexBaseType() const { return m_vertexDataType; } + inline QAttribute::VertexBaseType vertexBaseType() const { return m_vertexBaseType; } inline uint vertexSize() const { return m_vertexSize; } inline uint count() const { return m_count; } inline uint byteStride() const { return m_byteStride; } @@ -89,7 +89,7 @@ private: Qt3DCore::QNodeId m_bufferId; QString m_name; int m_nameId; - QAttribute::VertexBaseType m_vertexDataType; + QAttribute::VertexBaseType m_vertexBaseType; uint m_vertexSize; uint m_count; uint m_byteStride; diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp index 8c897dd2b..aaae9825f 100644 --- a/src/render/geometry/buffer.cpp +++ b/src/render/geometry/buffer.cpp @@ -70,6 +70,7 @@ void Buffer::cleanup() m_type = QBuffer::VertexBuffer; m_usage = QBuffer::StaticDraw; m_data.clear(); + m_bufferUpdates.clear(); m_functor.reset(); m_bufferDirty = false; m_syncData = false; @@ -120,6 +121,10 @@ void Buffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) QByteArray newData = propertyChange->value().value<QByteArray>(); m_bufferDirty |= m_data != newData; m_data = newData; + } else if (propertyName == QByteArrayLiteral("updateData")) { + Qt3DRender::QBufferUpdate updateData = propertyChange->value().value<Qt3DRender::QBufferUpdate>(); + m_bufferUpdates.push_back(updateData); + m_bufferDirty = true; } else if (propertyName == QByteArrayLiteral("type")) { m_type = static_cast<QBuffer::BufferType>(propertyChange->value().value<int>()); m_bufferDirty = true; diff --git a/src/render/geometry/buffer_p.h b/src/render/geometry/buffer_p.h index d6bfe1d8f..d474c1720 100644 --- a/src/render/geometry/buffer_p.h +++ b/src/render/geometry/buffer_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <QtCore> #include <Qt3DRender/private/backendnode_p.h> #include <Qt3DRender/qbuffer.h> #include <Qt3DRender/qbufferdatagenerator.h> @@ -59,6 +60,8 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { +class QBufferUpdate; + namespace Render { class BufferManager; @@ -74,10 +77,10 @@ public: void setManager(BufferManager *manager); void executeFunctor(); - inline QBuffer::BufferType type() const { return m_type; } inline QBuffer::UsageType usage() const { return m_usage; } inline QByteArray data() const { return m_data; } + inline QVector<Qt3DRender::QBufferUpdate> &pendingBufferUpdates() { return m_bufferUpdates; } inline bool isDirty() const { return m_bufferDirty; } inline QBufferDataGeneratorPtr dataGenerator() const { return m_functor; } inline bool isSyncData() const { return m_syncData; } @@ -89,6 +92,7 @@ private: QBuffer::BufferType m_type; QBuffer::UsageType m_usage; QByteArray m_data; + QVector<Qt3DRender::QBufferUpdate> m_bufferUpdates; bool m_bufferDirty; bool m_syncData; QBufferDataGeneratorPtr m_functor; diff --git a/src/render/geometry/geometryrenderer.cpp b/src/render/geometry/geometryrenderer.cpp index 70266ac52..1efacdfe0 100644 --- a/src/render/geometry/geometryrenderer.cpp +++ b/src/render/geometry/geometryrenderer.cpp @@ -241,7 +241,7 @@ Qt3DCore::QBackendNode *GeometryRendererFunctor::get(Qt3DCore::QNodeId id) const void GeometryRendererFunctor::destroy(Qt3DCore::QNodeId id) const { - return m_manager->releaseResource(id); + m_manager->releaseResource(id); } } // namespace Render diff --git a/src/render/geometry/qattribute.cpp b/src/render/geometry/qattribute.cpp index 62d8717d0..12ceda18f 100644 --- a/src/render/geometry/qattribute.cpp +++ b/src/render/geometry/qattribute.cpp @@ -51,8 +51,8 @@ QAttributePrivate::QAttributePrivate() : QNodePrivate() , m_buffer(nullptr) , m_name() - , m_dataType(QAttribute::Float) - , m_dataSize(1) + , m_vertexBaseType(QAttribute::Float) + , m_vertexSize(1) , m_count(0) , m_byteStride(0) , m_byteOffset(0) @@ -86,7 +86,7 @@ QAttributePrivate::QAttributePrivate() * will ensure your geometry will be compatible with picking and the various * materials provided in the Qt3DExtras module. * - * \sa QBuffer. + * \sa QBuffer */ /*! @@ -138,8 +138,8 @@ QAttribute::QAttribute(QBuffer *buf, VertexBaseType type, uint dataSize, uint co setBuffer(buf); d->m_count = count; d->m_byteOffset = offset; - d->m_dataType = type; - d->m_dataSize = dataSize; + d->m_vertexBaseType = type; + d->m_vertexSize = dataSize; d->m_byteStride = stride; } @@ -156,8 +156,8 @@ QAttribute::QAttribute(QBuffer *buf, const QString &name, VertexBaseType type, u d->m_name = name; d->m_count = count; d->m_byteOffset = offset; - d->m_dataType = type; - d->m_dataSize = dataSize; + d->m_vertexBaseType = type; + d->m_vertexSize = dataSize; d->m_byteStride = stride; } @@ -197,7 +197,7 @@ QString QAttribute::name() const uint QAttribute::vertexSize() const { Q_D(const QAttribute); - return d->m_dataSize; + return d->m_vertexSize; } /*! @@ -208,7 +208,7 @@ uint QAttribute::vertexSize() const QAttribute::VertexBaseType QAttribute::vertexBaseType() const { Q_D(const QAttribute); - return d->m_dataType; + return d->m_vertexBaseType; } /*! @@ -301,27 +301,39 @@ void QAttribute::setName(const QString &name) emit nameChanged(name); } -void QAttribute::setDataType(VertexBaseType type) +void QAttribute::setVertexBaseType(VertexBaseType type) { Q_D(QAttribute); - if (d->m_dataType == type) + if (d->m_vertexBaseType == type) return; - d->m_dataType = type; + d->m_vertexBaseType = type; + emit vertexBaseTypeChanged(type); emit dataTypeChanged(type); } -void QAttribute::setDataSize(uint size) +void QAttribute::setVertexSize(uint size) { Q_D(QAttribute); - if (d->m_dataSize == size) + if (d->m_vertexSize == size) return; Q_ASSERT((size >= 1 && size <= 4) || (size == 9) || (size == 16)); - d->m_dataSize = size; + d->m_vertexSize = size; + emit vertexSizeChanged(size); emit dataSizeChanged(size); } +void QAttribute::setDataType(VertexBaseType type) +{ + setVertexBaseType(type); +} + +void QAttribute::setDataSize(uint size) +{ + setVertexSize(size); +} + void QAttribute::setCount(uint count) { Q_D(QAttribute); @@ -419,8 +431,8 @@ Qt3DCore::QNodeCreatedChangeBasePtr QAttribute::createNodeCreationChange() const Q_D(const QAttribute); data.bufferId = qIdForNode(d->m_buffer); data.name = d->m_name; - data.dataType = d->m_dataType; - data.dataSize = d->m_dataSize; + data.vertexBaseType = d->m_vertexBaseType; + data.vertexSize = d->m_vertexSize; data.count = d->m_count; data.byteStride = d->m_byteStride; data.byteOffset = d->m_byteOffset; diff --git a/src/render/geometry/qattribute.h b/src/render/geometry/qattribute.h index e6b525dc4..3e413c659 100644 --- a/src/render/geometry/qattribute.h +++ b/src/render/geometry/qattribute.h @@ -58,13 +58,18 @@ class QT3DRENDERSHARED_EXPORT QAttribute : public Qt3DCore::QNode Q_OBJECT Q_PROPERTY(Qt3DRender::QBuffer *buffer READ buffer WRITE setBuffer NOTIFY bufferChanged) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(VertexBaseType vertexBaseType READ vertexBaseType WRITE setDataType NOTIFY dataTypeChanged) - Q_PROPERTY(uint vertexSize READ vertexSize WRITE setDataSize NOTIFY dataSizeChanged) + Q_PROPERTY(VertexBaseType vertexBaseType READ vertexBaseType WRITE setVertexBaseType NOTIFY vertexBaseTypeChanged) + Q_PROPERTY(uint vertexSize READ vertexSize WRITE setVertexSize NOTIFY vertexSizeChanged) Q_PROPERTY(uint count READ count WRITE setCount NOTIFY countChanged) Q_PROPERTY(uint byteStride READ byteStride WRITE setByteStride NOTIFY byteStrideChanged) Q_PROPERTY(uint byteOffset READ byteOffset WRITE setByteOffset NOTIFY byteOffsetChanged) Q_PROPERTY(uint divisor READ divisor WRITE setDivisor NOTIFY divisorChanged) Q_PROPERTY(AttributeType attributeType READ attributeType WRITE setAttributeType NOTIFY attributeTypeChanged) + Q_PROPERTY(QString defaultPositionAttributeName READ defaultPositionAttributeName CONSTANT) + Q_PROPERTY(QString defaultNormalAttributeName READ defaultNormalAttributeName CONSTANT) + Q_PROPERTY(QString defaultColorAttributeName READ defaultColorAttributeName CONSTANT) + Q_PROPERTY(QString defaultTextureCoordinateAttributeName READ defaultTextureCoordinateAttributeName CONSTANT) + Q_PROPERTY(QString defaultTangentAttributeName READ defaultTangentAttributeName CONSTANT) public: enum AttributeType { @@ -72,7 +77,7 @@ public: IndexAttribute }; - Q_ENUM(AttributeType) + Q_ENUM(AttributeType) // LCOV_EXCL_LINE enum VertexBaseType { Byte = 0, @@ -85,7 +90,7 @@ public: Float, Double }; - Q_ENUM(VertexBaseType) + Q_ENUM(VertexBaseType) // LCOV_EXCL_LINE explicit QAttribute(QNode *parent = nullptr); explicit QAttribute(QBuffer *buf, VertexBaseType vertexBaseType, uint vertexSize, uint count, uint offset = 0, uint stride = 0, QNode *parent = nullptr); @@ -111,8 +116,10 @@ public: public Q_SLOTS: void setBuffer(QBuffer *buffer); void setName(const QString &name); - void setDataType(VertexBaseType type); - void setDataSize(uint size); + void setVertexBaseType(VertexBaseType type); + void setVertexSize(uint size); + QT_DEPRECATED void setDataType(VertexBaseType type); + QT_DEPRECATED void setDataSize(uint size); void setCount(uint count); void setByteStride(uint byteStride); void setByteOffset(uint byteOffset); @@ -122,6 +129,8 @@ public Q_SLOTS: Q_SIGNALS: void bufferChanged(QBuffer *buffer); void nameChanged(const QString &name); + void vertexBaseTypeChanged(VertexBaseType vertexBaseType); + void vertexSizeChanged(uint vertexSize); void dataTypeChanged(VertexBaseType vertexBaseType); void dataSizeChanged(uint vertexSize); void countChanged(uint count); diff --git a/src/render/geometry/qattribute_p.h b/src/render/geometry/qattribute_p.h index 8731e3195..d3385345a 100644 --- a/src/render/geometry/qattribute_p.h +++ b/src/render/geometry/qattribute_p.h @@ -71,8 +71,8 @@ public: QBuffer *m_buffer; QString m_name; - QAttribute::VertexBaseType m_dataType; - uint m_dataSize; + QAttribute::VertexBaseType m_vertexBaseType; + uint m_vertexSize; uint m_count; uint m_byteStride; uint m_byteOffset; @@ -84,8 +84,8 @@ struct QAttributeData { Qt3DCore::QNodeId bufferId; QString name; - QAttribute::VertexBaseType dataType; - uint dataSize; + QAttribute::VertexBaseType vertexBaseType; + uint vertexSize; uint count; uint byteStride; uint byteOffset; diff --git a/src/render/geometry/qbuffer.cpp b/src/render/geometry/qbuffer.cpp index e79ebcd24..1d37dfad5 100644 --- a/src/render/geometry/qbuffer.cpp +++ b/src/render/geometry/qbuffer.cpp @@ -110,6 +110,91 @@ QBufferPrivate::QBufferPrivate() * This signal is emitted with \a bytes when data changes. */ +/*! + \class Qt3DRender::QBufferDataGenerator + \inmodule Qt3DRender + + \inherits Qt3DRender::QAbstractFunctor + + \brief Provides a mechanism to generate buffer data from a job. + + The Qt3DRender::QBufferDataGenerator should be subclassed to provide a way + to fill the data of a Qt3DRender::QBuffer. Such functors are executed at + runtime in a Qt 3D job (likely in parallel with many other jobs). When + providing a functor you must implement the operator() which will be called + to generate the actual data. You must make sure that you have stored copies + of anything you might need for it to execute properly. You should also + implement the operator==. It will be used to compare with other functors + and based on that allow the renderer to decide if a new functor should be + executed or not. + + \note functors are useful when you can build data from a few set of + attributes (e.g: building a sphere from a radius property). If you already + have access to the buffer data, using Qt3DRender::QBuffer::setData() is + likely more efficient. + + \code + + QByteArray createSphereMeshVertexData(float radius, int rings, int slices) + { + ... + } + + class SphereVertexDataFunctor : public QBufferDataGenerator + { + public: + SphereVertexDataFunctor(int rings, int slices, float radius) + : m_rings(rings) + , m_slices(slices) + , m_radius(radius) + {} + + QByteArray operator ()() Q_DECL_OVERRIDE + { + return createSphereMeshVertexData(m_radius, m_rings, m_slices); + } + + bool operator ==(const QBufferDataGenerator &other) const Q_DECL_OVERRIDE + { + const SphereVertexDataFunctor *otherFunctor = functor_cast<SphereVertexDataFunctor>(&other); + if (otherFunctor != nullptr) + return (otherFunctor->m_rings == m_rings && + otherFunctor->m_slices == m_slices && + otherFunctor->m_radius == m_radius); + return false; + } + + QT3D_FUNCTOR(SphereVertexDataFunctor) + + private: + int m_rings; + int m_slices; + float m_radius; + }; + + \endcode + + The QT3D_FUNCTOR macro should be added when subclassing. This allows you to + use functor_cast in your comparison operator to make sure that the other + functor is of the same type as the one your are trying to compare against. +*/ + +/*! + \fn Qt3DRender::QBufferDataGenerator::operator()() + + Should be implemented to return the buffer data as a QByteArray when called. + */ + +/*! + \fn Qt3DRender::QBufferDataGenerator::operator ==(const QBufferDataGenerator &other) const + + Should be reimplemented to return true when two generators are identical, + false otherwise. + + \note The renderer uses this comparison to decide whether data for a buffer + needs to be reuploaded or not when the functor on a Qt3DRender::QBuffer + changes. + */ /*! * \enum QBuffer::BufferType @@ -195,7 +280,7 @@ void QBuffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) */ void QBuffer::setData(const QByteArray &bytes) { - Q_D(QBuffer); + Q_D(QBuffer); if (bytes != d->m_data) { d->m_data = bytes; Qt3DCore::QNodePrivate::get(this)->notifyPropertyChange("data", QVariant::fromValue(d->m_data)); @@ -204,6 +289,30 @@ void QBuffer::setData(const QByteArray &bytes) } /*! + * \Update the data. + */ +void QBuffer::updateData(int offset, const QByteArray &bytes) +{ + Q_D(QBuffer); + Q_ASSERT(offset >= 0 && (offset + bytes.size()) <= d->m_data.size()); + + // Update data + d->m_data.replace(offset, bytes.size(), bytes); + const bool blocked = blockNotifications(true); + emit dataChanged(d->m_data); + blockNotifications(blocked); + + QBufferUpdate updateData; + updateData.offset = offset; + updateData.data = bytes; + + auto e = QPropertyUpdatedChangePtr::create(id()); + e->setPropertyName("updateData"); + e->setValue(QVariant::fromValue(updateData)); + notifyObservers(e); +} + +/*! * \return the data. */ QByteArray QBuffer::data() const diff --git a/src/render/geometry/qbuffer.h b/src/render/geometry/qbuffer.h index ba5877e6e..3827b04c9 100644 --- a/src/render/geometry/qbuffer.h +++ b/src/render/geometry/qbuffer.h @@ -44,6 +44,7 @@ #include <Qt3DRender/qt3drender_global.h> #include <QSharedPointer> + QT_BEGIN_NAMESPACE namespace Qt3DRender { @@ -69,7 +70,7 @@ public: UniformBuffer = 0x8A11, // GL_UNIFORM_BUFFER ShaderStorageBuffer = 0x90D2 // GL_SHADER_STORAGE_BUFFER }; - Q_ENUM(BufferType) + Q_ENUM(BufferType) // LCOV_EXCL_LINE enum UsageType { @@ -83,7 +84,7 @@ public: DynamicRead = 0x88E9, // GL_DYNAMIC_READ DynamicCopy = 0x88EA // GL_DYNAMIC_COPY }; - Q_ENUM(UsageType) + Q_ENUM(UsageType) // LCOV_EXCL_LINE explicit QBuffer(BufferType ty = QBuffer::VertexBuffer, Qt3DCore::QNode *parent = nullptr); ~QBuffer(); @@ -98,6 +99,8 @@ public: void setDataGenerator(const QBufferDataGeneratorPtr &functor); QBufferDataGeneratorPtr dataGenerator() const; + Q_INVOKABLE void updateData(int offset, const QByteArray &bytes); + public Q_SLOTS: void setType(BufferType type); void setUsage(UsageType usage); diff --git a/src/render/geometry/qbuffer_p.h b/src/render/geometry/qbuffer_p.h index 1c1f20db6..eb69730b8 100644 --- a/src/render/geometry/qbuffer_p.h +++ b/src/render/geometry/qbuffer_p.h @@ -85,8 +85,15 @@ struct QBufferData bool syncData; }; +struct QBufferUpdate +{ + int offset; + QByteArray data; +}; + } // namespace Qt3DRender QT_END_NAMESPACE +Q_DECLARE_METATYPE(Qt3DRender::QBufferUpdate) // LCOV_EXCL_LINE #endif // QT3DRENDER_QBUFFER_P_H diff --git a/src/render/geometry/qbufferdatagenerator.h b/src/render/geometry/qbufferdatagenerator.h index 2b37ec24d..702f396d4 100644 --- a/src/render/geometry/qbufferdatagenerator.h +++ b/src/render/geometry/qbufferdatagenerator.h @@ -62,7 +62,7 @@ typedef QSharedPointer<QBufferDataGenerator> QBufferDataGeneratorPtr; QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QBufferDataGeneratorPtr) +Q_DECLARE_METATYPE(Qt3DRender::QBufferDataGeneratorPtr) // LCOV_EXCL_LINE #endif // QT3DRENDER_QBUFFERDATAGENERATOR diff --git a/src/render/geometry/qgeometryfactory.h b/src/render/geometry/qgeometryfactory.h index affcc0e52..d5d88a45d 100644 --- a/src/render/geometry/qgeometryfactory.h +++ b/src/render/geometry/qgeometryfactory.h @@ -64,7 +64,7 @@ typedef QSharedPointer<QGeometryFactory> QGeometryFactoryPtr; QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QGeometryFactoryPtr) +Q_DECLARE_METATYPE(Qt3DRender::QGeometryFactoryPtr) // LCOV_EXCL_LINE #endif // QT3DRENDER_QGEOMETRYFACTORY diff --git a/src/render/geometry/qgeometryrenderer.h b/src/render/geometry/qgeometryrenderer.h index be3bb6146..28d580990 100644 --- a/src/render/geometry/qgeometryrenderer.h +++ b/src/render/geometry/qgeometryrenderer.h @@ -85,7 +85,7 @@ public: TriangleStripAdjacency = 0x000D, Patches = 0x000E }; - Q_ENUM(PrimitiveType) + Q_ENUM(PrimitiveType) // LCOV_EXCL_LINE // how to figure out index count and all the fancy stuff that QMeshData provides for us? // also how to figure out which attribute(s?) hold the indices? diff --git a/src/render/geometry/qmesh.cpp b/src/render/geometry/qmesh.cpp index 89e72ea45..30e8a9460 100644 --- a/src/render/geometry/qmesh.cpp +++ b/src/render/geometry/qmesh.cpp @@ -52,20 +52,6 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { -class MeshFunctor : public QGeometryFactory -{ -public : - MeshFunctor(const QUrl &sourcePath, const QString &meshName = QString()); - QGeometry *operator()() Q_DECL_OVERRIDE; - bool operator ==(const QGeometryFactory &other) const Q_DECL_OVERRIDE; - QT3D_FUNCTOR(MeshFunctor) - -private: - QUrl m_sourcePath; - QString m_meshName; -}; - - QMeshPrivate::QMeshPrivate() : QGeometryRendererPrivate() { @@ -126,7 +112,9 @@ void QMesh::setSource(const QUrl& source) d->m_source = source; // update the functor QGeometryRenderer::setGeometryFactory(QGeometryFactoryPtr(new MeshFunctor(d->m_source, d->m_meshName))); + const bool blocked = blockNotifications(true); emit sourceChanged(source); + blockNotifications(blocked); } /*! @@ -148,7 +136,9 @@ void QMesh::setMeshName(const QString &meshName) d->m_meshName = meshName; // update the functor QGeometryRenderer::setGeometryFactory(QGeometryFactoryPtr(new MeshFunctor(d->m_source, d->m_meshName))); + const bool blocked = blockNotifications(true); emit meshNameChanged(meshName); + blockNotifications(blocked); } /*! diff --git a/src/render/geometry/qmesh_p.h b/src/render/geometry/qmesh_p.h index c9a6cc1e8..a621525cc 100644 --- a/src/render/geometry/qmesh_p.h +++ b/src/render/geometry/qmesh_p.h @@ -71,6 +71,21 @@ public: QString m_meshName; }; + +class Q_AUTOTEST_EXPORT MeshFunctor : public QGeometryFactory +{ +public : + MeshFunctor(const QUrl &sourcePath, const QString &meshName = QString()); + QGeometry *operator()() Q_DECL_OVERRIDE; + bool operator ==(const QGeometryFactory &other) const Q_DECL_OVERRIDE; + QT3D_FUNCTOR(MeshFunctor) + +private: + QUrl m_sourcePath; + QString m_meshName; +}; + + } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index 7a72e5e87..8c0803a79 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -45,7 +45,7 @@ #include <Qt3DRender/private/renderlogging_p.h> #include <Qt3DRender/private/shader_p.h> #include <Qt3DRender/private/material_p.h> -#include <Qt3DRender/private/texture_p.h> +#include <Qt3DRender/private/gltexture_p.h> #include <Qt3DRender/private/buffer_p.h> #include <Qt3DRender/private/attribute_p.h> #include <Qt3DRender/private/rendercommand_p.h> @@ -56,7 +56,9 @@ #include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/buffermanager_p.h> #include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/gltexturemanager_p.h> #include <Qt3DRender/private/attachmentpack_p.h> +#include <Qt3DRender/private/qbuffer_p.h> #include <QOpenGLShaderProgram> #if !defined(QT_OPENGL_ES_2) @@ -65,7 +67,7 @@ #include <QOpenGLFunctions_3_3_Core> #include <QOpenGLFunctions_4_3_Core> #include <Qt3DRender/private/graphicshelpergl2_p.h> -#include <Qt3DRender/private/graphicshelpergl3_p.h> +#include <Qt3DRender/private/graphicshelpergl3_2_p.h> #include <Qt3DRender/private/graphicshelpergl3_3_p.h> #include <Qt3DRender/private/graphicshelpergl4_p.h> #endif @@ -185,9 +187,7 @@ void GraphicsContext::initialize() m_gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &numTexUnits); qCDebug(Backend) << "context supports" << numTexUnits << "texture units"; - m_pinnedTextureUnits = QBitArray(numTexUnits); m_activeTextures.resize(numTexUnits); - m_textureScopes.resize(numTexUnits); if (m_gl->format().majorVersion() >= 3) { m_supportsVAO = true; @@ -202,6 +202,31 @@ void GraphicsContext::initialize() qCDebug(Backend) << "VAO support = " << m_supportsVAO; } +void GraphicsContext::resolveRenderTargetFormat() +{ + const QSurfaceFormat format = m_gl->format(); + const uint a = format.alphaBufferSize(); + const uint r = format.redBufferSize(); + const uint g = format.greenBufferSize(); + const uint b = format.blueBufferSize(); + +#define RGBA_BITS(r,g,b,a) (r | (g << 6) | (b << 12) | (a << 18)) + + const uint bits = RGBA_BITS(r,g,b,a); + switch (bits) { + case RGBA_BITS(8,8,8,8): + m_renderTargetFormat = QAbstractTexture::RGBA8_UNorm; + break; + case RGBA_BITS(8,8,8,0): + m_renderTargetFormat = QAbstractTexture::RGB8_UNorm; + break; + case RGBA_BITS(5,6,5,0): + m_renderTargetFormat = QAbstractTexture::R5G6B5; + break; + } +#undef RGBA_BITS +} + bool GraphicsContext::beginDrawing(QSurface *surface) { Q_ASSERT(surface); @@ -223,6 +248,9 @@ bool GraphicsContext::beginDrawing(QSurface *surface) if (m_ownCurrent && !makeCurrent(m_surface)) return false; + // TODO: cache surface format somewhere rather than doing this every time render surface changes + resolveRenderTargetFormat(); + // Sets or Create the correct m_glHelper // for the current surface activateGLHelper(); @@ -249,7 +277,10 @@ bool GraphicsContext::beginDrawing(QSurface *surface) m_activeShaderDNA = 0; } - m_activeTextures.fill(0); + // reset active textures + for (int u = 0; u < m_activeTextures.size(); ++u) + m_activeTextures[u].texture = nullptr; + m_boundArrayBuffer = nullptr; static int callCount = 0; @@ -286,9 +317,8 @@ void GraphicsContext::endDrawing(bool swapBuffers) decayTextureScores(); } -void GraphicsContext::setViewport(const QRectF &viewport, const QSize &surfaceSize) +QSize GraphicsContext::renderTargetSize(const QSize &surfaceSize) const { - m_viewport = viewport; QSize renderTargetSize; if (m_activeFBO != m_defaultFBO) { // For external FBOs we may not have a m_renderTargets entry. @@ -317,7 +347,7 @@ void GraphicsContext::setViewport(const QRectF &viewport, const QSize &surfaceSi // Assumes texture level 0 and GL_TEXTURE_2D target renderTargetSize = m_glHelper->getTextureDimensions(attachment0Name, GL_TEXTURE_2D); else - return; + return renderTargetSize; } } else { renderTargetSize = m_surface->size(); @@ -326,9 +356,16 @@ void GraphicsContext::setViewport(const QRectF &viewport, const QSize &surfaceSi renderTargetSize *= dpr; } } + return renderTargetSize; +} + +void GraphicsContext::setViewport(const QRectF &viewport, const QSize &surfaceSize) +{ + m_viewport = viewport; + QSize size = renderTargetSize(surfaceSize); // Check that the returned size is before calling glViewport - if (renderTargetSize.isEmpty()) + if (size.isEmpty()) return; // Qt3D 0------------------> 1 OpenGL 1^ @@ -339,10 +376,10 @@ void GraphicsContext::setViewport(const QRectF &viewport, const QSize &surfaceSi // 1 0---------------------> 1 // The Viewport is defined between 0 and 1 which allows us to automatically // scale to the size of the provided window surface - m_gl->functions()->glViewport(m_viewport.x() * renderTargetSize.width(), - (1.0 - m_viewport.y() - m_viewport.height()) * renderTargetSize.height(), - m_viewport.width() * renderTargetSize.width(), - m_viewport.height() * renderTargetSize.height()); + m_gl->functions()->glViewport(m_viewport.x() * size.width(), + (1.0 - m_viewport.y() - m_viewport.height()) * size.height(), + m_viewport.width() * size.width(), + m_viewport.height() * size.height()); } void GraphicsContext::releaseOpenGL() @@ -384,6 +421,11 @@ bool GraphicsContext::hasValidGLHelper() const return m_glHelper != nullptr; } +bool GraphicsContext::isInitialized() const +{ + return m_initialized; +} + bool GraphicsContext::makeCurrent(QSurface *surface) { Q_ASSERT(m_gl); @@ -513,14 +555,20 @@ void GraphicsContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, fboId = m_renderTargets.value(renderTargetNodeId); // We need to check if one of the attachment was resized - TextureManager *textureManager = m_renderer->nodeManagers()->textureManager(); - bool needsResize = false; - const auto attachments_ = attachments.attachments(); - for (const Attachment &attachment : attachments_) { - Texture *rTex = textureManager->lookupResource(attachment.m_textureUuid); - if (rTex != nullptr) - needsResize |= rTex->isTextureReset(); + bool needsResize = !m_renderTargetsSize.contains(fboId); // not even initialized yet? + if (!needsResize) { + // render target exists, has attachment been resized? + GLTextureManager *glTextureManager = m_renderer->nodeManagers()->glTextureManager(); + const QSize s = m_renderTargetsSize[fboId]; + const auto attachments_ = attachments.attachments(); + for (const Attachment &attachment : attachments_) { + GLTexture *rTex = glTextureManager->lookupResource(attachment.m_textureUuid); + needsResize |= (rTex != nullptr && rTex->size() != s); + if (attachment.m_point == QRenderTargetOutput::Color0) + m_renderTargetFormat = rTex->properties().format; + } } + if (needsResize) { m_glHelper->bindFrameBufferObject(fboId); bindFrameBufferAttachmentHelper(fboId, attachments); @@ -538,19 +586,17 @@ void GraphicsContext::bindFrameBufferAttachmentHelper(GLuint fboId, const Attach // Set FBO attachments QSize fboSize; - TextureManager *textureManager = m_renderer->nodeManagers()->textureManager(); + GLTextureManager *glTextureManager = m_renderer->nodeManagers()->glTextureManager(); const auto attachments_ = attachments.attachments(); for (const Attachment &attachment : attachments_) { - Texture *rTex =textureManager->lookupResource(attachment.m_textureUuid); - if (rTex != nullptr) { - QOpenGLTexture *glTex = rTex->getOrCreateGLTexture(); - if (glTex != nullptr) { - if (fboSize.isEmpty()) - fboSize = QSize(glTex->width(), glTex->height()); - else - fboSize = QSize(qMin(fboSize.width(), glTex->width()), qMin(fboSize.height(), glTex->height())); - m_glHelper->bindFrameBufferAttachment(glTex, attachment); - } + GLTexture *rTex = glTextureManager->lookupResource(attachment.m_textureUuid); + QOpenGLTexture *glTex = rTex ? rTex->getOrCreateGLTexture() : nullptr; + if (glTex != nullptr) { + if (fboSize.isEmpty()) + fboSize = QSize(glTex->width(), glTex->height()); + else + fboSize = QSize(qMin(fboSize.width(), glTex->width()), qMin(fboSize.height(), glTex->height())); + m_glHelper->bindFrameBufferAttachment(glTex, attachment); } } m_renderTargetsSize.insert(fboId, fboSize); @@ -582,7 +628,7 @@ void GraphicsContext::setActiveMaterial(Material *rmat) m_material = rmat; } -int GraphicsContext::activateTexture(TextureScope scope, Texture *tex, int onUnit) +int GraphicsContext::activateTexture(TextureScope scope, GLTexture *tex, int onUnit) { // Returns the texture unit to use for the texture // This always return a valid unit, unless there are more textures than @@ -595,10 +641,10 @@ int GraphicsContext::activateTexture(TextureScope scope, Texture *tex, int onUni // actually re-bind if required, the tex->dna on the unit not being the same // Note: tex->dna() could be 0 if the texture has not been created yet - if (m_activeTextures[onUnit] != tex->dna() || tex->dna() == 0 || tex->dataUploadRequired()) { + if (m_activeTextures[onUnit].texture != tex) { QOpenGLTexture *glTex = tex->getOrCreateGLTexture(); glTex->bind(onUnit); - m_activeTextures[onUnit] = tex->dna(); + m_activeTextures[onUnit].texture = tex; } #if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) @@ -608,9 +654,9 @@ int GraphicsContext::activateTexture(TextureScope scope, Texture *tex, int onUni << tex->textureId() << "on unit" << onUnit; #endif - m_textureScores.insert(m_activeTextures[onUnit], 200); - m_pinnedTextureUnits[onUnit] = true; - m_textureScopes[onUnit] = scope; + m_activeTextures[onUnit].score = 200; + m_activeTextures[onUnit].pinned = true; + m_activeTextures[onUnit].scope = scope; return onUnit; } @@ -618,12 +664,12 @@ int GraphicsContext::activateTexture(TextureScope scope, Texture *tex, int onUni void GraphicsContext::deactivateTexturesWithScope(TextureScope ts) { for (int u=0; u<m_activeTextures.size(); ++u) { - if (!m_pinnedTextureUnits[u]) + if (!m_activeTextures[u].pinned) continue; // inactive, ignore - if (m_textureScopes[u] == ts) { - m_pinnedTextureUnits[u] = false; - m_textureScores.insert(m_activeTextures[u], m_textureScores.value(m_activeTextures[u], 1) - 1); + if (m_activeTextures[u].scope == ts) { + m_activeTextures[u].pinned = false; + m_activeTextures[u].score = qMax(m_activeTextures[u].score, 1) - 1; } } // of units iteration } @@ -656,7 +702,7 @@ GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions() glHelper = new GraphicsHelperGL3_3(); } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_3_2_Core>()) != nullptr) { qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.2"; - glHelper = new GraphicsHelperGL3(); + glHelper = new GraphicsHelperGL3_2(); } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_2_0>()) != nullptr) { qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 2 Helper"; glHelper = new GraphicsHelperGL2(); @@ -708,12 +754,12 @@ GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions() return glHelper; } -void GraphicsContext::deactivateTexture(Texture* tex) +void GraphicsContext::deactivateTexture(GLTexture* tex) { for (int u=0; u<m_activeTextures.size(); ++u) { - if (m_activeTextures[u] == tex->dna()) { - Q_ASSERT(m_pinnedTextureUnits[u]); - m_pinnedTextureUnits[u] = false; + if (m_activeTextures[u].texture == tex) { + Q_ASSERT(m_activeTextures[u].pinned); + m_activeTextures[u].pinned = false; return; } } // of units iteration @@ -726,7 +772,8 @@ void GraphicsContext::setCurrentStateSet(RenderStateSet *ss) if (ss == m_stateSet) return; - ss->apply(this); + if (ss) + ss->apply(this); m_stateSet = ss; } @@ -870,11 +917,6 @@ void GraphicsContext::bindFragOutputs(GLuint shader, const QHash<QString, int> & m_glHelper->bindFragDataLocation(shader, outputs); } -void GraphicsContext::bindUniform(const QVariant &v, const ShaderUniform &description) -{ - m_glHelper->bindUniform(v, description); -} - void GraphicsContext::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { m_glHelper->bindUniformBlock(programId, uniformBlockIndex, uniformBlockBinding); @@ -1003,20 +1045,20 @@ void GraphicsContext::setSeamlessCubemap(bool enable) Tries to use the texture unit with the texture that hasn't been used for the longest time if the texture happens not to be already pinned on a texture unit. */ -GLint GraphicsContext::assignUnitForTexture(Texture *tex) +GLint GraphicsContext::assignUnitForTexture(GLTexture *tex) { int lowestScoredUnit = -1; int lowestScore = 0xfffffff; for (int u=0; u<m_activeTextures.size(); ++u) { - if (m_activeTextures[u] == tex->dna()) + if (m_activeTextures[u].texture == tex) return u; // No texture is currently active on the texture unit // we save the texture unit with the texture that has been on there // the longest time while not being used - if (!m_pinnedTextureUnits[u]) { - int score = m_textureScores.value(m_activeTextures[u], 0); + if (!m_activeTextures[u].pinned) { + int score = m_activeTextures[u].score; if (score < lowestScore) { lowestScore = score; lowestScoredUnit = u; @@ -1032,18 +1074,8 @@ GLint GraphicsContext::assignUnitForTexture(Texture *tex) void GraphicsContext::decayTextureScores() { - QHash<uint, int>::iterator it = m_textureScores.begin(); - const QHash<uint, int>::iterator end = m_textureScores.end(); - - while (it != end) { - it.value()--; - if (it.value() <= 0) { - qCDebug(Backend) << "removing inactive texture" << it.key(); - it = m_textureScores.erase(it); - } else { - ++it; - } - } + for (int u = 0; u < m_activeTextures.size(); u++) + m_activeTextures[u].score = qMax(m_activeTextures[u].score - 1, 0); } QOpenGLShaderProgram* GraphicsContext::activeShader() const @@ -1074,13 +1106,14 @@ void GraphicsContext::setParameters(ShaderParameterPack ¶meterPack) for (int i = 0; i < parameterPack.textures().size(); ++i) { const ShaderParameterPack::NamedTexture &namedTex = parameterPack.textures().at(i); - Texture *t = manager->lookupResource<Texture, TextureManager>(namedTex.texId); - // TO DO : Rework the way textures are loaded - if (t != nullptr) { - int texUnit = activateTexture(TextureScopeMaterial, t); - if (uniformValues.contains(namedTex.glslNameId)) { - QUniformValue &texUniform = uniformValues[namedTex.glslNameId]; - texUniform.setTextureUnit(texUnit); + // Given a Texture QNodeId, we retrieve the associated shared GLTexture + if (uniformValues.contains(namedTex.glslNameId)) { + GLTexture *t = manager->glTextureManager()->lookupResource(namedTex.texId); + if (t != nullptr) { + UniformValue &texUniform = uniformValues[namedTex.glslNameId]; + Q_ASSERT(texUniform.valueType() == UniformValue::TextureValue); + const int texUnit = activateTexture(TextureScopeMaterial, t); + texUniform.data<UniformValue::Texture>()->textureId = texUnit; } } } @@ -1136,8 +1169,7 @@ void GraphicsContext::setParameters(ShaderParameterPack ¶meterPack) for (const ShaderUniform &uniform : activeUniforms) { // We can use [] as we are sure the the uniform wouldn't // be un activeUniforms if there wasn't a matching value - const QUniformValue &value = values[uniform.m_nameId]; - value.apply(this, uniform); + applyUniform(uniform, values[uniform.m_nameId]); } } @@ -1167,6 +1199,110 @@ void GraphicsContext::disableAttribute(const GraphicsContext::VAOVertexAttribute prog->disableAttributeArray(attr.location); } +void GraphicsContext::applyUniform(const ShaderUniform &description, const UniformValue &v) +{ + const UniformType type = m_glHelper->uniformTypeFromGLType(description.m_type); + + switch (type) { + case UniformType::Float: + applyUniformHelper<UniformType::Float>(description.m_location, description.m_size, v); + break; + case UniformType::Vec2: + applyUniformHelper<UniformType::Vec2>(description.m_location, description.m_size, v); + break; + case UniformType::Vec3: + applyUniformHelper<UniformType::Vec3>(description.m_location, description.m_size, v); + break; + case UniformType::Vec4: + applyUniformHelper<UniformType::Vec4>(description.m_location, description.m_size, v); + break; + + case UniformType::Double: + applyUniformHelper<UniformType::Double>(description.m_location, description.m_size, v); + break; + case UniformType::DVec2: + applyUniformHelper<UniformType::DVec2>(description.m_location, description.m_size, v); + break; + case UniformType::DVec3: + applyUniformHelper<UniformType::DVec3>(description.m_location, description.m_size, v); + break; + case UniformType::DVec4: + applyUniformHelper<UniformType::DVec4>(description.m_location, description.m_size, v); + break; + + case UniformType::Sampler: + case UniformType::Int: + applyUniformHelper<UniformType::Int>(description.m_location, description.m_size, v); + break; + case UniformType::IVec2: + applyUniformHelper<UniformType::IVec2>(description.m_location, description.m_size, v); + break; + case UniformType::IVec3: + applyUniformHelper<UniformType::IVec3>(description.m_location, description.m_size, v); + break; + case UniformType::IVec4: + applyUniformHelper<UniformType::IVec4>(description.m_location, description.m_size, v); + break; + + case UniformType::UInt: + applyUniformHelper<UniformType::Int>(description.m_location, description.m_size, v); + break; + case UniformType::UIVec2: + applyUniformHelper<UniformType::IVec2>(description.m_location, description.m_size, v); + break; + case UniformType::UIVec3: + applyUniformHelper<UniformType::IVec3>(description.m_location, description.m_size, v); + break; + case UniformType::UIVec4: + applyUniformHelper<UniformType::IVec4>(description.m_location, description.m_size, v); + break; + + case UniformType::Bool: + applyUniformHelper<UniformType::Bool>(description.m_location, description.m_size, v); + break; + case UniformType::BVec2: + applyUniformHelper<UniformType::BVec2>(description.m_location, description.m_size, v); + break; + case UniformType::BVec3: + applyUniformHelper<UniformType::BVec3>(description.m_location, description.m_size, v); + break; + case UniformType::BVec4: + applyUniformHelper<UniformType::BVec4>(description.m_location, description.m_size, v); + break; + + case UniformType::Mat2: + applyUniformHelper<UniformType::Mat2>(description.m_location, description.m_size, v); + break; + case UniformType::Mat3: + applyUniformHelper<UniformType::Mat3>(description.m_location, description.m_size, v); + break; + case UniformType::Mat4: + applyUniformHelper<UniformType::Mat4>(description.m_location, description.m_size, v); + break; + case UniformType::Mat2x3: + applyUniformHelper<UniformType::Mat2x3>(description.m_location, description.m_size, v); + break; + case UniformType::Mat3x2: + applyUniformHelper<UniformType::Mat3x2>(description.m_location, description.m_size, v); + break; + case UniformType::Mat2x4: + applyUniformHelper<UniformType::Mat2x4>(description.m_location, description.m_size, v); + break; + case UniformType::Mat4x2: + applyUniformHelper<UniformType::Mat4x2>(description.m_location, description.m_size, v); + break; + case UniformType::Mat3x4: + applyUniformHelper<UniformType::Mat3x4>(description.m_location, description.m_size, v); + break; + case UniformType::Mat4x3: + applyUniformHelper<UniformType::Mat4x3>(description.m_location, description.m_size, v); + break; + + default: + break; + } +} + // Note: needs to be called while VAO is bound void GraphicsContext::specifyAttribute(const Attribute *attribute, Buffer *buffer, int location) { @@ -1297,10 +1433,26 @@ void GraphicsContext::uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool rel { if (!bindGLBuffer(b, bufferTypeToGLBufferType(buffer->type()))) qCWarning(Render::Io) << Q_FUNC_INFO << "buffer bind failed"; - const int bufferSize = buffer->data().size(); - // TO DO: Handle usage pattern and sub data updates - b->allocate(this, bufferSize, false); // orphan the buffer - b->allocate(this, buffer->data().constData(), bufferSize, false); + // If the buffer is dirty (hence being called here) + // there are two possible cases + // * setData was called changing the whole data or functor (or the usage pattern) + // * partial buffer updates where received + + // Note: we assume the case where both setData/functor and updates are called to be a misuse + // with unexpected behavior + const QVector<Qt3DRender::QBufferUpdate> updates = std::move(buffer->pendingBufferUpdates()); + if (!updates.empty()) { + for (const Qt3DRender::QBufferUpdate &update : updates) { + // TO DO: based on the number of updates .., it might make sense to + // sometime use glMapBuffer rather than glBufferSubData + b->update(this, update.data.constData(), update.data.size(), update.offset); + } + } else { + const int bufferSize = buffer->data().size(); + // TO DO: Handle usage pattern + b->allocate(this, bufferSize, false); // orphan the buffer + b->allocate(this, buffer->data().constData(), bufferSize, false); + } if (releaseBuffer) { b->release(this); if (bufferTypeToGLBufferType(buffer->type()) == GLBuffer::ArrayBuffer) @@ -1426,6 +1578,208 @@ GLint GraphicsContext::glDataTypeFromAttributeDataType(QAttribute::VertexBaseTyp return GL_FLOAT; } +static void copyGLFramebufferDataToImage(QImage &img, const uchar *srcData, uint stride, uint width, uint height, QAbstractTexture::TextureFormat format) +{ + switch (format) { + case QAbstractTexture::RGBA32F: + { + uchar *srcScanline = (uchar *)srcData + stride * (height - 1); + for (uint i = 0; i < height; ++i) { + uchar *dstScanline = img.scanLine(i); + float *pSrc = (float*)srcScanline; + for (uint j = 0; j < width; j++) { + *dstScanline++ = (uchar)(255.0f * (pSrc[4*j+2] / (1.0f + pSrc[4*j+2]))); + *dstScanline++ = (uchar)(255.0f * (pSrc[4*j+1] / (1.0f + pSrc[4*j+1]))); + *dstScanline++ = (uchar)(255.0f * (pSrc[4*j+0] / (1.0f + pSrc[4*j+0]))); + *dstScanline++ = (uchar)(255.0f * qBound(0.0f, pSrc[4*j+3], 1.0f)); + } + srcScanline -= stride; + } + } break; + default: + { + uchar* srcScanline = (uchar *)srcData + stride * (height - 1); + for (uint i = 0; i < height; ++i) { + memcpy(img.scanLine(i), srcScanline, stride); + srcScanline -= stride; + } + } break; + } +} + +QImage GraphicsContext::readFramebuffer(QSize size) +{ + QImage img; + const unsigned int area = size.width() * size.height(); + unsigned int bytes; + GLenum format, type; + QImage::Format imageFormat; + uint stride; + +#ifndef QT_OPENGL_ES_2 + /* format value should match GL internalFormat */ + GLenum internalFormat = m_renderTargetFormat; +#endif + + switch (m_renderTargetFormat) { + case QAbstractTexture::RGBAFormat: + case QAbstractTexture::RGBA8_SNorm: + case QAbstractTexture::RGBA8_UNorm: + case QAbstractTexture::RGBA8U: + case QAbstractTexture::SRGB8_Alpha8: +#ifdef QT_OPENGL_ES_2 + format = GL_RGBA; + imageFormat = QImage::Format_RGBA8888_Premultiplied; +#else + format = GL_BGRA; + imageFormat = QImage::Format_ARGB32_Premultiplied; + internalFormat = GL_RGBA8; +#endif + type = GL_UNSIGNED_BYTE; + bytes = area * 4; + stride = size.width() * 4; + break; + case QAbstractTexture::SRGB8: + case QAbstractTexture::RGBFormat: + case QAbstractTexture::RGB8U: +#ifdef QT_OPENGL_ES_2 + format = GL_RGBA; + imageFormat = QImage::Format_RGBX8888; +#else + format = GL_BGRA; + imageFormat = QImage::Format_RGB32; + internalFormat = GL_RGB8; +#endif + type = GL_UNSIGNED_BYTE; + bytes = area * 4; + stride = size.width() * 4; + break; +#ifndef QT_OPENGL_ES_2 + case QAbstractTexture::RG11B10F: + bytes = area * 4; + format = GL_RGB; + type = GL_UNSIGNED_INT_10F_11F_11F_REV; + imageFormat = QImage::Format_RGB30; + stride = size.width() * 4; + break; + case QAbstractTexture::RGB10A2: + bytes = area * 4; + format = GL_RGBA; + type = GL_UNSIGNED_INT_2_10_10_10_REV; + imageFormat = QImage::Format_A2BGR30_Premultiplied; + stride = size.width() * 4; + break; + case QAbstractTexture::R5G6B5: + bytes = area * 2; + format = GL_RGB; + type = GL_UNSIGNED_SHORT; + internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV; + imageFormat = QImage::Format_RGB16; + stride = size.width() * 2; + break; + case QAbstractTexture::RGBA16F: + case QAbstractTexture::RGBA16U: + case QAbstractTexture::RGBA32F: + case QAbstractTexture::RGBA32U: + bytes = area * 16; + format = GL_RGBA; + type = GL_FLOAT; + imageFormat = QImage::Format_ARGB32_Premultiplied; + stride = size.width() * 16; + break; +#endif + default: + // unsupported format + Q_UNREACHABLE(); + return img; + } + +#ifndef QT_OPENGL_ES_2 + GLint samples = 0; + m_gl->functions()->glGetIntegerv(GL_SAMPLES, &samples); + if (samples > 0 && !m_glHelper->supportsFeature(GraphicsHelperInterface::BlitFramebuffer)) + return img; +#endif + + img = QImage(size.width(), size.height(), imageFormat); + + QScopedArrayPointer<uchar> data(new uchar [bytes]); + +#ifndef QT_OPENGL_ES_2 + if (samples > 0) { + // resolve multisample-framebuffer to renderbuffer and read pixels from it + GLuint fbo, rb; + QOpenGLFunctions *gl = m_gl->functions(); + gl->glGenFramebuffers(1, &fbo); + gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + gl->glGenRenderbuffers(1, &rb); + gl->glBindRenderbuffer(GL_RENDERBUFFER, rb); + gl->glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, size.width(), size.height()); + gl->glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb); + + const GLenum status = gl->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + gl->glDeleteRenderbuffers(1, &rb); + gl->glDeleteFramebuffers(1, &fbo); + return img; + } + + m_glHelper->blitFramebuffer(0, 0, size.width(), size.height(), + 0, 0, size.width(), size.height(), + GL_COLOR_BUFFER_BIT, GL_NEAREST); + gl->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + gl->glReadPixels(0,0,size.width(), size.height(), format, type, data.data()); + + copyGLFramebufferDataToImage(img, data.data(), stride, size.width(), size.height(), m_renderTargetFormat); + + gl->glBindRenderbuffer(GL_RENDERBUFFER, rb); + gl->glDeleteRenderbuffers(1, &rb); + gl->glBindFramebuffer(GL_FRAMEBUFFER, m_activeFBO); + gl->glDeleteFramebuffers(1, &fbo); + } else { +#endif + // read pixels directly from framebuffer + m_gl->functions()->glReadPixels(0,0,size.width(), size.height(), format, type, data.data()); + copyGLFramebufferDataToImage(img, data.data(), stride, size.width(), size.height(), m_renderTargetFormat); + +#ifndef QT_OPENGL_ES_2 + } +#endif + + return img; +} + +QT3D_UNIFORM_TYPE_IMPL(UniformType::Float, float, glUniform1fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec2, float, glUniform2fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec3, float, glUniform3fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec4, float, glUniform4fv) + +// OpenGL expects int* as values for booleans +QT3D_UNIFORM_TYPE_IMPL(UniformType::Bool, int, glUniform1iv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec2, int, glUniform2iv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec3, int, glUniform3iv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec4, int, glUniform4iv) + +QT3D_UNIFORM_TYPE_IMPL(UniformType::Int, int, glUniform1iv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec2, int, glUniform2iv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec3, int, glUniform3iv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec4, int, glUniform4iv) + +QT3D_UNIFORM_TYPE_IMPL(UniformType::UInt, uint, glUniform1uiv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec2, uint, glUniform2uiv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec3, uint, glUniform3uiv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec4, uint, glUniform4uiv) + +QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2, float, glUniformMatrix2fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3, float, glUniformMatrix3fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4, float, glUniformMatrix4fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x3, float, glUniformMatrix2x3fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x2, float, glUniformMatrix3x2fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x4, float, glUniformMatrix2x4fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x2, float, glUniformMatrix4x2fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x4, float, glUniformMatrix3x4fv) +QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x3, float, glUniformMatrix4x3fv) + } // namespace Render } // namespace Qt3DRender of namespace diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h index cc63a03b6..9f7a0f972 100644 --- a/src/render/graphicshelpers/graphicscontext_p.h +++ b/src/render/graphicshelpers/graphicscontext_p.h @@ -59,7 +59,8 @@ #include <QColor> #include <QMatrix4x4> #include <QBitArray> -#include <Qt3DRender/private/quniformvalue_p.h> +#include <QImage> +#include <Qt3DRender/private/shaderparameterpack_p.h> #include <Qt3DRender/qclearbuffers.h> #include <Qt3DRender/private/shader_p.h> #include <Qt3DRender/private/glbuffer_p.h> @@ -67,6 +68,7 @@ #include <Qt3DRender/private/handle_types_p.h> #include <Qt3DRender/private/qgraphicsapifilter_p.h> #include <Qt3DRender/private/shadercache_p.h> +#include <Qt3DRender/private/uniform_p.h> QT_BEGIN_NAMESPACE @@ -82,7 +84,7 @@ class Renderer; class GraphicsHelperInterface; class RenderStateSet; class Material; -class Texture; +class GLTexture; class RenderCommand; class RenderTarget; class AttachmentPack; @@ -98,7 +100,7 @@ enum TextureScope typedef QPair<QString, int> NamedUniformLocation; -class GraphicsContext +class Q_AUTOTEST_EXPORT GraphicsContext { public: GraphicsContext(); @@ -124,6 +126,7 @@ public: void doneCurrent(); void activateGLHelper(); bool hasValidGLHelper() const; + bool isInitialized() const; QOpenGLShaderProgram *createShaderProgram(Shader *shaderNode); void loadShader(Shader* shader); @@ -140,6 +143,8 @@ public: void executeCommand(const RenderCommand *command); + QSize renderTargetSize(const QSize &surfaceSize) const; + /** * @brief activeShader * @return @@ -170,9 +175,9 @@ public: * @param onUnit - option, specify the explicit unit to activate on * @return - the unit the texture was activated on */ - int activateTexture(TextureScope scope, Texture* tex, int onUnit = -1); + int activateTexture(TextureScope scope, GLTexture* tex, int onUnit = -1); - void deactivateTexture(Texture *tex); + void deactivateTexture(GLTexture *tex); void setCurrentStateSet(RenderStateSet* ss); RenderStateSet *currentStateSet() const; @@ -184,7 +189,6 @@ public: void bindBufferBase(GLenum target, GLuint bindingIndex, GLuint buffer); void bindFragOutputs(GLuint shader, const QHash<QString, int> &outputs); void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding); - void bindUniform(const QVariant &v, const ShaderUniform &description); void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding); void blendEquation(GLenum mode); void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor); @@ -227,12 +231,14 @@ public: bool supportsDrawBuffersBlend() const; bool supportsVAO() const { return m_supportsVAO; } + QImage readFramebuffer(QSize size); + private: void initialize(); void decayTextureScores(); - GLint assignUnitForTexture(Texture* tex); + GLint assignUnitForTexture(GLTexture* tex); void deactivateTexturesWithScope(TextureScope ts); GraphicsHelperInterface *resolveHighestOpenGLFunctions(); @@ -242,6 +248,7 @@ private: HGLBuffer createGLBufferFor(Buffer *buffer); void uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer = false); bool bindGLBuffer(GLBuffer *buffer, GLBuffer::Type type); + void resolveRenderTargetFormat(); bool m_initialized; const unsigned int m_id; @@ -257,23 +264,24 @@ private: QHash<Qt3DCore::QNodeId, HGLBuffer> m_renderBufferHash; QHash<Qt3DCore::QNodeId, GLuint> m_renderTargets; QHash<GLuint, QSize> m_renderTargetsSize; + QAbstractTexture::TextureFormat m_renderTargetFormat; QHash<QSurface *, GraphicsHelperInterface*> m_glHelpers; // active textures, indexed by texture unit - QVector<uint> m_activeTextures; - QBitArray m_pinnedTextureUnits; - QVector<TextureScope> m_textureScopes; + struct ActiveTexture { + GLTexture *texture = nullptr; + int score = 0; + TextureScope scope = TextureScopeMaterial; + bool pinned = false; + }; + QVector<ActiveTexture> m_activeTextures; // cache some current state, to make sure we don't issue unnecessary GL calls int m_currClearStencilValue; float m_currClearDepthValue; QColor m_currClearColorValue; - // recency score for all render-textures we've seen. Higher scores - // mean more recently used. - QHash<uint, int> m_textureScores; - Material* m_material; QRectF m_viewport; GLuint m_activeFBO; @@ -310,8 +318,59 @@ private: void enableAttribute(const VAOVertexAttribute &attr); void disableAttribute(const VAOVertexAttribute &attr); + + void applyUniform(const ShaderUniform &description, const UniformValue &v); + + template<UniformType> + void applyUniformHelper(int, int, const UniformValue &) const + { + Q_ASSERT_X(false, Q_FUNC_INFO, "Uniform: Didn't provide specialized apply() implementation"); + } }; +#define QT3D_UNIFORM_TYPE_PROTO(UniformTypeEnum, BaseType, Func) \ +template<> \ +void GraphicsContext::applyUniformHelper<UniformTypeEnum>(int location, int count, const UniformValue &value) const; + +#define QT3D_UNIFORM_TYPE_IMPL(UniformTypeEnum, BaseType, Func) \ + template<> \ + void GraphicsContext::applyUniformHelper<UniformTypeEnum>(int location, int count, const UniformValue &value) const \ +{ \ + m_glHelper->Func(location, count, value.constData<BaseType>()); \ +} + + +QT3D_UNIFORM_TYPE_PROTO(UniformType::Float, float, glUniform1fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Vec2, float, glUniform2fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Vec3, float, glUniform3fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Vec4, float, glUniform4fv) + +// OpenGL expects int* as values for booleans +QT3D_UNIFORM_TYPE_PROTO(UniformType::Bool, int, glUniform1iv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::BVec2, int, glUniform2iv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::BVec3, int, glUniform3iv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::BVec4, int, glUniform4iv) + +QT3D_UNIFORM_TYPE_PROTO(UniformType::Int, int, glUniform1iv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::IVec2, int, glUniform2iv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::IVec3, int, glUniform3iv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::IVec4, int, glUniform4iv) + +QT3D_UNIFORM_TYPE_PROTO(UniformType::UInt, uint, glUniform1uiv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::UIVec2, uint, glUniform2uiv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::UIVec3, uint, glUniform3uiv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::UIVec4, uint, glUniform4uiv) + +QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat2, float, glUniformMatrix2fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat3, float, glUniformMatrix3fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat4, float, glUniformMatrix4fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat2x3, float, glUniformMatrix2x3fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat3x2, float, glUniformMatrix3x2fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat2x4, float, glUniformMatrix2x4fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat4x2, float, glUniformMatrix4x2fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat3x4, float, glUniformMatrix3x4fv) +QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat4x3, float, glUniformMatrix4x3fv) + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/graphicshelpers/graphicshelperes2.cpp b/src/render/graphicshelpers/graphicshelperes2.cpp index b09e33291..1335b250f 100644 --- a/src/render/graphicshelpers/graphicshelperes2.cpp +++ b/src/render/graphicshelpers/graphicshelperes2.cpp @@ -334,8 +334,14 @@ void GraphicsHelperES2::bindFrameBufferAttachment(QOpenGLTexture *texture, const else qCritical() << "Unsupported FBO attachment OpenGL ES 2.0"; + const QOpenGLTexture::Target target = texture->target(); + + if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face == QAbstractTexture::AllFaces) { + qWarning() << "OpenGL ES 2.0 doesn't handle attaching all the faces of a cube map texture at once to an FBO"; + return; + } + texture->bind(); - QOpenGLTexture::Target target = texture->target(); if (target == QOpenGLTexture::Target2D) m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel); else if (target == QOpenGLTexture::TargetCubeMap) @@ -359,108 +365,6 @@ void GraphicsHelperES2::drawBuffers(GLsizei, const int *) qWarning() << "drawBuffers is not supported by ES 2.0"; } -void GraphicsHelperES2::bindUniform(const QVariant &v, const ShaderUniform &description) -{ - switch (description.m_type) { - - case GL_FLOAT: - m_funcs->glUniform1fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1)); - break; - - case GL_FLOAT_VEC2: - m_funcs->glUniform2fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2)); - break; - - case GL_FLOAT_VEC3: - m_funcs->glUniform3fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3)); - break; - - case GL_FLOAT_VEC4: - m_funcs->glUniform4fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT2: - m_funcs->glUniformMatrix2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT3: - m_funcs->glUniformMatrix3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9)); - break; - - case GL_FLOAT_MAT4: - m_funcs->glUniformMatrix4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16)); - break; - - case GL_INT: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_INT_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_INT_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_INT_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_BOOL: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_BOOL_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_BOOL_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_BOOL_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_SAMPLER_2D: - case GL_SAMPLER_CUBE: { - Q_ASSERT(description.m_size == 1); - m_funcs->glUniform1i(description.m_location, v.toInt()); - break; - } - - // ES 3.0+ - case GL_SAMPLER_3D: - case GL_SAMPLER_2D_SHADOW: - case GL_SAMPLER_CUBE_SHADOW: - case GL_SAMPLER_2D_ARRAY: - case GL_SAMPLER_2D_ARRAY_SHADOW: - qWarning() << Q_FUNC_INFO << "ES 3.0 uniform type" << description.m_type << "for" - << description.m_name << "is not supported in ES 2.0"; - break; - - default: - qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name; - break; - } -} - void GraphicsHelperES2::bindFragDataLocation(GLuint , const QHash<QString, int> &) { qCritical() << "bindFragDataLocation is not supported by ES 2.0"; @@ -655,6 +559,169 @@ void GraphicsHelperES2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) qWarning() << "Compute Shaders are not supported by ES 2.0 (since ES 3.1)"; } +void GraphicsHelperES2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform1fv(location, count, values); +} + +void GraphicsHelperES2::glUniform2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform2fv(location, count, values); +} + +void GraphicsHelperES2::glUniform3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform3fv(location, count, values); +} + +void GraphicsHelperES2::glUniform4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform4fv(location, count, values); +} + +void GraphicsHelperES2::glUniform1iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform1iv(location, count, values); +} + +void GraphicsHelperES2::glUniform2iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform2iv(location, count, values); +} + +void GraphicsHelperES2::glUniform3iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform3iv(location, count, values); +} + +void GraphicsHelperES2::glUniform4iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform4iv(location, count, values); +} + +void GraphicsHelperES2::glUniform1uiv(GLint , GLsizei , const GLuint *) +{ + qWarning() << "glUniform1uiv not supported by ES 2"; +} + +void GraphicsHelperES2::glUniform2uiv(GLint , GLsizei , const GLuint *) +{ + qWarning() << "glUniform2uiv not supported by ES 2"; +} + +void GraphicsHelperES2::glUniform3uiv(GLint , GLsizei , const GLuint *) +{ + qWarning() << "glUniform3uiv not supported by ES 2"; +} + +void GraphicsHelperES2::glUniform4uiv(GLint , GLsizei , const GLuint *) +{ + qWarning() << "glUniform4uiv not supported by ES 2"; +} + +void GraphicsHelperES2::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2fv(location, count, false, values); +} + +void GraphicsHelperES2::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3fv(location, count, false, values); +} + +void GraphicsHelperES2::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4fv(location, count, false, values); +} + +void GraphicsHelperES2::glUniformMatrix2x3fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix2x3fv not supported by ES 2"; +} + +void GraphicsHelperES2::glUniformMatrix3x2fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix3x2fv not supported by ES 2"; +} + +void GraphicsHelperES2::glUniformMatrix2x4fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix2x4fv not supported by ES 2"; +} + +void GraphicsHelperES2::glUniformMatrix4x2fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix4x2fv not supported by ES 2"; +} + +void GraphicsHelperES2::glUniformMatrix3x4fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix3x4fv not supported by ES 2"; +} + +void GraphicsHelperES2::glUniformMatrix4x3fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix4x3fv not supported by ES 2"; +} + +UniformType GraphicsHelperES2::uniformTypeFromGLType(GLenum type) +{ + switch (type) { + case GL_FLOAT: + return UniformType::Float; + case GL_FLOAT_VEC2: + return UniformType::Vec2; + case GL_FLOAT_VEC3: + return UniformType::Vec3; + case GL_FLOAT_VEC4: + return UniformType::Vec4; + case GL_FLOAT_MAT2: + return UniformType::Mat2; + case GL_FLOAT_MAT3: + return UniformType::Mat3; + case GL_FLOAT_MAT4: + return UniformType::Mat4; + case GL_INT: + return UniformType::Int; + case GL_INT_VEC2: + return UniformType::IVec2; + case GL_INT_VEC3: + return UniformType::IVec3; + case GL_INT_VEC4: + return UniformType::IVec4; + case GL_BOOL: + return UniformType::Bool; + case GL_BOOL_VEC2: + return UniformType::BVec2; + case GL_BOOL_VEC3: + return UniformType::BVec3; + case GL_BOOL_VEC4: + return UniformType::BVec4; + + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + return UniformType::Sampler; + default: + Q_UNREACHABLE(); + return UniformType::Float; + } +} + +void GraphicsHelperES2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +{ + Q_UNUSED(srcX0); + Q_UNUSED(srcX1); + Q_UNUSED(srcY0); + Q_UNUSED(srcY1); + Q_UNUSED(dstX0); + Q_UNUSED(dstX1); + Q_UNUSED(dstY0); + Q_UNUSED(dstY1); + Q_UNUSED(mask); + Q_UNUSED(filter); + qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)"; +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/graphicshelpers/graphicshelperes2_p.h b/src/render/graphicshelpers/graphicshelperes2_p.h index df8f148a9..17249ef23 100644 --- a/src/render/graphicshelpers/graphicshelperes2_p.h +++ b/src/render/graphicshelpers/graphicshelperes2_p.h @@ -74,10 +74,10 @@ public: void bindFrameBufferObject(GLuint frameBufferId) Q_DECL_OVERRIDE; void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE; void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE; - void bindUniform(const QVariant &v, const ShaderUniform &description) Q_DECL_OVERRIDE; void blendEquation(GLenum mode) Q_DECL_OVERRIDE; void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE; void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE; + void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE; GLuint boundFrameBufferObject() Q_DECL_OVERRIDE; void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE; bool checkFrameBufferComplete() Q_DECL_OVERRIDE; @@ -118,6 +118,34 @@ public: uint uniformByteSize(const ShaderUniform &description) Q_DECL_OVERRIDE; void useProgram(GLuint programId) Q_DECL_OVERRIDE; void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE; + + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + void glUniform1iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform2iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform3iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform4iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + + void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + + void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + UniformType uniformTypeFromGLType(GLenum glType) Q_DECL_OVERRIDE; + protected: QOpenGLFunctions *m_funcs; }; diff --git a/src/render/graphicshelpers/graphicshelperes3.cpp b/src/render/graphicshelpers/graphicshelperes3.cpp index fe39d9d3f..fcd0a2ad2 100644 --- a/src/render/graphicshelpers/graphicshelperes3.cpp +++ b/src/render/graphicshelpers/graphicshelperes3.cpp @@ -119,8 +119,14 @@ void GraphicsHelperES3::bindFrameBufferAttachment(QOpenGLTexture *texture, const else qCritical() << "Unsupported FBO attachment OpenGL ES 3.0"; + const QOpenGLTexture::Target target = texture->target(); + + if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face == QAbstractTexture::AllFaces) { + qWarning() << "OpenGL ES 3.0 doesn't handle attaching all the faces of a cube map texture at once to an FBO"; + return; + } + texture->bind(); - QOpenGLTexture::Target target = texture->target(); if (target == QOpenGLTexture::Target2D) m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel); else if (target == QOpenGLTexture::TargetCubeMap) @@ -135,6 +141,7 @@ bool GraphicsHelperES3::supportsFeature(GraphicsHelperInterface::Feature feature switch (feature) { case RenderBufferDimensionRetrieval: case MRT: + case BlitFramebuffer: return true; default: return false; @@ -150,23 +157,25 @@ void GraphicsHelperES3::drawBuffers(GLsizei n, const int *bufs) m_extraFuncs->glDrawBuffers(n, drawBufs.constData()); } -void GraphicsHelperES3::bindUniform(const QVariant &v, const ShaderUniform &description) +UniformType GraphicsHelperES3::uniformTypeFromGLType(GLenum glType) { - switch (description.m_type) { + switch (glType) { case GL_SAMPLER_3D: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_2D_ARRAY: case GL_SAMPLER_2D_ARRAY_SHADOW: - Q_ASSERT(description.m_size == 1); - m_funcs->glUniform1i(description.m_location, v.toInt()); - break; + return UniformType::Sampler; default: - GraphicsHelperES2::bindUniform(v, description); - break; + return GraphicsHelperES2::uniformTypeFromGLType(glType); } } +void GraphicsHelperES3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +{ + m_extraFuncs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/graphicshelpers/graphicshelperes3_p.h b/src/render/graphicshelpers/graphicshelperes3_p.h index e5bb51c53..7520328d4 100644 --- a/src/render/graphicshelpers/graphicshelperes3_p.h +++ b/src/render/graphicshelpers/graphicshelperes3_p.h @@ -67,12 +67,15 @@ public: // QGraphicHelperInterface interface virtual void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) Q_DECL_OVERRIDE; - virtual void bindUniform(const QVariant &v, const ShaderUniform &description) Q_DECL_OVERRIDE; + virtual void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE; virtual void drawBuffers(GLsizei n, const int *bufs) Q_DECL_OVERRIDE; virtual void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) Q_DECL_OVERRIDE; virtual void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE; virtual bool supportsFeature(Feature feature) const Q_DECL_OVERRIDE; virtual void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE; + + UniformType uniformTypeFromGLType(GLenum glType) Q_DECL_OVERRIDE; + protected: QOpenGLExtraFunctions *m_extraFuncs = Q_NULLPTR; }; diff --git a/src/render/graphicshelpers/graphicshelpergl2.cpp b/src/render/graphicshelpers/graphicshelpergl2.cpp index a8f6ce510..8ee0c020b 100644 --- a/src/render/graphicshelpers/graphicshelpergl2.cpp +++ b/src/render/graphicshelpers/graphicshelpergl2.cpp @@ -58,7 +58,7 @@ GraphicsHelperGL2::GraphicsHelperGL2() } void GraphicsHelperGL2::initializeHelper(QOpenGLContext *context, - QAbstractOpenGLFunctions *functions) + QAbstractOpenGLFunctions *functions) { Q_UNUSED(context); m_funcs = static_cast<QOpenGLFunctions_2_0*>(functions); @@ -95,9 +95,9 @@ void GraphicsHelperGL2::drawElementsInstancedBaseVertexBaseInstance(GLenum primi } void GraphicsHelperGL2::drawArraysInstanced(GLenum primitiveType, - GLint first, - GLsizei count, - GLsizei instances) + GLint first, + GLsizei count, + GLsizei instances) { for (GLint i = 0; i < instances; i++) drawArrays(primitiveType, @@ -116,10 +116,10 @@ void GraphicsHelperGL2::drawArraysInstancedBaseInstance(GLenum primitiveType, GL } void GraphicsHelperGL2::drawElements(GLenum primitiveType, - GLsizei primitiveCount, - GLint indexType, - void *indices, - GLint baseVertex) + GLsizei primitiveCount, + GLint indexType, + void *indices, + GLint baseVertex) { if (baseVertex != 0) qWarning() << "glDrawElementsBaseVertex is not supported with OpenGL 2"; @@ -131,8 +131,8 @@ void GraphicsHelperGL2::drawElements(GLenum primitiveType, } void GraphicsHelperGL2::drawArrays(GLenum primitiveType, - GLint first, - GLsizei count) + GLint first, + GLsizei count) { m_funcs->glDrawArrays(primitiveType, first, @@ -211,7 +211,7 @@ QVector<ShaderStorageBlock> GraphicsHelperGL2::programShaderStorageBlocks(GLuint } void GraphicsHelperGL2::vertexAttribDivisor(GLuint index, - GLuint divisor) + GLuint divisor) { Q_UNUSED(index); Q_UNUSED(divisor); @@ -316,8 +316,14 @@ void GraphicsHelperGL2::bindFrameBufferAttachment(QOpenGLTexture *texture, const else qCritical() << "DepthStencil Attachment not supported on OpenGL 2.0"; + const QOpenGLTexture::Target target = texture->target(); + + if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face == QAbstractTexture::AllFaces) { + qWarning() << "OpenGL 2.0 doesn't handle attaching all the faces of a cube map texture at once to an FBO"; + return; + } + texture->bind(); - QOpenGLTexture::Target target = texture->target(); if (target == QOpenGLTexture::Target3D) m_fboFuncs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel, attachment.m_layer); else if (target == QOpenGLTexture::TargetCubeMap) @@ -358,98 +364,6 @@ void GraphicsHelperGL2::bindFragDataLocation(GLuint, const QHash<QString, int> & qCritical() << "bindFragDataLocation is not supported by GL 2.0"; } -void GraphicsHelperGL2::bindUniform(const QVariant &v, const ShaderUniform &description) -{ - switch (description.m_type) { - - case GL_FLOAT: - m_funcs->glUniform1fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1)); - break; - - case GL_FLOAT_VEC2: - m_funcs->glUniform2fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2)); - break; - - case GL_FLOAT_VEC3: - m_funcs->glUniform3fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3)); - break; - - case GL_FLOAT_VEC4: - m_funcs->glUniform4fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT2: - m_funcs->glUniformMatrix2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT3: - m_funcs->glUniformMatrix3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9)); - break; - - case GL_FLOAT_MAT4: - m_funcs->glUniformMatrix4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16)); - break; - - case GL_INT: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_INT_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_INT_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_INT_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_BOOL: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_BOOL_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_BOOL_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_BOOL_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_SAMPLER_2D: - case GL_SAMPLER_CUBE: { - Q_ASSERT(description.m_size == 1); - m_funcs->glUniform1i(description.m_location, v.toInt()); - break; - } - - default: - qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name; - break; - } -} - void GraphicsHelperGL2::bindFrameBufferObject(GLuint frameBufferId) { if (m_fboFuncs != nullptr) @@ -550,10 +464,17 @@ uint GraphicsHelperGL2::uniformByteSize(const ShaderUniform &description) case GL_INT: case GL_FLOAT: + case GL_SAMPLER_1D: + case GL_SAMPLER_1D_SHADOW: case GL_SAMPLER_2D: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_3D: case GL_SAMPLER_CUBE: rawByteSize = 4; break; + + default: + Q_UNREACHABLE(); } return arrayStride ? rawByteSize * arrayStride : rawByteSize; @@ -663,6 +584,174 @@ void GraphicsHelperGL2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) qWarning() << "Compute Shaders are not supported by OpenGL 2.0 (since OpenGL 4.3)"; } +void GraphicsHelperGL2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform1fv(location, count, values); +} + +void GraphicsHelperGL2::glUniform2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform2fv(location, count, values); +} + +void GraphicsHelperGL2::glUniform3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform3fv(location, count, values); +} + +void GraphicsHelperGL2::glUniform4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform4fv(location, count, values); +} + +void GraphicsHelperGL2::glUniform1iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform1iv(location, count, values); +} + +void GraphicsHelperGL2::glUniform2iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform2iv(location, count, values); +} + +void GraphicsHelperGL2::glUniform3iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform3iv(location, count, values); +} + +void GraphicsHelperGL2::glUniform4iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform4iv(location, count, values); +} + +void GraphicsHelperGL2::glUniform1uiv(GLint , GLsizei , const GLuint *) +{ + qWarning() << "glUniform1uiv not supported by GL 2"; +} + +void GraphicsHelperGL2::glUniform2uiv(GLint , GLsizei , const GLuint *) +{ + qWarning() << "glUniform2uiv not supported by GL 2"; +} + +void GraphicsHelperGL2::glUniform3uiv(GLint , GLsizei , const GLuint *) +{ + qWarning() << "glUniform3uiv not supported by GL 2"; +} + +void GraphicsHelperGL2::glUniform4uiv(GLint , GLsizei , const GLuint *) +{ + qWarning() << "glUniform4uiv not supported by GL 2"; +} + +void GraphicsHelperGL2::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2fv(location, count, false, values); +} + +void GraphicsHelperGL2::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3fv(location, count, false, values); +} + +void GraphicsHelperGL2::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4fv(location, count, false, values); +} + +void GraphicsHelperGL2::glUniformMatrix2x3fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix2x3fv not supported by GL 2"; +} + +void GraphicsHelperGL2::glUniformMatrix3x2fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix3x2fv not supported by GL 2"; +} + +void GraphicsHelperGL2::glUniformMatrix2x4fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix2x4fv not supported by GL 2"; +} + +void GraphicsHelperGL2::glUniformMatrix4x2fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix4x2fv not supported by GL 2"; +} + +void GraphicsHelperGL2::glUniformMatrix3x4fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix3x4fv not supported by GL 2"; +} + +void GraphicsHelperGL2::glUniformMatrix4x3fv(GLint , GLsizei , const GLfloat *) +{ + qWarning() << "glUniformMatrix4x3fv not supported by GL 2"; +} + +UniformType GraphicsHelperGL2::uniformTypeFromGLType(GLenum type) +{ + switch (type) { + case GL_FLOAT: + return UniformType::Float; + case GL_FLOAT_VEC2: + return UniformType::Vec2; + case GL_FLOAT_VEC3: + return UniformType::Vec3; + case GL_FLOAT_VEC4: + return UniformType::Vec4; + case GL_FLOAT_MAT2: + return UniformType::Mat2; + case GL_FLOAT_MAT3: + return UniformType::Mat3; + case GL_FLOAT_MAT4: + return UniformType::Mat4; + case GL_INT: + return UniformType::Int; + case GL_INT_VEC2: + return UniformType::IVec2; + case GL_INT_VEC3: + return UniformType::IVec3; + case GL_INT_VEC4: + return UniformType::IVec4; + case GL_BOOL: + return UniformType::Bool; + case GL_BOOL_VEC2: + return UniformType::BVec2; + case GL_BOOL_VEC3: + return UniformType::BVec3; + case GL_BOOL_VEC4: + return UniformType::BVec4; + + case GL_SAMPLER_1D: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_3D: + return UniformType::Sampler; + + default: + Q_UNREACHABLE(); + return UniformType::Float; + } +} + +void GraphicsHelperGL2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +{ + Q_UNUSED(srcX0); + Q_UNUSED(srcX1); + Q_UNUSED(srcY0); + Q_UNUSED(srcY1); + Q_UNUSED(dstX0); + Q_UNUSED(dstX1); + Q_UNUSED(dstY0); + Q_UNUSED(dstY1); + Q_UNUSED(mask); + Q_UNUSED(filter); + qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)"; +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/graphicshelpers/graphicshelpergl2_p.h b/src/render/graphicshelpers/graphicshelpergl2_p.h index 719f9c92c..cfd90eab7 100644 --- a/src/render/graphicshelpers/graphicshelpergl2_p.h +++ b/src/render/graphicshelpers/graphicshelpergl2_p.h @@ -63,7 +63,7 @@ class QOpenGLExtension_ARB_framebuffer_object; namespace Qt3DRender { namespace Render { -class GraphicsHelperGL2 : public GraphicsHelperInterface +class Q_AUTOTEST_EXPORT GraphicsHelperGL2 : public GraphicsHelperInterface { public: GraphicsHelperGL2(); @@ -76,10 +76,10 @@ public: void bindFrameBufferObject(GLuint frameBufferId) Q_DECL_OVERRIDE; void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE; void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE; - void bindUniform(const QVariant &v, const ShaderUniform &description) Q_DECL_OVERRIDE; void blendEquation(GLenum mode) Q_DECL_OVERRIDE; void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE; void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE; + void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE; GLuint boundFrameBufferObject() Q_DECL_OVERRIDE; void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE; bool checkFrameBufferComplete() Q_DECL_OVERRIDE; @@ -121,6 +121,33 @@ public: void useProgram(GLuint programId) Q_DECL_OVERRIDE; void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + void glUniform1iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform2iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform3iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform4iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + + void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + + void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + UniformType uniformTypeFromGLType(GLenum glType) Q_DECL_OVERRIDE; + private: QOpenGLFunctions_2_0 *m_funcs; QOpenGLExtension_ARB_framebuffer_object *m_fboFuncs; diff --git a/src/render/graphicshelpers/graphicshelpergl3.cpp b/src/render/graphicshelpers/graphicshelpergl3_2.cpp index 549c665c3..47e9414ca 100644 --- a/src/render/graphicshelpers/graphicshelpergl3.cpp +++ b/src/render/graphicshelpers/graphicshelpergl3_2.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "graphicshelpergl3_p.h" +#include "graphicshelpergl3_2_p.h" #ifndef QT_OPENGL_ES_2 #include <QOpenGLFunctions_3_2_Core> @@ -71,13 +71,17 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { -GraphicsHelperGL3::GraphicsHelperGL3() +GraphicsHelperGL3_2::GraphicsHelperGL3_2() : m_funcs(nullptr) , m_tessFuncs() { } -void GraphicsHelperGL3::initializeHelper(QOpenGLContext *context, +GraphicsHelperGL3_2::~GraphicsHelperGL3_2() +{ +} + +void GraphicsHelperGL3_2::initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) { m_funcs = static_cast<QOpenGLFunctions_3_2_Core*>(functions); @@ -91,7 +95,7 @@ void GraphicsHelperGL3::initializeHelper(QOpenGLContext *context, } } -void GraphicsHelperGL3::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, +void GraphicsHelperGL3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, @@ -111,7 +115,7 @@ void GraphicsHelperGL3::drawElementsInstancedBaseVertexBaseInstance(GLenum primi baseVertex); } -void GraphicsHelperGL3::drawArraysInstanced(GLenum primitiveType, +void GraphicsHelperGL3_2::drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) @@ -123,7 +127,7 @@ void GraphicsHelperGL3::drawArraysInstanced(GLenum primitiveType, instances); } -void GraphicsHelperGL3::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance) +void GraphicsHelperGL3_2::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance) { if (baseInstance != 0) qWarning() << "glDrawArraysInstancedBaseInstance is not supported with OpenGL 3"; @@ -133,7 +137,7 @@ void GraphicsHelperGL3::drawArraysInstancedBaseInstance(GLenum primitiveType, GL instances); } -void GraphicsHelperGL3::drawElements(GLenum primitiveType, +void GraphicsHelperGL3_2::drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, @@ -146,7 +150,7 @@ void GraphicsHelperGL3::drawElements(GLenum primitiveType, baseVertex); } -void GraphicsHelperGL3::drawArrays(GLenum primitiveType, +void GraphicsHelperGL3_2::drawArrays(GLenum primitiveType, GLint first, GLsizei count) { @@ -155,7 +159,7 @@ void GraphicsHelperGL3::drawArrays(GLenum primitiveType, count); } -void GraphicsHelperGL3::setVerticesPerPatch(GLint verticesPerPatch) +void GraphicsHelperGL3_2::setVerticesPerPatch(GLint verticesPerPatch) { #if defined(QT_OPENGL_4) if (!m_tessFuncs) { @@ -170,12 +174,12 @@ void GraphicsHelperGL3::setVerticesPerPatch(GLint verticesPerPatch) #endif } -void GraphicsHelperGL3::useProgram(GLuint programId) +void GraphicsHelperGL3_2::useProgram(GLuint programId) { m_funcs->glUseProgram(programId); } -QVector<ShaderUniform> GraphicsHelperGL3::programUniformsAndLocations(GLuint programId) +QVector<ShaderUniform> GraphicsHelperGL3_2::programUniformsAndLocations(GLuint programId) { QVector<ShaderUniform> uniforms; @@ -207,7 +211,7 @@ QVector<ShaderUniform> GraphicsHelperGL3::programUniformsAndLocations(GLuint pro return uniforms; } -QVector<ShaderAttribute> GraphicsHelperGL3::programAttributesAndLocations(GLuint programId) +QVector<ShaderAttribute> GraphicsHelperGL3_2::programAttributesAndLocations(GLuint programId) { QVector<ShaderAttribute> attributes; GLint nbrActiveAttributes = 0; @@ -229,7 +233,7 @@ QVector<ShaderAttribute> GraphicsHelperGL3::programAttributesAndLocations(GLuint return attributes; } -QVector<ShaderUniformBlock> GraphicsHelperGL3::programUniformBlocks(GLuint programId) +QVector<ShaderUniformBlock> GraphicsHelperGL3_2::programUniformBlocks(GLuint programId) { QVector<ShaderUniformBlock> blocks; GLint nbrActiveUniformsBlocks = 0; @@ -250,7 +254,7 @@ QVector<ShaderUniformBlock> GraphicsHelperGL3::programUniformBlocks(GLuint progr return blocks; } -QVector<ShaderStorageBlock> GraphicsHelperGL3::programShaderStorageBlocks(GLuint programId) +QVector<ShaderStorageBlock> GraphicsHelperGL3_2::programShaderStorageBlocks(GLuint programId) { Q_UNUSED(programId); QVector<ShaderStorageBlock> blocks; @@ -258,19 +262,19 @@ QVector<ShaderStorageBlock> GraphicsHelperGL3::programShaderStorageBlocks(GLuint return blocks; } -void GraphicsHelperGL3::vertexAttribDivisor(GLuint index, GLuint divisor) +void GraphicsHelperGL3_2::vertexAttribDivisor(GLuint index, GLuint divisor) { Q_UNUSED(index); Q_UNUSED(divisor); qCWarning(Render::Rendering) << "Vertex attribute divisor not available with OpenGL 3.2 core"; } -void GraphicsHelperGL3::blendEquation(GLenum mode) +void GraphicsHelperGL3_2::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); } -void GraphicsHelperGL3::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) +void GraphicsHelperGL3_2::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) { Q_UNUSED(buf); Q_UNUSED(sfactor); @@ -279,7 +283,7 @@ void GraphicsHelperGL3::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) qWarning() << "glBlendFunci() not supported by OpenGL 3.0 (since OpenGL 4.0)"; } -void GraphicsHelperGL3::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) +void GraphicsHelperGL3_2::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) { Q_UNUSED(buf); Q_UNUSED(sRGB); @@ -290,70 +294,70 @@ void GraphicsHelperGL3::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, qWarning() << "glBlendFuncSeparatei() not supported by OpenGL 3.0 (since OpenGL 4.0)"; } -void GraphicsHelperGL3::alphaTest(GLenum, GLenum) +void GraphicsHelperGL3_2::alphaTest(GLenum, GLenum) { qCWarning(Render::Rendering) << "AlphaTest not available with OpenGL 3.2 core"; } -void GraphicsHelperGL3::depthTest(GLenum mode) +void GraphicsHelperGL3_2::depthTest(GLenum mode) { m_funcs->glEnable(GL_DEPTH_TEST); m_funcs->glDepthFunc(mode); } -void GraphicsHelperGL3::depthMask(GLenum mode) +void GraphicsHelperGL3_2::depthMask(GLenum mode) { m_funcs->glDepthMask(mode); } -void GraphicsHelperGL3::frontFace(GLenum mode) +void GraphicsHelperGL3_2::frontFace(GLenum mode) { m_funcs->glFrontFace(mode); } -void GraphicsHelperGL3::setMSAAEnabled(bool enabled) +void GraphicsHelperGL3_2::setMSAAEnabled(bool enabled) { enabled ? m_funcs->glEnable(GL_MULTISAMPLE) : m_funcs->glDisable(GL_MULTISAMPLE); } -void GraphicsHelperGL3::setAlphaCoverageEnabled(bool enabled) +void GraphicsHelperGL3_2::setAlphaCoverageEnabled(bool enabled) { enabled ? m_funcs->glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE) : m_funcs->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); } -GLuint GraphicsHelperGL3::createFrameBufferObject() +GLuint GraphicsHelperGL3_2::createFrameBufferObject() { GLuint id; m_funcs->glGenFramebuffers(1, &id); return id; } -void GraphicsHelperGL3::releaseFrameBufferObject(GLuint frameBufferId) +void GraphicsHelperGL3_2::releaseFrameBufferObject(GLuint frameBufferId) { m_funcs->glDeleteFramebuffers(1, &frameBufferId); } -void GraphicsHelperGL3::bindFrameBufferObject(GLuint frameBufferId) +void GraphicsHelperGL3_2::bindFrameBufferObject(GLuint frameBufferId) { m_funcs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferId); } -GLuint GraphicsHelperGL3::boundFrameBufferObject() +GLuint GraphicsHelperGL3_2::boundFrameBufferObject() { GLint id = 0; m_funcs->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &id); return id; } -bool GraphicsHelperGL3::checkFrameBufferComplete() +bool GraphicsHelperGL3_2::checkFrameBufferComplete() { return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); } -void GraphicsHelperGL3::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) +void GraphicsHelperGL3_2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) { GLenum attr = GL_DEPTH_STENCIL_ATTACHMENT; @@ -378,7 +382,7 @@ void GraphicsHelperGL3::bindFrameBufferAttachment(QOpenGLTexture *texture, const texture->release(); } -bool GraphicsHelperGL3::supportsFeature(GraphicsHelperInterface::Feature feature) const +bool GraphicsHelperGL3_2::supportsFeature(GraphicsHelperInterface::Feature feature) const { switch (feature) { case MRT: @@ -386,6 +390,8 @@ bool GraphicsHelperGL3::supportsFeature(GraphicsHelperInterface::Feature feature case PrimitiveRestart: case RenderBufferDimensionRetrieval: case TextureDimensionRetrieval: + case BindableFragmentOutputs: + case BlitFramebuffer: return true; case Tessellation: return !m_tessFuncs.isNull(); @@ -394,7 +400,7 @@ bool GraphicsHelperGL3::supportsFeature(GraphicsHelperInterface::Feature feature } } -void GraphicsHelperGL3::drawBuffers(GLsizei n, const int *bufs) +void GraphicsHelperGL3_2::drawBuffers(GLsizei n, const int *bufs) { // Use QVarLengthArray here QVarLengthArray<GLenum, 16> drawBufs(n); @@ -404,194 +410,18 @@ void GraphicsHelperGL3::drawBuffers(GLsizei n, const int *bufs) m_funcs->glDrawBuffers(n, drawBufs.constData()); } -void GraphicsHelperGL3::bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) +void GraphicsHelperGL3_2::bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) { for (auto it = outputs.begin(), end = outputs.end(); it != end; ++it) m_funcs->glBindFragDataLocation(shader, it.value(), it.key().toStdString().c_str()); } -void GraphicsHelperGL3::bindUniform(const QVariant &v, const ShaderUniform &description) -{ - switch (description.m_type) { - - case GL_FLOAT: - m_funcs->glUniform1fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1)); - break; - - case GL_FLOAT_VEC2: - m_funcs->glUniform2fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2)); - break; - - case GL_FLOAT_VEC3: - m_funcs->glUniform3fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3)); - break; - - case GL_FLOAT_VEC4: - m_funcs->glUniform4fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT2: - m_funcs->glUniformMatrix2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT2x3: - m_funcs->glUniformMatrix2x3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6)); - break; - - case GL_FLOAT_MAT2x4: - m_funcs->glUniformMatrix2x4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8)); - break; - - case GL_FLOAT_MAT3: - m_funcs->glUniformMatrix3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9)); - break; - - case GL_FLOAT_MAT3x2: - m_funcs->glUniformMatrix3x2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6)); - break; - - case GL_FLOAT_MAT3x4: - m_funcs->glUniformMatrix3x4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12)); - break; - - case GL_FLOAT_MAT4: - m_funcs->glUniformMatrix4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16)); - break; - - case GL_FLOAT_MAT4x2: - m_funcs->glUniformMatrix4x2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8)); - break; - - case GL_FLOAT_MAT4x3: - m_funcs->glUniformMatrix4x3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12)); - break; - - case GL_INT: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_INT_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_INT_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_INT_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_UNSIGNED_INT: - m_funcs->glUniform1uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 1)); - break; - - case GL_UNSIGNED_INT_VEC2: - m_funcs->glUniform2uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 2)); - break; - - case GL_UNSIGNED_INT_VEC3: - m_funcs->glUniform3uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 3)); - break; - - case GL_UNSIGNED_INT_VEC4: - m_funcs->glUniform4uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 4)); - break; - - case GL_BOOL: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_BOOL_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_BOOL_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_BOOL_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - case GL_SAMPLER_CUBE: - case GL_SAMPLER_BUFFER: - case GL_SAMPLER_2D_RECT: - case GL_INT_SAMPLER_1D: - case GL_INT_SAMPLER_2D: - case GL_INT_SAMPLER_3D: - case GL_INT_SAMPLER_CUBE: - case GL_INT_SAMPLER_BUFFER: - case GL_INT_SAMPLER_2D_RECT: - case GL_UNSIGNED_INT_SAMPLER_1D: - case GL_UNSIGNED_INT_SAMPLER_2D: - case GL_UNSIGNED_INT_SAMPLER_3D: - case GL_UNSIGNED_INT_SAMPLER_CUBE: - case GL_UNSIGNED_INT_SAMPLER_BUFFER: - case GL_UNSIGNED_INT_SAMPLER_2D_RECT: - case GL_SAMPLER_1D_SHADOW: - case GL_SAMPLER_2D_SHADOW: - case GL_SAMPLER_CUBE_SHADOW: - case GL_SAMPLER_1D_ARRAY: - case GL_SAMPLER_2D_ARRAY: - case GL_INT_SAMPLER_1D_ARRAY: - case GL_INT_SAMPLER_2D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - case GL_SAMPLER_1D_ARRAY_SHADOW: - case GL_SAMPLER_2D_ARRAY_SHADOW: - case GL_SAMPLER_2D_RECT_SHADOW: - case GL_SAMPLER_2D_MULTISAMPLE: - case GL_INT_SAMPLER_2D_MULTISAMPLE: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: - case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: { - Q_ASSERT(description.m_size == 1); - m_funcs->glUniform1i(description.m_location, v.toInt()); - break; - } - - default: - qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name; - break; - } -} - -void GraphicsHelperGL3::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) +void GraphicsHelperGL3_2::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { m_funcs->glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockBinding); } -void GraphicsHelperGL3::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) +void GraphicsHelperGL3_2::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) { Q_UNUSED(programId); Q_UNUSED(shaderStorageBlockIndex); @@ -599,12 +429,12 @@ void GraphicsHelperGL3::bindShaderStorageBlock(GLuint programId, GLuint shaderSt qWarning() << "SSBO are not supported by OpenGL 3.0 (since OpenGL 4.3)"; } -void GraphicsHelperGL3::bindBufferBase(GLenum target, GLuint index, GLuint buffer) +void GraphicsHelperGL3_2::bindBufferBase(GLenum target, GLuint index, GLuint buffer) { m_funcs->glBindBufferBase(target, index, buffer); } -void GraphicsHelperGL3::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) +void GraphicsHelperGL3_2::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) { char *bufferData = buffer.data(); @@ -808,7 +638,7 @@ void GraphicsHelperGL3::buildUniformBuffer(const QVariant &v, const ShaderUnifor } } -uint GraphicsHelperGL3::uniformByteSize(const ShaderUniform &description) +uint GraphicsHelperGL3_2::uniformByteSize(const ShaderUniform &description) { uint rawByteSize = 0; int arrayStride = qMax(description.m_arrayStride, 0); @@ -932,17 +762,17 @@ uint GraphicsHelperGL3::uniformByteSize(const ShaderUniform &description) return arrayStride ? rawByteSize * arrayStride : rawByteSize; } -void GraphicsHelperGL3::enableClipPlane(int clipPlane) +void GraphicsHelperGL3_2::enableClipPlane(int clipPlane) { m_funcs->glEnable(GL_CLIP_DISTANCE0 + clipPlane); } -void GraphicsHelperGL3::disableClipPlane(int clipPlane) +void GraphicsHelperGL3_2::disableClipPlane(int clipPlane) { m_funcs->glDisable(GL_CLIP_DISTANCE0 + clipPlane); } -void GraphicsHelperGL3::setClipPlane(int clipPlane, const QVector3D &normal, float distance) +void GraphicsHelperGL3_2::setClipPlane(int clipPlane, const QVector3D &normal, float distance) { // deprecated Q_UNUSED(clipPlane); @@ -950,31 +780,31 @@ void GraphicsHelperGL3::setClipPlane(int clipPlane, const QVector3D &normal, flo Q_UNUSED(distance); } -GLint GraphicsHelperGL3::maxClipPlaneCount() +GLint GraphicsHelperGL3_2::maxClipPlaneCount() { GLint max = 0; m_funcs->glGetIntegerv(GL_MAX_CLIP_DISTANCES, &max); return max; } -void GraphicsHelperGL3::enablePrimitiveRestart(int primitiveRestartIndex) +void GraphicsHelperGL3_2::enablePrimitiveRestart(int primitiveRestartIndex) { m_funcs->glPrimitiveRestartIndex(primitiveRestartIndex); m_funcs->glEnable(GL_PRIMITIVE_RESTART); } -void GraphicsHelperGL3::disablePrimitiveRestart() +void GraphicsHelperGL3_2::disablePrimitiveRestart() { m_funcs->glDisable(GL_PRIMITIVE_RESTART); } -void GraphicsHelperGL3::clearBufferf(GLint drawbuffer, const QVector4D &values) +void GraphicsHelperGL3_2::clearBufferf(GLint drawbuffer, const QVector4D &values) { GLfloat vec[4] = {values[0], values[1], values[2], values[3]}; m_funcs->glClearBufferfv(GL_COLOR, drawbuffer, vec); } -void GraphicsHelperGL3::pointSize(bool programmable, GLfloat value) +void GraphicsHelperGL3_2::pointSize(bool programmable, GLfloat value) { if (programmable) { m_funcs->glEnable(GL_PROGRAM_POINT_SIZE); @@ -984,23 +814,25 @@ void GraphicsHelperGL3::pointSize(bool programmable, GLfloat value) } } -void GraphicsHelperGL3::enablei(GLenum cap, GLuint index) +void GraphicsHelperGL3_2::enablei(GLenum cap, GLuint index) { m_funcs->glEnablei(cap, index); } -void GraphicsHelperGL3::disablei(GLenum cap, GLuint index) +void GraphicsHelperGL3_2::disablei(GLenum cap, GLuint index) { m_funcs->glDisablei(cap, index); } -void GraphicsHelperGL3::setSeamlessCubemap(bool enable) +void GraphicsHelperGL3_2::setSeamlessCubemap(bool enable) { - Q_UNUSED(enable); - qWarning() << "GL_TEXTURE_CUBE_MAP_SEAMLESS not supported by OpenGL 3.0 (since 3.2)"; + if (enable) + m_funcs->glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + else + m_funcs->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); } -QSize GraphicsHelperGL3::getRenderBufferDimensions(GLuint renderBufferId) +QSize GraphicsHelperGL3_2::getRenderBufferDimensions(GLuint renderBufferId) { GLint width = 0; GLint height = 0; @@ -1013,7 +845,7 @@ QSize GraphicsHelperGL3::getRenderBufferDimensions(GLuint renderBufferId) return QSize(width, height); } -QSize GraphicsHelperGL3::getTextureDimensions(GLuint textureId, GLenum target, uint level) +QSize GraphicsHelperGL3_2::getTextureDimensions(GLuint textureId, GLenum target, uint level) { GLint width = 0; GLint height = 0; @@ -1026,12 +858,216 @@ QSize GraphicsHelperGL3::getTextureDimensions(GLuint textureId, GLenum target, u return QSize(width, height); } -void GraphicsHelperGL3::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) +void GraphicsHelperGL3_2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) { Q_UNUSED(wx); Q_UNUSED(wy); Q_UNUSED(wz); - qWarning() << "Compute Shaders are not supported by OpenGL 3.0 (since OpenGL 4.3)"; + qWarning() << "Compute Shaders are not supported by OpenGL 3.2 (since OpenGL 4.3)"; +} + +void GraphicsHelperGL3_2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform1fv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform2fv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform3fv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform4fv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform1iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform1iv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform2iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform2iv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform3iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform3iv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform4iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform4iv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform1uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform1uiv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform2uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform2uiv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform3uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform3uiv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniform4uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform4uiv(location, count, values); +} + +void GraphicsHelperGL3_2::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2fv(location, count, false, values); +} + +void GraphicsHelperGL3_2::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3fv(location, count, false, values); +} + +void GraphicsHelperGL3_2::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4fv(location, count, false, values); +} + +void GraphicsHelperGL3_2::glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2x3fv(location, count, false, values); +} + +void GraphicsHelperGL3_2::glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3x2fv(location, count, false, values); +} + +void GraphicsHelperGL3_2::glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2x4fv(location, count, false, values); +} + +void GraphicsHelperGL3_2::glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4x2fv(location, count, false, values); +} + +void GraphicsHelperGL3_2::glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3x4fv(location, count, false, values); +} + +void GraphicsHelperGL3_2::glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4x3fv(location, count, false, values); +} + +UniformType GraphicsHelperGL3_2::uniformTypeFromGLType(GLenum type) +{ + switch (type) { + case GL_FLOAT: + return UniformType::Float; + case GL_FLOAT_VEC2: + return UniformType::Vec2; + case GL_FLOAT_VEC3: + return UniformType::Vec3; + case GL_FLOAT_VEC4: + return UniformType::Vec4; + case GL_FLOAT_MAT2: + return UniformType::Mat2; + case GL_FLOAT_MAT3: + return UniformType::Mat3; + case GL_FLOAT_MAT4: + return UniformType::Mat4; + case GL_FLOAT_MAT2x3: + return UniformType::Mat2x3; + case GL_FLOAT_MAT3x2: + return UniformType::Mat3x2; + case GL_FLOAT_MAT2x4: + return UniformType::Mat2x4; + case GL_FLOAT_MAT4x2: + return UniformType::Mat4x2; + case GL_FLOAT_MAT3x4: + return UniformType::Mat3x4; + case GL_FLOAT_MAT4x3: + return UniformType::Mat4x3; + case GL_INT: + return UniformType::Int; + case GL_INT_VEC2: + return UniformType::IVec2; + case GL_INT_VEC3: + return UniformType::IVec3; + case GL_INT_VEC4: + return UniformType::IVec4; + case GL_UNSIGNED_INT: + return UniformType::UInt; + case GL_UNSIGNED_INT_VEC2: + return UniformType::UIVec2; + case GL_UNSIGNED_INT_VEC3: + return UniformType::UIVec3; + case GL_UNSIGNED_INT_VEC4: + return UniformType::UIVec4; + case GL_BOOL: + return UniformType::Bool; + case GL_BOOL_VEC2: + return UniformType::BVec2; + case GL_BOOL_VEC3: + return UniformType::BVec3; + case GL_BOOL_VEC4: + return UniformType::BVec4; + + case GL_SAMPLER_BUFFER: + case GL_SAMPLER_1D: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D: + case GL_SAMPLER_2D_RECT: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_RECT_SHADOW: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_1D_ARRAY: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_BUFFER: + case GL_INT_SAMPLER_1D: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_1D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_BUFFER: + case GL_UNSIGNED_INT_SAMPLER_1D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + return UniformType::Sampler; + default: + Q_UNREACHABLE(); + return UniformType::Float; + } +} + +void GraphicsHelperGL3_2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +{ + m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } } // namespace Render diff --git a/src/render/graphicshelpers/graphicshelpergl3_p.h b/src/render/graphicshelpers/graphicshelpergl3_2_p.h index 721078130..1ee716a76 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_p.h +++ b/src/render/graphicshelpers/graphicshelpergl3_2_p.h @@ -64,10 +64,11 @@ class QOpenGLExtension_ARB_tessellation_shader; namespace Qt3DRender { namespace Render { -class GraphicsHelperGL3 : public GraphicsHelperInterface +class Q_AUTOTEST_EXPORT GraphicsHelperGL3_2 : public GraphicsHelperInterface { public: - GraphicsHelperGL3(); + GraphicsHelperGL3_2(); + ~GraphicsHelperGL3_2(); // QGraphicHelperInterface interface void alphaTest(GLenum mode1, GLenum mode2) Q_DECL_OVERRIDE; @@ -77,10 +78,10 @@ public: void bindFrameBufferObject(GLuint frameBufferId) Q_DECL_OVERRIDE; void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE; void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE; - void bindUniform(const QVariant &v, const ShaderUniform &description) Q_DECL_OVERRIDE; void blendEquation(GLenum mode) Q_DECL_OVERRIDE; void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE; void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE; + void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE; GLuint boundFrameBufferObject() Q_DECL_OVERRIDE; void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE; bool checkFrameBufferComplete() Q_DECL_OVERRIDE; @@ -122,6 +123,33 @@ public: void useProgram(GLuint programId) Q_DECL_OVERRIDE; void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + void glUniform1iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform2iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform3iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform4iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + + void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + + void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + UniformType uniformTypeFromGLType(GLenum glType) Q_DECL_OVERRIDE; + private: QOpenGLFunctions_3_2_Core *m_funcs; QScopedPointer<QOpenGLExtension_ARB_tessellation_shader> m_tessFuncs; diff --git a/src/render/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/graphicshelpers/graphicshelpergl3_3.cpp index fe257ce27..7f0223af2 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_3.cpp +++ b/src/render/graphicshelpers/graphicshelpergl3_3.cpp @@ -76,6 +76,10 @@ GraphicsHelperGL3_3::GraphicsHelperGL3_3() { } +GraphicsHelperGL3_3::~GraphicsHelperGL3_3() +{ +} + void GraphicsHelperGL3_3::initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) { @@ -368,7 +372,7 @@ void GraphicsHelperGL3_3::bindFrameBufferAttachment(QOpenGLTexture *texture, con m_funcs->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel, attachment.m_layer); else if (target == QOpenGLTexture::TargetCubeMapArray) m_funcs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel, attachment.m_layer); - else if (target == QOpenGLTexture::TargetCubeMap) + else if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face != QAbstractTexture::AllFaces) m_funcs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel); else m_funcs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel); @@ -383,6 +387,8 @@ bool GraphicsHelperGL3_3::supportsFeature(GraphicsHelperInterface::Feature featu case PrimitiveRestart: case RenderBufferDimensionRetrieval: case TextureDimensionRetrieval: + case BindableFragmentOutputs: + case BlitFramebuffer: return true; case Tessellation: return !m_tessFuncs.isNull(); @@ -407,182 +413,6 @@ void GraphicsHelperGL3_3::bindFragDataLocation(GLuint shader, const QHash<QStrin m_funcs->glBindFragDataLocation(shader, it.value(), it.key().toStdString().c_str()); } -void GraphicsHelperGL3_3::bindUniform(const QVariant &v, const ShaderUniform &description) -{ - switch (description.m_type) { - - case GL_FLOAT: - m_funcs->glUniform1fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1)); - break; - - case GL_FLOAT_VEC2: - m_funcs->glUniform2fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2)); - break; - - case GL_FLOAT_VEC3: - m_funcs->glUniform3fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3)); - break; - - case GL_FLOAT_VEC4: - m_funcs->glUniform4fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT2: - m_funcs->glUniformMatrix2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT2x3: - m_funcs->glUniformMatrix2x3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6)); - break; - - case GL_FLOAT_MAT2x4: - m_funcs->glUniformMatrix2x4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8)); - break; - - case GL_FLOAT_MAT3: - m_funcs->glUniformMatrix3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9)); - break; - - case GL_FLOAT_MAT3x2: - m_funcs->glUniformMatrix3x2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6)); - break; - - case GL_FLOAT_MAT3x4: - m_funcs->glUniformMatrix3x4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12)); - break; - - case GL_FLOAT_MAT4: - m_funcs->glUniformMatrix4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16)); - break; - - case GL_FLOAT_MAT4x2: - m_funcs->glUniformMatrix4x2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8)); - break; - - case GL_FLOAT_MAT4x3: - m_funcs->glUniformMatrix4x3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12)); - break; - - case GL_INT: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_INT_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_INT_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_INT_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_UNSIGNED_INT: - m_funcs->glUniform1uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 1)); - break; - - case GL_UNSIGNED_INT_VEC2: - m_funcs->glUniform2uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 2)); - break; - - case GL_UNSIGNED_INT_VEC3: - m_funcs->glUniform3uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 3)); - break; - - case GL_UNSIGNED_INT_VEC4: - m_funcs->glUniform4uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 4)); - break; - - case GL_BOOL: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_BOOL_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_BOOL_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_BOOL_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - case GL_SAMPLER_CUBE: - case GL_SAMPLER_BUFFER: - case GL_SAMPLER_2D_RECT: - case GL_INT_SAMPLER_1D: - case GL_INT_SAMPLER_2D: - case GL_INT_SAMPLER_3D: - case GL_INT_SAMPLER_CUBE: - case GL_INT_SAMPLER_BUFFER: - case GL_INT_SAMPLER_2D_RECT: - case GL_UNSIGNED_INT_SAMPLER_1D: - case GL_UNSIGNED_INT_SAMPLER_2D: - case GL_UNSIGNED_INT_SAMPLER_3D: - case GL_UNSIGNED_INT_SAMPLER_CUBE: - case GL_UNSIGNED_INT_SAMPLER_BUFFER: - case GL_UNSIGNED_INT_SAMPLER_2D_RECT: - case GL_SAMPLER_1D_SHADOW: - case GL_SAMPLER_2D_SHADOW: - case GL_SAMPLER_CUBE_SHADOW: - case GL_SAMPLER_1D_ARRAY: - case GL_SAMPLER_2D_ARRAY: - case GL_INT_SAMPLER_1D_ARRAY: - case GL_INT_SAMPLER_2D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - case GL_SAMPLER_1D_ARRAY_SHADOW: - case GL_SAMPLER_2D_ARRAY_SHADOW: - case GL_SAMPLER_2D_RECT_SHADOW: - case GL_SAMPLER_2D_MULTISAMPLE: - case GL_INT_SAMPLER_2D_MULTISAMPLE: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: - case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: { - Q_ASSERT(description.m_size == 1); - m_funcs->glUniform1i(description.m_location, v.toInt()); - break; - } - - default: - qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name; - break; - } -} - void GraphicsHelperGL3_3::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { m_funcs->glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockBinding); @@ -1033,6 +863,210 @@ void GraphicsHelperGL3_3::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) qWarning() << "Compute Shaders are not supported by OpenGL 3.3 (since OpenGL 4.3)"; } +void GraphicsHelperGL3_3::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform1fv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform2fv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform3fv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform4fv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform1iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform1iv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform2iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform2iv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform3iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform3iv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform4iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform4iv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform1uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform1uiv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform2uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform2uiv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform3uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform3uiv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniform4uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform4uiv(location, count, values); +} + +void GraphicsHelperGL3_3::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2fv(location, count, false, values); +} + +void GraphicsHelperGL3_3::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3fv(location, count, false, values); +} + +void GraphicsHelperGL3_3::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4fv(location, count, false, values); +} + +void GraphicsHelperGL3_3::glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2x3fv(location, count, false, values); +} + +void GraphicsHelperGL3_3::glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3x2fv(location, count, false, values); +} + +void GraphicsHelperGL3_3::glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2x4fv(location, count, false, values); +} + +void GraphicsHelperGL3_3::glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4x2fv(location, count, false, values); +} + +void GraphicsHelperGL3_3::glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3x4fv(location, count, false, values); +} + +void GraphicsHelperGL3_3::glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4x3fv(location, count, false, values); +} + +UniformType GraphicsHelperGL3_3::uniformTypeFromGLType(GLenum type) +{ + switch (type) { + case GL_FLOAT: + return UniformType::Float; + case GL_FLOAT_VEC2: + return UniformType::Vec2; + case GL_FLOAT_VEC3: + return UniformType::Vec3; + case GL_FLOAT_VEC4: + return UniformType::Vec4; + case GL_FLOAT_MAT2: + return UniformType::Mat2; + case GL_FLOAT_MAT3: + return UniformType::Mat3; + case GL_FLOAT_MAT4: + return UniformType::Mat4; + case GL_FLOAT_MAT2x3: + return UniformType::Mat2x3; + case GL_FLOAT_MAT3x2: + return UniformType::Mat3x2; + case GL_FLOAT_MAT2x4: + return UniformType::Mat2x4; + case GL_FLOAT_MAT4x2: + return UniformType::Mat4x2; + case GL_FLOAT_MAT3x4: + return UniformType::Mat3x4; + case GL_FLOAT_MAT4x3: + return UniformType::Mat4x3; + case GL_INT: + return UniformType::Int; + case GL_INT_VEC2: + return UniformType::IVec2; + case GL_INT_VEC3: + return UniformType::IVec3; + case GL_INT_VEC4: + return UniformType::IVec4; + case GL_UNSIGNED_INT: + return UniformType::UInt; + case GL_UNSIGNED_INT_VEC2: + return UniformType::UIVec2; + case GL_UNSIGNED_INT_VEC3: + return UniformType::UIVec3; + case GL_UNSIGNED_INT_VEC4: + return UniformType::UIVec4; + case GL_BOOL: + return UniformType::Bool; + case GL_BOOL_VEC2: + return UniformType::BVec2; + case GL_BOOL_VEC3: + return UniformType::BVec3; + case GL_BOOL_VEC4: + return UniformType::BVec4; + + case GL_SAMPLER_BUFFER: + case GL_SAMPLER_1D: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_1D_ARRAY: + case GL_SAMPLER_2D: + case GL_SAMPLER_2D_RECT: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_RECT_SHADOW: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_BUFFER: + case GL_INT_SAMPLER_1D: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_1D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_BUFFER: + case GL_UNSIGNED_INT_SAMPLER_1D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + return UniformType::Sampler; + default: + Q_UNREACHABLE(); + return UniformType::Float; + } +} + +void GraphicsHelperGL3_3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +{ + m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/graphicshelpers/graphicshelpergl3_3_p.h index bb6946a20..b2ea8abca 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_3_p.h +++ b/src/render/graphicshelpers/graphicshelpergl3_3_p.h @@ -64,10 +64,11 @@ class QOpenGLExtension_ARB_tessellation_shader; namespace Qt3DRender { namespace Render { -class GraphicsHelperGL3_3 : public GraphicsHelperInterface +class Q_AUTOTEST_EXPORT GraphicsHelperGL3_3 : public GraphicsHelperInterface { public: GraphicsHelperGL3_3(); + ~GraphicsHelperGL3_3(); // QGraphicHelperInterface interface void alphaTest(GLenum mode1, GLenum mode2) Q_DECL_OVERRIDE; @@ -77,10 +78,10 @@ public: void bindFrameBufferObject(GLuint frameBufferId) Q_DECL_OVERRIDE; void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE; void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE; - void bindUniform(const QVariant &v, const ShaderUniform &description) Q_DECL_OVERRIDE; void blendEquation(GLenum mode) Q_DECL_OVERRIDE; void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE; void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE; + void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE; GLuint boundFrameBufferObject() Q_DECL_OVERRIDE; void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE; bool checkFrameBufferComplete() Q_DECL_OVERRIDE; @@ -122,6 +123,33 @@ public: void useProgram(GLuint programId) Q_DECL_OVERRIDE; void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + void glUniform1iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform2iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform3iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform4iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + + void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + + void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + UniformType uniformTypeFromGLType(GLenum glType) Q_DECL_OVERRIDE; + private: QOpenGLFunctions_3_3_Core *m_funcs; QScopedPointer<QOpenGLExtension_ARB_tessellation_shader> m_tessFuncs; diff --git a/src/render/graphicshelpers/graphicshelpergl4.cpp b/src/render/graphicshelpers/graphicshelpergl4.cpp index 6d7a3b5b1..81a6846e0 100644 --- a/src/render/graphicshelpers/graphicshelpergl4.cpp +++ b/src/render/graphicshelpers/graphicshelpergl4.cpp @@ -266,6 +266,210 @@ void GraphicsHelperGL4::vertexAttribDivisor(GLuint index, GLuint divisor) m_funcs->glVertexAttribDivisor(index, divisor); } +void GraphicsHelperGL4::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform1fv(location, count, values); +} + +void GraphicsHelperGL4::glUniform2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform2fv(location, count, values); +} + +void GraphicsHelperGL4::glUniform3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform3fv(location, count, values); +} + +void GraphicsHelperGL4::glUniform4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniform4fv(location, count, values); +} + +void GraphicsHelperGL4::glUniform1iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform1iv(location, count, values); +} + +void GraphicsHelperGL4::glUniform2iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform2iv(location, count, values); +} + +void GraphicsHelperGL4::glUniform3iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform3iv(location, count, values); +} + +void GraphicsHelperGL4::glUniform4iv(GLint location, GLsizei count, const GLint *values) +{ + m_funcs->glUniform4iv(location, count, values); +} + +void GraphicsHelperGL4::glUniform1uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform1uiv(location, count, values); +} + +void GraphicsHelperGL4::glUniform2uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform2uiv(location, count, values); +} + +void GraphicsHelperGL4::glUniform3uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform3uiv(location, count, values); +} + +void GraphicsHelperGL4::glUniform4uiv(GLint location, GLsizei count, const GLuint *values) +{ + m_funcs->glUniform4uiv(location, count, values); +} + +void GraphicsHelperGL4::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2fv(location, count, false, values); +} + +void GraphicsHelperGL4::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3fv(location, count, false, values); +} + +void GraphicsHelperGL4::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4fv(location, count, false, values); +} + +void GraphicsHelperGL4::glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2x3fv(location, count, false, values); +} + +void GraphicsHelperGL4::glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3x2fv(location, count, false, values); +} + +void GraphicsHelperGL4::glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix2x4fv(location, count, false, values); +} + +void GraphicsHelperGL4::glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4x2fv(location, count, false, values); +} + +void GraphicsHelperGL4::glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix3x4fv(location, count, false, values); +} + +void GraphicsHelperGL4::glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *values) +{ + m_funcs->glUniformMatrix4x3fv(location, count, false, values); +} + +UniformType GraphicsHelperGL4::uniformTypeFromGLType(GLenum type) +{ + switch (type) { + case GL_FLOAT: + return UniformType::Float; + case GL_FLOAT_VEC2: + return UniformType::Vec2; + case GL_FLOAT_VEC3: + return UniformType::Vec3; + case GL_FLOAT_VEC4: + return UniformType::Vec4; + case GL_FLOAT_MAT2: + return UniformType::Mat2; + case GL_FLOAT_MAT3: + return UniformType::Mat3; + case GL_FLOAT_MAT4: + return UniformType::Mat4; + case GL_FLOAT_MAT2x3: + return UniformType::Mat2x3; + case GL_FLOAT_MAT3x2: + return UniformType::Mat3x2; + case GL_FLOAT_MAT2x4: + return UniformType::Mat2x4; + case GL_FLOAT_MAT4x2: + return UniformType::Mat4x2; + case GL_FLOAT_MAT3x4: + return UniformType::Mat3x4; + case GL_FLOAT_MAT4x3: + return UniformType::Mat4x3; + case GL_INT: + return UniformType::Int; + case GL_INT_VEC2: + return UniformType::IVec2; + case GL_INT_VEC3: + return UniformType::IVec3; + case GL_INT_VEC4: + return UniformType::IVec4; + case GL_UNSIGNED_INT: + return UniformType::UInt; + case GL_UNSIGNED_INT_VEC2: + return UniformType::UIVec2; + case GL_UNSIGNED_INT_VEC3: + return UniformType::UIVec3; + case GL_UNSIGNED_INT_VEC4: + return UniformType::UIVec4; + case GL_BOOL: + return UniformType::Bool; + case GL_BOOL_VEC2: + return UniformType::BVec2; + case GL_BOOL_VEC3: + return UniformType::BVec3; + case GL_BOOL_VEC4: + return UniformType::BVec4; + + case GL_SAMPLER_1D: + case GL_SAMPLER_1D_ARRAY: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D: + case GL_SAMPLER_2D_RECT: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_RECT_SHADOW: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_CUBE_MAP_ARRAY: + case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_SAMPLER_3D: + case GL_SAMPLER_BUFFER: + case GL_INT_SAMPLER_1D: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_BUFFER: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_CUBE_MAP_ARRAY: + case GL_INT_SAMPLER_1D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_1D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_BUFFER: + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY: + return UniformType::Sampler; + default: + // TO DO: Add support for Doubles and Images + Q_UNREACHABLE(); + return UniformType::Float; + } +} + void GraphicsHelperGL4::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); @@ -362,7 +566,7 @@ void GraphicsHelperGL4::bindFrameBufferAttachment(QOpenGLTexture *texture, const m_funcs->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel, attachment.m_layer); else if (target == QOpenGLTexture::TargetCubeMapArray) m_funcs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel, attachment.m_layer); - else if (target == QOpenGLTexture::TargetCubeMap) + else if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face != QAbstractTexture::AllFaces) m_funcs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel); else m_funcs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel); @@ -375,11 +579,14 @@ bool GraphicsHelperGL4::supportsFeature(GraphicsHelperInterface::Feature feature case MRT: case Tessellation: case UniformBufferObject: + case BindableFragmentOutputs: + case PrimitiveRestart: case RenderBufferDimensionRetrieval: case TextureDimensionRetrieval: case ShaderStorageObject: case Compute: case DrawBuffersBlend: + case BlitFramebuffer: return true; default: return false; @@ -402,182 +609,6 @@ void GraphicsHelperGL4::bindFragDataLocation(GLuint shader, const QHash<QString, m_funcs->glBindFragDataLocation(shader, it.value(), it.key().toStdString().c_str()); } -void GraphicsHelperGL4::bindUniform(const QVariant &v, const ShaderUniform &description) -{ - switch (description.m_type) { - - case GL_FLOAT: - m_funcs->glUniform1fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1)); - break; - - case GL_FLOAT_VEC2: - m_funcs->glUniform2fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2)); - break; - - case GL_FLOAT_VEC3: - m_funcs->glUniform3fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3)); - break; - - case GL_FLOAT_VEC4: - m_funcs->glUniform4fv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT2: - m_funcs->glUniformMatrix2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4)); - break; - - case GL_FLOAT_MAT2x3: - m_funcs->glUniformMatrix2x3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6)); - break; - - case GL_FLOAT_MAT2x4: - m_funcs->glUniformMatrix2x4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8)); - break; - - case GL_FLOAT_MAT3: - m_funcs->glUniformMatrix3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9)); - break; - - case GL_FLOAT_MAT3x2: - m_funcs->glUniformMatrix3x2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6)); - break; - - case GL_FLOAT_MAT3x4: - m_funcs->glUniformMatrix3x4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12)); - break; - - case GL_FLOAT_MAT4: - m_funcs->glUniformMatrix4fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16)); - break; - - case GL_FLOAT_MAT4x2: - m_funcs->glUniformMatrix4x2fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8)); - break; - - case GL_FLOAT_MAT4x3: - m_funcs->glUniformMatrix4x3fv(description.m_location, description.m_size, GL_FALSE, - QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12)); - break; - - case GL_INT: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_INT_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_INT_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_INT_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_UNSIGNED_INT: - m_funcs->glUniform1uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 1)); - break; - - case GL_UNSIGNED_INT_VEC2: - m_funcs->glUniform2uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 2)); - break; - - case GL_UNSIGNED_INT_VEC3: - m_funcs->glUniform3uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 3)); - break; - - case GL_UNSIGNED_INT_VEC4: - m_funcs->glUniform4uiv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 4)); - break; - - case GL_BOOL: - m_funcs->glUniform1iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1)); - break; - - case GL_BOOL_VEC2: - m_funcs->glUniform2iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2)); - break; - - case GL_BOOL_VEC3: - m_funcs->glUniform3iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3)); - break; - - case GL_BOOL_VEC4: - m_funcs->glUniform4iv(description.m_location, description.m_size, - QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4)); - break; - - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - case GL_SAMPLER_CUBE: - case GL_SAMPLER_BUFFER: - case GL_SAMPLER_2D_RECT: - case GL_INT_SAMPLER_1D: - case GL_INT_SAMPLER_2D: - case GL_INT_SAMPLER_3D: - case GL_INT_SAMPLER_CUBE: - case GL_INT_SAMPLER_BUFFER: - case GL_INT_SAMPLER_2D_RECT: - case GL_UNSIGNED_INT_SAMPLER_1D: - case GL_UNSIGNED_INT_SAMPLER_2D: - case GL_UNSIGNED_INT_SAMPLER_3D: - case GL_UNSIGNED_INT_SAMPLER_CUBE: - case GL_UNSIGNED_INT_SAMPLER_BUFFER: - case GL_UNSIGNED_INT_SAMPLER_2D_RECT: - case GL_SAMPLER_1D_SHADOW: - case GL_SAMPLER_2D_SHADOW: - case GL_SAMPLER_CUBE_SHADOW: - case GL_SAMPLER_1D_ARRAY: - case GL_SAMPLER_2D_ARRAY: - case GL_INT_SAMPLER_1D_ARRAY: - case GL_INT_SAMPLER_2D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - case GL_SAMPLER_1D_ARRAY_SHADOW: - case GL_SAMPLER_2D_ARRAY_SHADOW: - case GL_SAMPLER_2D_RECT_SHADOW: - case GL_SAMPLER_2D_MULTISAMPLE: - case GL_INT_SAMPLER_2D_MULTISAMPLE: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: - case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: { - Q_ASSERT(description.m_size == 1); - m_funcs->glUniform1i(description.m_location, v.toInt()); - break; - } - - default: - qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name; - break; - } -} - void GraphicsHelperGL4::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { m_funcs->glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockBinding); @@ -1019,6 +1050,11 @@ void GraphicsHelperGL4::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) m_funcs->glDispatchCompute(wx, wy, wz); } +void GraphicsHelperGL4::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +{ + m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/graphicshelpers/graphicshelpergl4_p.h b/src/render/graphicshelpers/graphicshelpergl4_p.h index 38a01e271..1f2111419 100644 --- a/src/render/graphicshelpers/graphicshelpergl4_p.h +++ b/src/render/graphicshelpers/graphicshelpergl4_p.h @@ -63,7 +63,7 @@ class QOpenGLFunctions_4_3_Core; namespace Qt3DRender { namespace Render { -class GraphicsHelperGL4 : public GraphicsHelperInterface +class Q_AUTOTEST_EXPORT GraphicsHelperGL4 : public GraphicsHelperInterface { public: GraphicsHelperGL4(); @@ -76,10 +76,10 @@ public: void bindFrameBufferObject(GLuint frameBufferId) Q_DECL_OVERRIDE; void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE; void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE; - void bindUniform(const QVariant &v, const ShaderUniform &description) Q_DECL_OVERRIDE; void blendEquation(GLenum mode) Q_DECL_OVERRIDE; void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE; void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE; + void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE; GLuint boundFrameBufferObject() Q_DECL_OVERRIDE; void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE; bool checkFrameBufferComplete() Q_DECL_OVERRIDE; @@ -121,6 +121,33 @@ public: void useProgram(GLuint programId) Q_DECL_OVERRIDE; void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + void glUniform1iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform2iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform3iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + void glUniform4iv(GLint location, GLsizei count, const GLint *value) Q_DECL_OVERRIDE; + + void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) Q_DECL_OVERRIDE; + + void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE; + + UniformType uniformTypeFromGLType(GLenum glType) Q_DECL_OVERRIDE; + private: QOpenGLFunctions_4_3_Core *m_funcs; }; diff --git a/src/render/graphicshelpers/graphicshelperinterface_p.h b/src/render/graphicshelpers/graphicshelperinterface_p.h index 6e7caee6a..a22ea0274 100644 --- a/src/render/graphicshelpers/graphicshelperinterface_p.h +++ b/src/render/graphicshelpers/graphicshelperinterface_p.h @@ -55,6 +55,7 @@ #include <QOpenGLTexture> #include <QVector> #include <Qt3DRender/private/shadervariables_p.h> +#include <Qt3DRender/private/uniform_p.h> QT_BEGIN_NAMESPACE @@ -76,7 +77,8 @@ public: TextureDimensionRetrieval, ShaderStorageObject, Compute, - DrawBuffersBlend + DrawBuffersBlend, + BlitFramebuffer }; virtual ~GraphicsHelperInterface() {} @@ -87,10 +89,10 @@ public: virtual void bindFrameBufferObject(GLuint frameBufferId) = 0; virtual void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) = 0; virtual void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0; - virtual void bindUniform(const QVariant &v, const ShaderUniform &description) = 0; virtual void blendEquation(GLenum mode) = 0; virtual void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) = 0; virtual void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) = 0; + virtual void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) = 0; virtual GLuint boundFrameBufferObject() = 0; virtual void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) = 0; virtual bool checkFrameBufferComplete() = 0; @@ -131,6 +133,33 @@ public: virtual uint uniformByteSize(const ShaderUniform &description) = 0; virtual void useProgram(GLuint programId) = 0; virtual void vertexAttribDivisor(GLuint index, GLuint divisor) = 0; + + virtual void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) = 0; + + virtual void glUniform1iv(GLint location, GLsizei count, const GLint *value) = 0; + virtual void glUniform2iv(GLint location, GLsizei count, const GLint *value) = 0; + virtual void glUniform3iv(GLint location, GLsizei count, const GLint *value) = 0; + virtual void glUniform4iv(GLint location, GLsizei count, const GLint *value) = 0; + + virtual void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) = 0; + virtual void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) = 0; + virtual void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) = 0; + virtual void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) = 0; + + virtual void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) = 0; + virtual void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) = 0; + + virtual UniformType uniformTypeFromGLType(GLenum glType) = 0; }; diff --git a/src/render/graphicshelpers/graphicshelpers.pri b/src/render/graphicshelpers/graphicshelpers.pri index ecf2e6b54..e9c5c1bc8 100644 --- a/src/render/graphicshelpers/graphicshelpers.pri +++ b/src/render/graphicshelpers/graphicshelpers.pri @@ -8,15 +8,15 @@ HEADERS += \ $$PWD/graphicshelperes2_p.h \ $$PWD/graphicshelperes3_p.h \ $$PWD/graphicshelpergl2_p.h \ - $$PWD/graphicshelpergl3_p.h \ $$PWD/graphicshelpergl3_3_p.h \ - $$PWD/graphicshelpergl4_p.h + $$PWD/graphicshelpergl4_p.h \ + $$PWD/graphicshelpergl3_2_p.h SOURCES += \ $$PWD/graphicscontext.cpp \ $$PWD/graphicshelperes2.cpp \ $$PWD/graphicshelperes3.cpp \ $$PWD/graphicshelpergl2.cpp \ - $$PWD/graphicshelpergl3.cpp \ $$PWD/graphicshelpergl3_3.cpp \ - $$PWD/graphicshelpergl4.cpp + $$PWD/graphicshelpergl4.cpp \ + $$PWD/graphicshelpergl3_2.cpp diff --git a/src/render/io/qsceneiohandler_p.h b/src/render/io/qsceneiohandler_p.h index c6f65ea82..ebebc440d 100644 --- a/src/render/io/qsceneiohandler_p.h +++ b/src/render/io/qsceneiohandler_p.h @@ -80,7 +80,7 @@ public: Loaded, Error }; - Q_ENUM(ParserStatus) + Q_ENUM(ParserStatus) // LCOV_EXCL_LINE QSceneIOHandler(); virtual ~QSceneIOHandler(); diff --git a/src/render/io/qsceneloader.h b/src/render/io/qsceneloader.h index 43d97ec51..fe75185ae 100644 --- a/src/render/io/qsceneloader.h +++ b/src/render/io/qsceneloader.h @@ -67,7 +67,7 @@ public: Ready, Error }; - Q_ENUM(Status) + Q_ENUM(Status) // LCOV_EXCL_LINE QUrl source() const; Status status() const; diff --git a/src/render/jobs/calcboundingvolumejob_p.h b/src/render/jobs/calcboundingvolumejob_p.h index c507f7f2d..cd09aa37b 100644 --- a/src/render/jobs/calcboundingvolumejob_p.h +++ b/src/render/jobs/calcboundingvolumejob_p.h @@ -72,8 +72,6 @@ public: void setRoot(Entity *node); void setManagers(NodeManagers *manager); - -protected: void run() Q_DECL_OVERRIDE; private: diff --git a/src/render/jobs/calcgeometrytrianglevolumes_p.h b/src/render/jobs/calcgeometrytrianglevolumes_p.h index 96c9854d9..4b77d6f5e 100644 --- a/src/render/jobs/calcgeometrytrianglevolumes_p.h +++ b/src/render/jobs/calcgeometrytrianglevolumes_p.h @@ -67,8 +67,6 @@ class Q_AUTOTEST_EXPORT CalcGeometryTriangleVolumes : public Qt3DCore::QAspectJo { public: explicit CalcGeometryTriangleVolumes(const Qt3DCore::QNodeId geometryRendererId, NodeManagers *manager); - -protected: void run() Q_DECL_OVERRIDE; private: diff --git a/src/render/jobs/expandboundingvolumejob_p.h b/src/render/jobs/expandboundingvolumejob_p.h index d20722eb8..2153e3035 100644 --- a/src/render/jobs/expandboundingvolumejob_p.h +++ b/src/render/jobs/expandboundingvolumejob_p.h @@ -69,8 +69,6 @@ public: ExpandBoundingVolumeJob(); void setRoot(Entity *root); - -protected: void run() Q_DECL_OVERRIDE; private: diff --git a/src/render/jobs/filterlayerentityjob.cpp b/src/render/jobs/filterlayerentityjob.cpp index d22b61337..668193fd0 100644 --- a/src/render/jobs/filterlayerentityjob.cpp +++ b/src/render/jobs/filterlayerentityjob.cpp @@ -49,13 +49,9 @@ namespace Qt3DRender { namespace Render { -#ifdef QT3D_JOBS_RUN_STATS namespace { - int layerFilterJobCounter = 0; - } // anonymous -#endif FilterLayerEntityJob::FilterLayerEntityJob() : Qt3DCore::QAspectJob() diff --git a/src/render/jobs/filterlayerentityjob_p.h b/src/render/jobs/filterlayerentityjob_p.h index 26084e44a..50b988ce4 100644 --- a/src/render/jobs/filterlayerentityjob_p.h +++ b/src/render/jobs/filterlayerentityjob_p.h @@ -53,6 +53,7 @@ #include <Qt3DCore/qaspectjob.h> #include <Qt3DCore/qnodeid.h> +#include <Qt3DRender/private/qt3drender_global_p.h> QT_BEGIN_NAMESPACE @@ -63,7 +64,7 @@ namespace Render { class Entity; class NodeManagers; -class Q_AUTOTEST_EXPORT FilterLayerEntityJob : public Qt3DCore::QAspectJob +class QT3DRENDERSHARED_PRIVATE_EXPORT FilterLayerEntityJob : public Qt3DCore::QAspectJob { public: FilterLayerEntityJob(); @@ -73,6 +74,9 @@ public: inline void setHasLayerFilter(bool hasLayerFilter) Q_DECL_NOEXCEPT { m_hasLayerFilter = hasLayerFilter; } inline QVector<Entity *> filteredEntities() const Q_DECL_NOEXCEPT { return m_filteredEntities; } + inline bool hasLayerFilter() const Q_DECL_NOTHROW { return m_hasLayerFilter; } + inline Qt3DCore::QNodeIdVector layers() const { return m_layerIds; } + // QAspectJob interface void run() Q_DECL_FINAL; diff --git a/src/render/jobs/framecleanupjob.cpp b/src/render/jobs/framecleanupjob.cpp index ab3a18223..3105f547c 100644 --- a/src/render/jobs/framecleanupjob.cpp +++ b/src/render/jobs/framecleanupjob.cpp @@ -73,10 +73,6 @@ void FrameCleanupJob::run() // mark each ShaderData clean ShaderData::cleanup(m_managers); - // Cleanup texture handles - TextureDataManager *textureDataManager = m_managers->textureDataManager(); - textureDataManager->cleanup(); - // Debug bounding volume debug updateBoundingVolumesDebug(m_root); } diff --git a/src/render/jobs/frustumcullingjob_p.h b/src/render/jobs/frustumcullingjob_p.h index cb4b38b2b..ebd870937 100644 --- a/src/render/jobs/frustumcullingjob_p.h +++ b/src/render/jobs/frustumcullingjob_p.h @@ -71,7 +71,9 @@ public: inline void setRoot(Entity *root) Q_DECL_NOTHROW { m_root = root; } inline void setActive(bool active) Q_DECL_NOTHROW { m_active = active; } + inline bool isActive() const Q_DECL_NOTHROW { return m_active; } inline void setViewProjection(const QMatrix4x4 &viewProjection) Q_DECL_NOTHROW { m_viewProjection = viewProjection; } + inline QMatrix4x4 viewProjection() const Q_DECL_NOTHROW { return m_viewProjection; } QVector<Entity *> visibleEntities() const Q_DECL_NOTHROW { return m_visibleEntities; } diff --git a/src/render/jobs/genericlambdajob_p.h b/src/render/jobs/genericlambdajob_p.h index 656af7b8d..aa2fa3430 100644 --- a/src/render/jobs/genericlambdajob_p.h +++ b/src/render/jobs/genericlambdajob_p.h @@ -64,11 +64,11 @@ template<typename T> class GenericLambdaJob : public Qt3DCore::QAspectJob { public: - explicit GenericLambdaJob(T callable) + explicit GenericLambdaJob(T callable, JobTypes::JobType type = JobTypes::GenericLambda) : Qt3DCore::QAspectJob() , m_callable(callable) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::GenericLambda, 0); + SET_JOB_RUN_STAT_TYPE(this, type, 0); } // QAspectJob interface diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h index a24c428eb..f45f5639e 100644 --- a/src/render/jobs/job_common_p.h +++ b/src/render/jobs/job_common_p.h @@ -64,7 +64,7 @@ namespace JobTypes { enum JobType { LoadBuffer = 1, FrameCleanup, - FramePreparation, + UpdateShaderDataTransform, CalcBoundingVolume, CalcTriangleVolume, LoadGeometry, @@ -83,7 +83,18 @@ namespace JobTypes { FrustumCulling, LightGathering, UpdateWorldBoundingVolume, - FrameSubmissionPart2 + FrameSubmissionPart2, + DirtyBufferGathering, + DirtyTextureGathering, + DirtyShaderGathering, + SendRenderCapture, + SyncRenderViewCommandBuilding, + SyncRenderViewInitialization, + SyncRenderViewCommandBuilder, + SyncFrustumCulling, + ClearBufferDrawIndex, + UpdateMeshTriangleList, + FilterCompatibleTechniques }; } // JobTypes diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri index a970f2efc..b5d47d9aa 100644 --- a/src/render/jobs/jobs.pri +++ b/src/render/jobs/jobs.pri @@ -5,7 +5,6 @@ HEADERS += \ $$PWD/renderviewjobutils_p.h \ $$PWD/loadscenejob_p.h \ $$PWD/framecleanupjob_p.h \ - $$PWD/framepreparationjob_p.h \ $$PWD/loadtexturedatajob_p.h \ $$PWD/loadbufferjob_p.h \ $$PWD/loadgeometryjob_p.h \ @@ -22,14 +21,17 @@ HEADERS += \ $$PWD/frustumcullingjob_p.h \ $$PWD/lightgatherer_p.h \ $$PWD/expandboundingvolumejob_p.h \ - $$PWD/updateworldboundingvolumejob_p.h + $$PWD/updateworldboundingvolumejob_p.h \ + $$PWD/sendrendercapturejob_p.h \ + $$PWD/updateshaderdatatransformjob_p.h \ + $$PWD/updatemeshtrianglelistjob_p.h \ + $$PWD/pickboundingvolumeutils_p.h SOURCES += \ $$PWD/updateworldtransformjob.cpp \ $$PWD/renderviewjobutils.cpp \ $$PWD/loadscenejob.cpp \ $$PWD/framecleanupjob.cpp \ - $$PWD/framepreparationjob.cpp \ $$PWD/loadtexturedatajob.cpp \ $$PWD/loadbufferjob.cpp \ $$PWD/loadgeometryjob.cpp \ @@ -43,4 +45,8 @@ SOURCES += \ $$PWD/frustumcullingjob.cpp \ $$PWD/lightgatherer.cpp \ $$PWD/expandboundingvolumejob.cpp \ - $$PWD/updateworldboundingvolumejob.cpp + $$PWD/updateworldboundingvolumejob.cpp \ + $$PWD/sendrendercapturejob.cpp \ + $$PWD/updateshaderdatatransformjob.cpp \ + $$PWD/updatemeshtrianglelistjob.cpp \ + $$PWD/pickboundingvolumeutils.cpp diff --git a/src/render/jobs/loadbufferjob_p.h b/src/render/jobs/loadbufferjob_p.h index c7b744310..65262a2f6 100644 --- a/src/render/jobs/loadbufferjob_p.h +++ b/src/render/jobs/loadbufferjob_p.h @@ -64,16 +64,16 @@ namespace Render { class NodeManagers; -class LoadBufferJob : public Qt3DCore::QAspectJob +class Q_AUTOTEST_EXPORT LoadBufferJob : public Qt3DCore::QAspectJob { public: explicit LoadBufferJob(const HBuffer &handle); ~LoadBufferJob(); void setNodeManager(NodeManagers *nodeManagers) { m_nodeManagers = nodeManagers; } + void run() Q_DECL_OVERRIDE; protected: - void run() Q_DECL_OVERRIDE; HBuffer m_handle; NodeManagers *m_nodeManagers; }; diff --git a/src/render/jobs/loadgeometryjob_p.h b/src/render/jobs/loadgeometryjob_p.h index bc9358ad8..2b0331d1c 100644 --- a/src/render/jobs/loadgeometryjob_p.h +++ b/src/render/jobs/loadgeometryjob_p.h @@ -63,7 +63,7 @@ namespace Render { class NodeManagers; -class LoadGeometryJob : public Qt3DCore::QAspectJob +class Q_AUTOTEST_EXPORT LoadGeometryJob : public Qt3DCore::QAspectJob { public: explicit LoadGeometryJob(const HGeometryRenderer &handle); diff --git a/src/render/jobs/loadtexturedatajob.cpp b/src/render/jobs/loadtexturedatajob.cpp index b8663e4a7..55232d74f 100644 --- a/src/render/jobs/loadtexturedatajob.cpp +++ b/src/render/jobs/loadtexturedatajob.cpp @@ -39,12 +39,8 @@ #include "loadtexturedatajob_p.h" #include <Qt3DRender/private/nodemanagers_p.h> -#include <Qt3DRender/private/managers_p.h> #include <Qt3DRender/private/texturedatamanager_p.h> -#include <Qt3DRender/private/qtextureimage_p.h> #include <Qt3DRender/qtextureimagedata.h> -#include <Qt3DRender/qtexturedata.h> -#include <QThread> #include <Qt3DRender/private/job_common_p.h> #include <Qt3DRender/private/qtextureimagedata_p.h> @@ -53,87 +49,16 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { -namespace { - -typedef QPair<HTextureData, QTextureImageData *> HandleDataPair; - -HandleDataPair textureDataFromGenerator(TextureDataManager *textureDataManager, - QTextureImageDataGeneratorPtr generator) +LoadTextureDataJob::LoadTextureDataJob(const QTextureGeneratorPtr &texGen) + : m_texGen(texGen) + , m_imgDataGen(nullptr) { - HTextureData textureDataHandle; - QTextureImageData *data = nullptr; - - QMutexLocker locker(textureDataManager->mutex()); - // We don't want to take the chance of having two jobs uploading the same functor - // because of sync issues - - textureDataHandle = textureDataManager->textureDataFromFunctor(generator); - - // Texture data handle isn't null == there's already a matching TextureData - if (!textureDataHandle.isNull()) { - data = textureDataManager->data(textureDataHandle); - } else { - // Texture data is null -> we need to generate it - QTextureImageDataPtr dataPtr = generator->operator ()(); - if (dataPtr.isNull()) { - qCDebug(Jobs) << Q_FUNC_INFO << "Texture has no raw data"; - } else { - // Save the QTextureImageDataPtr with it's functor as a key - textureDataHandle = textureDataManager->acquire(); - data = textureDataManager->data(textureDataHandle); - *data = *(dataPtr.data()); - textureDataManager->addTextureDataForFunctor(textureDataHandle, generator); - } - } - - return qMakePair(textureDataHandle, data); -} - -void createTextureFromGenerator(TextureDataManager *textureDataManager, - Texture *texture) -{ - QTextureGeneratorPtr generator = texture->dataGenerator(); - const QTextureDataPtr generatedData = generator->operator ()(); - - // TO DO set the status of the texture based on the status of the functor - - // Use the first QTexImageData loaded to determine the target / mipmaps - // if not specified - - if (texture->target() != QAbstractTexture::TargetAutomatic) - qWarning() << "When a texture provides a generator, it's target is expected to be TargetAutomatic"; - - texture->setTarget(static_cast<QAbstractTexture::Target>(generatedData->target())); - texture->setSize(generatedData->width(), generatedData->height(), generatedData->depth()); - texture->setLayers(generatedData->layers()); - texture->setFormat(generatedData->format()); - - // Note: These texture data handles aren't associated with a QTextureImageDataGenerator - // and will therefore be destroyed when the Texture element is destroyed or cleaned up - const QVector<QTextureImageDataPtr> imageData = generatedData->imageData(); - - if (imageData.size() > 0) { - QMutexLocker locker(textureDataManager->mutex()); - // We don't want to take the chance of having two jobs uploading the same functor - // because of sync issues - - // Set the mips level based on the first image if autoMipMapGeneration is disabled - if (!texture->isAutoMipMapGenerationEnabled()) - texture->setMipLevels(imageData.first()->mipLevels()); - - for (QTextureImageDataPtr dataPtr : imageData) { - HTextureData textureDataHandle = textureDataManager->acquire(); - QTextureImageData *data = textureDataManager->data(textureDataHandle); - *data = *(dataPtr.data()); - texture->addTextureDataHandle(textureDataHandle); - } - } + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadTextureData, 0); } -} // anonymous - -LoadTextureDataJob::LoadTextureDataJob(Qt3DCore::QNodeId textureId) - : m_textureId(textureId) +LoadTextureDataJob::LoadTextureDataJob(const QTextureImageDataGeneratorPtr &imgDataGen) + : m_texGen(nullptr) + , m_imgDataGen(imgDataGen) { SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadTextureData, 0); } @@ -144,73 +69,13 @@ LoadTextureDataJob::~LoadTextureDataJob() void LoadTextureDataJob::run() { - qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread(); - - Texture *txt = m_manager->textureManager()->lookupResource(m_textureId); - TextureDataManager *textureDataManager = m_manager->manager<QTextureImageData, TextureDataManager>(); - - if (txt != nullptr) { - // We need to clear the TextureData handles of the texture in case it was previously - // loaded with a different functor - txt->releaseTextureDataHandles(); - - // If the texture has a functor we used it to generate embedded TextureImages - if (txt->dataGenerator()) - createTextureFromGenerator(textureDataManager, txt); - - // Load update each TextureImage - const auto texImgHandles = txt->textureImages(); - for (HTextureImage texImgHandle : texImgHandles) { - TextureImage *texImg = m_manager->textureImageManager()->data(texImgHandle); - if (texImg != nullptr && texImg->isDirty() && !texImg->dataGenerator().isNull()) { - QTextureImageDataGeneratorPtr generator = texImg->dataGenerator(); - - QPair<HTextureData, QTextureImageData *> handleData = textureDataFromGenerator(textureDataManager, generator); - - // If using QTextureImage, notify the frontend of the change in status - const QImageTextureDataFunctor *imageGenerator = functor_cast<QImageTextureDataFunctor>(generator.data()); - if (imageGenerator) - texImg->setStatus(imageGenerator->status()); - - HTextureData textureDataHandle = handleData.first; - QTextureImageData *data = handleData.second; - - // XXX released textureDataManager mutex, do we have a race here? - - // Update HTextureImage Functor to release TextureData when needed - TextureDataManager *textureDataManager = m_manager->manager<QTextureImageData, TextureDataManager>(); - textureDataManager->assignFunctorToTextureImage(generator, texImgHandle); - - // 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->mipLevel() == 0 && - texImg->face() == QAbstractTexture::CubeMapPositiveX) { - - if (data == 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() == QAbstractTexture::Automatic) { - txt->setFormat(static_cast<QAbstractTexture::TextureFormat>(data->format())); - } - } - } - // Set the textureDataHandle on the texture image - // Note: this internally updates the DNA of the TextureImage - texImg->setTextureDataHandle(textureDataHandle); - if (data) - texImg->updateDNA(::qHash(QTextureImageDataPrivate::get(data)->m_data)); - } - } - // Tell the renderer to reload/upload to GPU the TextureImage for the Texture - // next frame - txt->requestTextureDataUpdate(); + if (m_texGen) { + QTextureDataPtr texData = (*m_texGen)(); + m_manager->textureDataManager()->assignData(m_texGen, texData); + } + if (m_imgDataGen) { + QTextureImageDataPtr imgData = (*m_imgDataGen)(); + m_manager->textureImageDataManager()->assignData(m_imgDataGen, imgData); } } diff --git a/src/render/jobs/loadtexturedatajob_p.h b/src/render/jobs/loadtexturedatajob_p.h index db2521354..36fdd950b 100644 --- a/src/render/jobs/loadtexturedatajob_p.h +++ b/src/render/jobs/loadtexturedatajob_p.h @@ -53,7 +53,8 @@ #include <Qt3DCore/qnodeid.h> #include <Qt3DCore/qaspectjob.h> -#include <Qt3DRender/qtextureimage.h> +#include <Qt3DRender/qtexturegenerator.h> +#include <Qt3DRender/qtextureimagedatagenerator.h> QT_BEGIN_NAMESPACE @@ -66,15 +67,19 @@ class NodeManagers; class LoadTextureDataJob : public Qt3DCore::QAspectJob { public: - explicit LoadTextureDataJob(Qt3DCore::QNodeId textureId); + LoadTextureDataJob(const QTextureGeneratorPtr &texGen); + LoadTextureDataJob(const QTextureImageDataGeneratorPtr &imgDataGen); ~LoadTextureDataJob(); + inline void setNodeManagers(NodeManagers *manager) { m_manager = manager; } protected: void run() Q_DECL_FINAL; private: - Qt3DCore::QNodeId m_textureId; + QTextureGeneratorPtr m_texGen; + QTextureImageDataGeneratorPtr m_imgDataGen; + NodeManagers *m_manager; }; diff --git a/src/render/jobs/materialparametergathererjob.cpp b/src/render/jobs/materialparametergathererjob.cpp index f7ee96403..9c7209cec 100644 --- a/src/render/jobs/materialparametergathererjob.cpp +++ b/src/render/jobs/materialparametergathererjob.cpp @@ -52,10 +52,7 @@ namespace Render { namespace { -#ifdef QT3D_JOBS_RUN_STATS int materialParameterGathererCounter = 0; -#endif - const int likelyNumberOfParameters = 24; } // anonymous diff --git a/src/render/jobs/materialparametergathererjob_p.h b/src/render/jobs/materialparametergathererjob_p.h index 63b4d2946..d14e096d8 100644 --- a/src/render/jobs/materialparametergathererjob_p.h +++ b/src/render/jobs/materialparametergathererjob_p.h @@ -81,6 +81,9 @@ public: inline QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> &materialToPassAndParameter() Q_DECL_NOTHROW { return m_parameters; } inline void setHandles(const QVector<HMaterial> &handles) Q_DECL_NOTHROW { m_handles = handles; } + inline TechniqueFilter *techniqueFilter() const Q_DECL_NOTHROW { return m_techniqueFilter; } + inline RenderPassFilter *renderPassFilter() const Q_DECL_NOTHROW { return m_renderPassFilter; } + void run() Q_DECL_FINAL; private: diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp index 21cf36afc..7aa2be759 100644 --- a/src/render/jobs/pickboundingvolumejob.cpp +++ b/src/render/jobs/pickboundingvolumejob.cpp @@ -38,29 +38,16 @@ ****************************************************************************/ #include "pickboundingvolumejob_p.h" -#include "qpickevent.h" #include "qpicktriangleevent.h" #include <Qt3DRender/private/renderer_p.h> #include <Qt3DRender/private/nodemanagers_p.h> -#include <Qt3DRender/private/framegraphnode_p.h> -#include <Qt3DRender/private/cameralens_p.h> -#include <Qt3DRender/private/cameraselectornode_p.h> -#include <Qt3DRender/private/viewportnode_p.h> #include <Qt3DRender/private/entity_p.h> #include <Qt3DRender/private/objectpicker_p.h> #include <Qt3DRender/private/managers_p.h> -#include <Qt3DRender/private/sphere_p.h> #include <Qt3DRender/private/geometryrenderer_p.h> -#include <Qt3DRender/private/trianglesvisitor_p.h> -#include <Qt3DRender/private/triangleboundingvolume_p.h> -#include <Qt3DRender/private/qraycastingservice_p.h> -#include <Qt3DRender/private/rendersurfaceselector_p.h> + #include <Qt3DRender/private/rendersettings_p.h> -#include <Qt3DRender/private/rendersurfaceselector_p.h> -#include <Qt3DRender/private/qray3d_p.h> #include <Qt3DRender/qgeometryrenderer.h> -#include <Qt3DCore/private/qservicelocator_p.h> -#include <QSurface> #include <Qt3DRender/private/job_common_p.h> QT_BEGIN_NAMESPACE @@ -69,291 +56,193 @@ namespace Qt3DRender { namespace Render { -struct ViewportCameraAreaTriplet -{ - Qt3DCore::QNodeId cameraId; - QRectF viewport; - QSize area; -}; -QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, ViewportCameraAreaTriplet, Q_PRIMITIVE_TYPE) - namespace { -class ViewportCameraAreaGatherer +void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers) { -private: - QVector<FrameGraphNode *> m_leaves; - - void visit(FrameGraphNode *node) - { - const auto children = node->children(); - for (Render::FrameGraphNode *n : children) - visit(n); - if (node->childrenIds().empty()) - m_leaves.push_back(node); - } - - ViewportCameraAreaTriplet gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const - { - ViewportCameraAreaTriplet vca; - vca.viewport = QRectF(0.0f, 0.0f, 1.0f, 1.0f); - - while (node) { - if (node->isEnabled()) { - switch (node->nodeType()) { - case FrameGraphNode::CameraSelector: - vca.cameraId = static_cast<const CameraSelector *>(node)->cameraUuid(); - break; - case FrameGraphNode::Viewport: - vca.viewport = computeViewport(vca.viewport, static_cast<const ViewportNode *>(node)); - break; - case FrameGraphNode::Surface: - vca.area = static_cast<const RenderSurfaceSelector *>(node)->renderTargetSize(); - break; - default: - break; - } - } - node = node->parent(); - } - return vca; - } - - bool isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, const ViewportCameraAreaTriplet &vca) const - { - for (const ViewportCameraAreaTriplet &triplet : vcaTriplets) { - if (vca.cameraId == triplet.cameraId && vca.viewport == triplet.viewport && vca.area == triplet.area) - return false; - } - return true; + switch (event.button()) { + case Qt::LeftButton: + eventButton = QPickEvent::LeftButton; + break; + case Qt::RightButton: + eventButton = QPickEvent::RightButton; + break; + case Qt::MiddleButton: + eventButton = QPickEvent::MiddleButton; + break; + case Qt::BackButton: + eventButton = QPickEvent::BackButton; + break; + default: + break; } -public: - QVector<ViewportCameraAreaTriplet> gather(FrameGraphNode *root) - { - // Retrieve all leaves - visit(root); - QVector<ViewportCameraAreaTriplet> vcaTriplets; - vcaTriplets.reserve(m_leaves.count()); - - // Find all viewport/camera pairs by traversing from leaf to root - for (Render::FrameGraphNode *leaf : qAsConst(m_leaves)) { - ViewportCameraAreaTriplet vcaTriplet = gatherUpViewportCameraAreas(leaf); - if (!vcaTriplet.cameraId.isNull() && isUnique(vcaTriplets, vcaTriplet)) - vcaTriplets.push_back(vcaTriplet); - } - return vcaTriplets; - } + if (event.buttons() & Qt::LeftButton) + eventButtons |= QPickEvent::LeftButton; + if (event.buttons() & Qt::RightButton) + eventButtons |= QPickEvent::RightButton; + if (event.buttons() & Qt::MiddleButton) + eventButtons |= QPickEvent::MiddleButton; + if (event.buttons() & Qt::BackButton) + eventButtons |= QPickEvent::BackButton; + if (event.modifiers() & Qt::ShiftModifier) + eventModifiers |= QPickEvent::ShiftModifier; + if (event.modifiers() & Qt::ControlModifier) + eventModifiers |= QPickEvent::ControlModifier; + if (event.modifiers() & Qt::AltModifier) + eventModifiers |= QPickEvent::AltModifier; + if (event.modifiers() & Qt::MetaModifier) + eventModifiers |= QPickEvent::MetaModifier; + if (event.modifiers() & Qt::KeypadModifier) + eventModifiers |= QPickEvent::KeypadModifier; +} -}; +} // anonymous -static QVector<Entity *> gatherEntities(Entity *entity, QVector<Entity *> entities) +PickBoundingVolumeJob::PickBoundingVolumeJob() + : m_manager(nullptr) + , m_node(nullptr) + , m_frameGraphRoot(nullptr) + , m_renderSettings(nullptr) { - if (entity != nullptr) { - entities.push_back(entity); - // Traverse children - const auto children = entity->children(); - for (Entity *child : children) - entities = gatherEntities(child, std::move(entities)); - } - return entities; + SET_JOB_RUN_STAT_TYPE(this, JobTypes::PickBoundingVolume, 0); } -class EntityGatherer +void PickBoundingVolumeJob::setRoot(Entity *root) { -public: - explicit EntityGatherer(Entity *root) - : m_root(root) - , m_needsRefresh(true) - { - } - - QVector<Entity *> entities() const - { - if (m_needsRefresh) { - m_entities.clear(); - m_entities = gatherEntities(m_root, std::move(m_entities)); - m_needsRefresh = false; - } - return m_entities; - } - -private: - Entity *m_root; - mutable QVector<Entity *> m_entities; - mutable bool m_needsRefresh; -}; + m_node = root; +} -class CollisionVisitor : public TrianglesVisitor +void PickBoundingVolumeJob::setMouseEvents(const QList<QMouseEvent> &pendingEvents) { -public: - typedef QVector<QCollisionQueryResult::Hit> HitList; - HitList hits; - - CollisionVisitor(NodeManagers* manager, const Entity *root, const QRay3D& ray) : TrianglesVisitor(manager), m_root(root), m_ray(ray), m_triangleIndex(0) { } -private: - const Entity *m_root; - QRay3D m_ray; - Qt3DRender::QRayCastingService rayCasting; - uint m_triangleIndex; - - void visit(uint andx, const QVector3D &a, - uint bndx, const QVector3D &b, - uint cndx, const QVector3D &c) - { - TriangleBoundingVolume volume(m_root->peerId(), a, b, c); - volume = volume.transform(*m_root->worldTransform()); - - QCollisionQueryResult::Hit queryResult = rayCasting.query(m_ray, &volume); - if (queryResult.m_distance > 0.) { - queryResult.m_triangleIndex = m_triangleIndex; - queryResult.m_vertexIndex[0] = andx; - queryResult.m_vertexIndex[1] = bndx; - queryResult.m_vertexIndex[2] = cndx; - hits.push_back(queryResult); - } + m_pendingMouseEvents = pendingEvents; +} - m_triangleIndex++; - } -}; +void PickBoundingVolumeJob::setFrameGraphRoot(FrameGraphNode *frameGraphRoot) +{ + m_frameGraphRoot = frameGraphRoot; +} -struct AbstractCollisionGathererFunctor +void PickBoundingVolumeJob::setRenderSettings(RenderSettings *settings) { - AbstractCollisionGathererFunctor() : m_renderer(0) { } - virtual ~AbstractCollisionGathererFunctor() { } + m_renderSettings = settings; +} - Renderer *m_renderer; - QRay3D m_ray; +QRay3D PickBoundingVolumeJob::intersectionRay(const QPoint &pos, const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix, const QRect &viewport) +{ + QVector3D nearPos = QVector3D(pos.x(), pos.y(), 0.0f); + nearPos = nearPos.unproject(viewMatrix, projectionMatrix, viewport); + QVector3D farPos = QVector3D(pos.x(), pos.y(), 1.0f); + farPos = farPos.unproject(viewMatrix, projectionMatrix, viewport); - typedef CollisionVisitor::HitList result_type; + return QRay3D(nearPos, + (farPos - nearPos).normalized(), + (farPos - nearPos).length()); +} - result_type operator ()(const Entity *entity) const - { - result_type result; +bool PickBoundingVolumeJob::runHelper() +{ + // Move to clear the events so that we don't process them several times + // if run is called several times + const auto mouseEvents = std::move(m_pendingMouseEvents); - HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); + // If we have no events return early + if (mouseEvents.empty()) + return false; - // If the Entity which actually received the hit doesn't have - // an object picker component, we need to check the parent if it has one ... - while (objectPickerHandle.isNull() && entity != nullptr) { - entity = entity->parent(); - if (entity != nullptr) - objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); - } + PickingUtils::ViewportCameraAreaGatherer vcaGatherer; + // TO DO: We could cache this and only gather when we know the FrameGraph tree has changed + const QVector<PickingUtils::ViewportCameraAreaTriplet> vcaTriplets = vcaGatherer.gather(m_frameGraphRoot); - ObjectPicker *objectPicker = m_renderer->nodeManagers()->objectPickerManager()->data(objectPickerHandle); - if (objectPicker == nullptr) - return result_type(); // don't bother picking entities that don't have an object picker + // If we have no viewport / camera or area, return early + if (vcaTriplets.empty()) + return false; - Qt3DRender::QRayCastingService rayCasting; + bool hasMoveEvent = false; + bool hasOtherEvent = false; - return pick(&rayCasting, entity); + // Quickly look which types of events we've got + for (const QMouseEvent &event : mouseEvents) { + const bool isMove = (event.type() == QEvent::MouseMove); + hasMoveEvent |= isMove; + hasOtherEvent |= !isMove; } - virtual result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const = 0; -}; - -struct EntityCollisionGathererFunctor : public AbstractCollisionGathererFunctor -{ - result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE - { - result_type result; - - const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume()); - if (queryResult.m_distance >= 0.f) - result.push_back(queryResult); - - return result; + // In the case we have a move event, find if we actually have + // an object picker that cares about these + if (!hasOtherEvent) { + // Retrieve the last used object picker + ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); + + // The only way to set lastCurrentPicker is to click + // so we can return since if we're there it means we + // have only move events + if (lastCurrentPicker == nullptr) + return false; + + const bool caresAboutMove = (hasMoveEvent && lastCurrentPicker->isDragEnabled()); + // Early return if the current object picker doesn't care about move events + if (!caresAboutMove) + return false; } -}; -struct TriangleCollisionGathererFunctor : public AbstractCollisionGathererFunctor -{ - result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE - { - result_type result; - - GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>(); - if (!gRenderer) - return result; - - if (rayHitsEntity(rayCasting, entity)) { - CollisionVisitor visitor(m_renderer->nodeManagers(), entity, m_ray); - visitor.apply(gRenderer, entity->peerId()); - result = visitor.hits; - - struct - { - bool operator()(const result_type::value_type &a, const result_type::value_type &b) - { - return a.m_distance < b.m_distance; - } - } compareHitsDistance; - std::sort(result.begin(), result.end(), compareHitsDistance); - } - - return result; - } - bool rayHitsEntity(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const - { - const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume()); - return queryResult.m_distance >= 0.f; - } -}; - -CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate) -{ - if (!intermediate.empty()) { - if (result.empty()) - result.push_back(intermediate.front()); - float closest = result.front().m_distance; - for (const auto &v : intermediate) { - if (v.m_distance < closest) { - result.push_front(v); - closest = v.m_distance; + // TO DO: + // If we have move or hover move events that someone cares about, we try to avoid expensive computations + // by compressing them into a single one + + // Gather the entities for the frame + // TO DO: We could skip doing that every frame and only do it when we know for sure + // that the tree structure has changed + PickingUtils::EntityGatherer entitiesGatherer(m_node); + + // Store the reducer function which varies depending on the picking settings set on the renderer + using ReducerFunction = PickingUtils::CollisionVisitor::HitList (*)(PickingUtils::CollisionVisitor::HitList &results, const PickingUtils::CollisionVisitor::HitList &intermediate); + + const bool trianglePickingRequested = (m_renderSettings->pickMethod() == QPickingSettings::TrianglePicking); + const bool allHitsRequested = (m_renderSettings->pickResultMode() == QPickingSettings::AllPicks); + + // Select the best reduction function based on the settings + const ReducerFunction reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit; + + // For each mouse event + for (const QMouseEvent &event : mouseEvents) { + m_hoveredPickersToClear = m_hoveredPickers; + + QPickEvent::Buttons eventButton = QPickEvent::NoButton; + int eventButtons = 0; + int eventModifiers = QPickEvent::NoModifier; + + setEventButtonAndModifiers(event, eventButton, eventButtons, eventModifiers); + + // For each triplet of Viewport / Camera and Area + for (const PickingUtils::ViewportCameraAreaTriplet &vca : vcaTriplets) { + typedef PickingUtils::AbstractCollisionGathererFunctor::result_type HitList; + HitList sphereHits; + QRay3D ray = rayForViewportAndCamera(vca.area, event.pos(), vca.viewport, vca.cameraId); + if (trianglePickingRequested) { + PickingUtils::TriangleCollisionGathererFunctor gathererFunctor; + gathererFunctor.m_manager = m_manager; + gathererFunctor.m_ray = ray; + sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp); + } else { + PickingUtils::EntityCollisionGathererFunctor gathererFunctor; + gathererFunctor.m_manager = m_manager; + gathererFunctor.m_ray = ray; + sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp); } - } - while (result.size() > 1) - result.pop_back(); + // Dispatch events based on hit results + dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers); + } } - return result; -} - -// Unordered -CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate) -{ - if (!intermediate.empty()) - results << intermediate; - return results; -} - -} // anonymous - -PickBoundingVolumeJob::PickBoundingVolumeJob(Renderer *renderer) - : m_renderer(renderer) - , m_manager(nullptr) - , m_node(nullptr) -{ - SET_JOB_RUN_STAT_TYPE(this, JobTypes::PickBoundingVolume, 0); -} -void PickBoundingVolumeJob::setRoot(Entity *root) -{ - m_node = root; -} - -QRay3D PickBoundingVolumeJob::intersectionRay(const QPoint &pos, const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix, const QRect &viewport) -{ - QVector3D nearPos = QVector3D(pos.x(), pos.y(), 0.0f); - nearPos = nearPos.unproject(viewMatrix, projectionMatrix, viewport); - QVector3D farPos = QVector3D(pos.x(), pos.y(), 1.0f); - farPos = farPos.unproject(viewMatrix, projectionMatrix, viewport); - - return QRay3D(nearPos, - (farPos - nearPos).normalized(), - (farPos - nearPos).length()); + // Clear Hovered elements that needs to be cleared + // Send exit event to object pickers on which we + // had set the hovered flag for a previous frame + // and that aren't being hovered any longer + clearPreviouslyHoveredPickers(); + return true; } void PickBoundingVolumeJob::setManagers(NodeManagers *manager) @@ -363,152 +252,126 @@ void PickBoundingVolumeJob::setManagers(NodeManagers *manager) void PickBoundingVolumeJob::run() { - const auto mouseEvents = m_renderer->pendingPickingEvents(); - if (mouseEvents.empty()) - return; - - ViewportCameraAreaGatherer vcaGatherer; - const QVector<ViewportCameraAreaTriplet> vcaTriplets = vcaGatherer.gather(m_renderer->frameGraphRoot()); - - EntityGatherer entitiesGatherer(m_node); - - if (!vcaTriplets.empty()) { - for (const QMouseEvent &event : mouseEvents) { - m_hoveredPickersToClear = m_hoveredPickers; - ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); - - for (const ViewportCameraAreaTriplet &vca : vcaTriplets) { - typedef AbstractCollisionGathererFunctor::result_type HitList; - HitList sphereHits; - QRay3D ray = rayForViewportAndCamera(vca.area, event.pos(), vca.viewport, vca.cameraId); - auto reducerOp = m_renderer->settings() && m_renderer->settings()->pickResultMode() == QPickingSettings::AllPicks ? reduceToAllHits : reduceToFirstHit; - if (m_renderer->settings() && m_renderer->settings()->pickMethod() == QPickingSettings::TrianglePicking) { - TriangleCollisionGathererFunctor gathererFunctor; - gathererFunctor.m_renderer = m_renderer; - gathererFunctor.m_ray = ray; - sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp); - } else { - EntityCollisionGathererFunctor gathererFunctor; - gathererFunctor.m_renderer = m_renderer; - gathererFunctor.m_ray = ray; - sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp); - } - - // If we have hits - if (!sphereHits.isEmpty()) { - // Note: how can we control that we want the first/last/all elements along the ray to be picked + Q_ASSERT(m_frameGraphRoot && m_renderSettings && m_node && m_manager); + runHelper(); +} - // How do we differentiate betwnee an Entity with no GeometryRenderer and one with one, both having - // an ObjectPicker component when it comes +void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event, + const PickingUtils::CollisionVisitor::HitList &sphereHits, + QPickEvent::Buttons eventButton, + int eventButtons, + int eventModifiers) +{ + ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); + // If we have hits + if (!sphereHits.isEmpty()) { - // We want to gather hits against triangles - // build a triangle based bounding volume + const bool trianglePickingRequested = (m_renderSettings->pickResultMode() == QPickingSettings::AllPicks); + // Note: how can we control that we want the first/last/all elements along the ray to be picked - for (const QCollisionQueryResult::Hit &hit : qAsConst(sphereHits)) { - Entity *entity = m_manager->renderNodesManager()->lookupResource(hit.m_entityId); - HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); + // How do we differentiate betwnee an Entity with no GeometryRenderer and one with one, both having + // an ObjectPicker component when it comes - // If the Entity which actually received the hit doesn't have - // an object picker component, we need to check the parent if it has one ... - while (objectPickerHandle.isNull() && entity != nullptr) { - entity = entity->parent(); - if (entity != nullptr) - objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); - } + // We want to gather hits against triangles + // build a triangle based bounding volume - ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle); - - if (objectPicker != nullptr) { - // Send the corresponding event - QVector3D localIntersection = hit.m_intersection; - if (entity && entity->worldTransform()) - localIntersection = hit.m_intersection * entity->worldTransform()->inverted(); - QPickEventPtr pickEvent; - if (m_renderer->settings() && m_renderer->settings()->pickMethod() == QPickingSettings::TrianglePicking) { - pickEvent.reset(new QPickTriangleEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance, - hit.m_triangleIndex, hit.m_vertexIndex[0], hit.m_vertexIndex[1], hit.m_vertexIndex[2])); - } else { - pickEvent.reset(new QPickEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance)); - } - - switch (event.type()) { - case QEvent::MouseButtonPress: { - // Store pressed object handle - m_currentPicker = objectPickerHandle; - // Send pressed event to m_currentPicker - objectPicker->onPressed(pickEvent); - break; - } - - case QEvent::MouseButtonRelease: { - if (lastCurrentPicker != nullptr && m_currentPicker == objectPickerHandle) - m_currentPicker = HObjectPicker(); - // Only send the release event if it was pressed - if (objectPicker->isPressed()) { - objectPicker->onClicked(pickEvent); - objectPicker->onReleased(pickEvent); - } - break; - } - - case Qt::TapGesture: { - objectPicker->onClicked(pickEvent); - break; - } - - case QEvent::MouseMove: { - if (objectPicker->isPressed() && objectPicker->isDragEnabled()) { - objectPicker->onMoved(pickEvent); - } - // fallthrough - } - case QEvent::HoverMove: { - if (!m_hoveredPickers.contains(objectPickerHandle)) { - if (objectPicker->isHoverEnabled()) { - // Send entered event to objectPicker - objectPicker->onEntered(); - // and save it in the hoveredPickers - m_hoveredPickers.push_back(objectPickerHandle); - } - } - break; - } - - default: - break; - } - } + for (const QCollisionQueryResult::Hit &hit : qAsConst(sphereHits)) { + Entity *entity = m_manager->renderNodesManager()->lookupResource(hit.m_entityId); + HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); - // The ObjectPicker was hit -> it is still being hovered - m_hoveredPickersToClear.removeAll(objectPickerHandle); + // If the Entity which actually received the hit doesn't have + // an object picker component, we need to check the parent if it has one ... + while (objectPickerHandle.isNull() && entity != nullptr) { + entity = entity->parent(); + if (entity != nullptr) + objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); + } + ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle); + + if (objectPicker != nullptr) { + // Send the corresponding event + QVector3D localIntersection = hit.m_intersection; + if (entity && entity->worldTransform()) + localIntersection = hit.m_intersection * entity->worldTransform()->inverted(); + + QPickEventPtr pickEvent; + if (trianglePickingRequested) + pickEvent.reset(new QPickTriangleEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance, + hit.m_triangleIndex, hit.m_vertexIndex[0], hit.m_vertexIndex[1], hit.m_vertexIndex[2], + eventButton, eventButtons, eventModifiers)); + else + pickEvent.reset(new QPickEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance, + eventButton, eventButtons, eventModifiers)); + + switch (event.type()) { + case QEvent::MouseButtonPress: { + // Store pressed object handle + m_currentPicker = objectPickerHandle; + // Send pressed event to m_currentPicker + objectPicker->onPressed(pickEvent); + break; + } - lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); + case QEvent::MouseButtonRelease: { + if (lastCurrentPicker != nullptr && m_currentPicker == objectPickerHandle) + m_currentPicker = HObjectPicker(); + // Only send the release event if it was pressed + if (objectPicker->isPressed()) { + objectPicker->onClicked(pickEvent); + objectPicker->onReleased(pickEvent); } + break; + } - // Otherwise no hits - } else { - switch (event.type()) { - case QEvent::MouseButtonRelease: { - // Send release event to m_currentPicker - if (lastCurrentPicker != nullptr) { - m_currentPicker = HObjectPicker(); - QPickEventPtr pickEvent(new QPickEvent); - lastCurrentPicker->onReleased(pickEvent); - } - break; + case Qt::TapGesture: { + objectPicker->onClicked(pickEvent); + break; + } + + case QEvent::MouseMove: { + if (objectPicker->isPressed() && objectPicker->isDragEnabled()) { + objectPicker->onMoved(pickEvent); } - default: - break; + // fallthrough + } + case QEvent::HoverMove: { + if (!m_hoveredPickers.contains(objectPickerHandle)) { + if (objectPicker->isHoverEnabled()) { + // Send entered event to objectPicker + objectPicker->onEntered(); + // and save it in the hoveredPickers + m_hoveredPickers.push_back(objectPickerHandle); + } } + break; + } + + default: + break; } } + + // The ObjectPicker was hit -> it is still being hovered + m_hoveredPickersToClear.removeAll(objectPickerHandle); + + lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); } - // Clear Hovered elements that needs to be cleared - // Send exit event to object pickers on which we - // had set the hovered flag for a previous frame - // and that aren't being hovered any longer - clearPreviouslyHoveredPickers(); + // Otherwise no hits + } else { + switch (event.type()) { + case QEvent::MouseButtonRelease: { + // Send release event to m_currentPicker + if (lastCurrentPicker != nullptr) { + m_currentPicker = HObjectPicker(); + QPickEventPtr pickEvent(new QPickEvent); + lastCurrentPicker->onReleased(pickEvent); + } + break; + } + default: + break; + } } } diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h index 1baa67fee..e0a759d6c 100644 --- a/src/render/jobs/pickboundingvolumejob_p.h +++ b/src/render/jobs/pickboundingvolumejob_p.h @@ -56,6 +56,8 @@ #include <Qt3DRender/private/handle_types_p.h> #include <Qt3DRender/private/qboundingvolumeprovider_p.h> #include <Qt3DRender/private/qcollisionqueryresult_p.h> +#include <Qt3DRender/private/pickboundingvolumeutils_p.h> +#include <Qt3DRender/qpickevent.h> #include <QMouseEvent> #include <QSharedPointer> @@ -74,26 +76,42 @@ namespace Render { class Entity; class Renderer; class NodeManagers; +class RenderSettings; class Q_AUTOTEST_EXPORT PickBoundingVolumeJob : public Qt3DCore::QAspectJob { public: - PickBoundingVolumeJob(Renderer *renderer); + PickBoundingVolumeJob(); void setRoot(Entity *root); + void setMouseEvents(const QList<QMouseEvent> &pendingEvents); + void setFrameGraphRoot(FrameGraphNode *frameGraphRoot); + void setRenderSettings(RenderSettings *settings); + void setManagers(NodeManagers *manager); static QRay3D intersectionRay(const QPoint &pos, const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix, const QRect &viewport); - void setManagers(NodeManagers *manager); + + // For unit tests + inline HObjectPicker currentPicker() const { return m_currentPicker; } + inline QVector<HObjectPicker> hoveredPickers() const { return m_hoveredPickers; } + bool runHelper(); + protected: void run() Q_DECL_FINAL; + void dispatchPickEvents(const QMouseEvent &event, const PickingUtils::CollisionVisitor::HitList &sphereHits, + QPickEvent::Buttons eventButton, + int eventButtons, + int eventModifiers); private: - Renderer *m_renderer; NodeManagers *m_manager; Entity *m_node; + FrameGraphNode *m_frameGraphRoot; + RenderSettings *m_renderSettings; + QList<QMouseEvent> m_pendingMouseEvents; void viewMatrixForCamera(Qt3DCore::QNodeId cameraId, QMatrix4x4 &viewMatrix, diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp new file mode 100644 index 000000000..fd4eded27 --- /dev/null +++ b/src/render/jobs/pickboundingvolumeutils.cpp @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pickboundingvolumeutils_p.h" +#include <Qt3DRender/private/framegraphnode_p.h> +#include <Qt3DRender/private/cameralens_p.h> +#include <Qt3DRender/private/cameraselectornode_p.h> +#include <Qt3DRender/private/viewportnode_p.h> +#include <Qt3DRender/private/rendersurfaceselector_p.h> +#include <Qt3DRender/private/triangleboundingvolume_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DRender/private/sphere_p.h> +#include <Qt3DRender/private/entity_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +namespace PickingUtils { + +void ViewportCameraAreaGatherer::visit(FrameGraphNode *node) +{ + const auto children = node->children(); + for (Render::FrameGraphNode *n : children) + visit(n); + if (node->childrenIds().empty()) + m_leaves.push_back(node); +} + +ViewportCameraAreaTriplet ViewportCameraAreaGatherer::gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const +{ + ViewportCameraAreaTriplet vca; + vca.viewport = QRectF(0.0f, 0.0f, 1.0f, 1.0f); + + while (node) { + if (node->isEnabled()) { + switch (node->nodeType()) { + case FrameGraphNode::CameraSelector: + vca.cameraId = static_cast<const CameraSelector *>(node)->cameraUuid(); + break; + case FrameGraphNode::Viewport: + vca.viewport = computeViewport(vca.viewport, static_cast<const ViewportNode *>(node)); + break; + case FrameGraphNode::Surface: + vca.area = static_cast<const RenderSurfaceSelector *>(node)->renderTargetSize(); + break; + default: + break; + } + } + node = node->parent(); + } + return vca; +} + +QVector<ViewportCameraAreaTriplet> ViewportCameraAreaGatherer::gather(FrameGraphNode *root) +{ + // Retrieve all leaves + visit(root); + QVector<ViewportCameraAreaTriplet> vcaTriplets; + vcaTriplets.reserve(m_leaves.count()); + + // Find all viewport/camera pairs by traversing from leaf to root + for (Render::FrameGraphNode *leaf : qAsConst(m_leaves)) { + ViewportCameraAreaTriplet vcaTriplet = gatherUpViewportCameraAreas(leaf); + if (!vcaTriplet.cameraId.isNull() && isUnique(vcaTriplets, vcaTriplet)) + vcaTriplets.push_back(vcaTriplet); + } + return vcaTriplets; +} + +bool PickingUtils::ViewportCameraAreaGatherer::isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, const ViewportCameraAreaTriplet &vca) const +{ + for (const ViewportCameraAreaTriplet &triplet : vcaTriplets) { + if (vca.cameraId == triplet.cameraId && vca.viewport == triplet.viewport && vca.area == triplet.area) + return false; + } + return true; +} + +QVector<Entity *> gatherEntities(Entity *entity, QVector<Entity *> entities) +{ + if (entity != nullptr) { + entities.push_back(entity); + // Traverse children + const auto children = entity->children(); + for (Entity *child : children) + entities = gatherEntities(child, std::move(entities)); + } + return entities; +} + +EntityGatherer::EntityGatherer(Entity *root) + : m_root(root) + , m_needsRefresh(true) +{ +} + +QVector<Entity *> EntityGatherer::entities() const +{ + if (m_needsRefresh) { + m_entities.clear(); + m_entities = gatherEntities(m_root, std::move(m_entities)); + m_needsRefresh = false; + } + return m_entities; +} + +void CollisionVisitor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c) +{ + TriangleBoundingVolume volume(m_root->peerId(), a, b, c); + volume = volume.transform(*m_root->worldTransform()); + + QCollisionQueryResult::Hit queryResult = rayCasting.query(m_ray, &volume); + if (queryResult.m_distance > 0.) { + queryResult.m_triangleIndex = m_triangleIndex; + queryResult.m_vertexIndex[0] = andx; + queryResult.m_vertexIndex[1] = bndx; + queryResult.m_vertexIndex[2] = cndx; + hits.push_back(queryResult); + } + + m_triangleIndex++; +} + +AbstractCollisionGathererFunctor::AbstractCollisionGathererFunctor() + : m_manager(nullptr) +{ } + +AbstractCollisionGathererFunctor::~AbstractCollisionGathererFunctor() +{ } + +AbstractCollisionGathererFunctor::result_type AbstractCollisionGathererFunctor::operator ()(const Entity *entity) const +{ + HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); + + // If the Entity which actually received the hit doesn't have + // an object picker component, we need to check the parent if it has one ... + auto parentEntity = entity; + while (objectPickerHandle.isNull() && parentEntity != nullptr) { + parentEntity = parentEntity->parent(); + if (parentEntity != nullptr) + objectPickerHandle = parentEntity->componentHandle<ObjectPicker, 16>(); + } + + ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle); + if (objectPicker == nullptr) + return result_type(); // don't bother picking entities that don't have an object picker + + Qt3DRender::QRayCastingService rayCasting; + + return pick(&rayCasting, entity); +} + +AbstractCollisionGathererFunctor::result_type EntityCollisionGathererFunctor::pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const +{ + result_type result; + + const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume()); + if (queryResult.m_distance >= 0.f) + result.push_back(queryResult); + + return result; +} + +AbstractCollisionGathererFunctor::result_type TriangleCollisionGathererFunctor::pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const +{ + result_type result; + + GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>(); + if (!gRenderer) + return result; + + if (rayHitsEntity(rayCasting, entity)) { + CollisionVisitor visitor(m_manager, entity, m_ray); + visitor.apply(gRenderer, entity->peerId()); + result = visitor.hits; + + struct + { + bool operator()(const result_type::value_type &a, const result_type::value_type &b) + { + return a.m_distance < b.m_distance; + } + } compareHitsDistance; + std::sort(result.begin(), result.end(), compareHitsDistance); + } + + return result; +} + +bool TriangleCollisionGathererFunctor::rayHitsEntity(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const +{ + const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume()); + return queryResult.m_distance >= 0.f; +} + +CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate) +{ + if (!intermediate.empty()) { + if (result.empty()) + result.push_back(intermediate.front()); + float closest = result.front().m_distance; + for (const auto &v : intermediate) { + if (v.m_distance < closest) { + result.push_front(v); + closest = v.m_distance; + } + } + + while (result.size() > 1) + result.pop_back(); + } + return result; +} + +CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate) +{ + if (!intermediate.empty()) + results << intermediate; + return results; +} + +} // PickingUtils + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h new file mode 100644 index 000000000..5bc94a13b --- /dev/null +++ b/src/render/jobs/pickboundingvolumeutils_p.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_PICKBOUNDINGVOLUMEUTILS_H +#define QT3DRENDER_RENDER_PICKBOUNDINGVOLUMEUTILS_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DRender/private/qray3d_p.h> +#include <Qt3DRender/private/trianglesvisitor_p.h> +#include <Qt3DRender/private/qraycastingservice_p.h> + + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QAbstractCollisionQueryService; + +namespace Render { + +class Entity; +class Renderer; +class FrameGraphNode; + +namespace PickingUtils { + +struct Q_AUTOTEST_EXPORT ViewportCameraAreaTriplet +{ + Qt3DCore::QNodeId cameraId; + QRectF viewport; + QSize area; +}; +QT3D_DECLARE_TYPEINFO_3(Qt3DRender, Render, PickingUtils, ViewportCameraAreaTriplet, Q_PRIMITIVE_TYPE) + +class Q_AUTOTEST_EXPORT ViewportCameraAreaGatherer +{ +public: + QVector<ViewportCameraAreaTriplet> gather(FrameGraphNode *root); + +private: + QVector<FrameGraphNode *> m_leaves; + + void visit(FrameGraphNode *node); + ViewportCameraAreaTriplet gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const; + bool isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, const ViewportCameraAreaTriplet &vca) const; +}; + +class Q_AUTOTEST_EXPORT EntityGatherer +{ +public: + explicit EntityGatherer(Entity *root); + + QVector<Entity *> entities() const; + +private: + Entity *m_root; + mutable QVector<Entity *> m_entities; + mutable bool m_needsRefresh; +}; + +class Q_AUTOTEST_EXPORT CollisionVisitor : public TrianglesVisitor +{ +public: + typedef QVector<QCollisionQueryResult::Hit> HitList; + HitList hits; + + CollisionVisitor(NodeManagers* manager, const Entity *root, const QRay3D& ray) : TrianglesVisitor(manager), m_root(root), m_ray(ray), m_triangleIndex(0) { } +private: + const Entity *m_root; + QRay3D m_ray; + Qt3DRender::QRayCastingService rayCasting; + uint m_triangleIndex; + + void visit(uint andx, const QVector3D &a, + uint bndx, const QVector3D &b, + uint cndx, const QVector3D &c); +}; + +struct Q_AUTOTEST_EXPORT AbstractCollisionGathererFunctor +{ + AbstractCollisionGathererFunctor(); + virtual ~AbstractCollisionGathererFunctor(); + + NodeManagers *m_manager; + QRay3D m_ray; + + // This define is required to work with QtConcurrent + typedef CollisionVisitor::HitList result_type; + result_type operator ()(const Entity *entity) const; + virtual result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const = 0; +}; + +struct Q_AUTOTEST_EXPORT EntityCollisionGathererFunctor : public AbstractCollisionGathererFunctor +{ + result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE; +}; + +struct Q_AUTOTEST_EXPORT TriangleCollisionGathererFunctor : public AbstractCollisionGathererFunctor +{ + result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE; + + bool rayHitsEntity(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const; +}; + +Q_AUTOTEST_EXPORT QVector<Entity *> gatherEntities(Entity *entity, QVector<Entity *> entities); + +Q_AUTOTEST_EXPORT CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate); + +// Unordered +Q_AUTOTEST_EXPORT CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate); + +} // PickingUtils + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_PICKBOUNDINGVOLUMEUTILS_H diff --git a/src/render/jobs/renderviewbuilderjob.cpp b/src/render/jobs/renderviewbuilderjob.cpp index f0cf83e15..fa6218d6f 100644 --- a/src/render/jobs/renderviewbuilderjob.cpp +++ b/src/render/jobs/renderviewbuilderjob.cpp @@ -48,11 +48,9 @@ namespace Qt3DRender { namespace Render { -#ifdef QT3D_JOBS_RUN_STATS namespace { int renderViewInstanceCounter = 0; } // anonymous -#endif RenderViewBuilderJob::RenderViewBuilderJob() : Qt3DCore::QAspectJob(), diff --git a/src/render/jobs/renderviewinitializerjob.cpp b/src/render/jobs/renderviewinitializerjob.cpp index f43f86fac..7bf55be40 100644 --- a/src/render/jobs/renderviewinitializerjob.cpp +++ b/src/render/jobs/renderviewinitializerjob.cpp @@ -61,7 +61,6 @@ int renderViewInstanceCounter = 0; RenderViewInitializerJob::RenderViewInitializerJob() : m_renderer(nullptr) - , m_devicePixelRatio(1.) , m_fgLeaf(nullptr) , m_index(0) , m_renderView(nullptr) @@ -90,8 +89,6 @@ void RenderViewInitializerJob::run() // RenderView should allocate heap resources using only the currentFrameAllocator m_renderView->setRenderer(m_renderer); - m_renderView->setSurfaceSize(m_surfaceSize); - m_renderView->setDevicePixelRatio(m_devicePixelRatio); // Populate the renderview's configuration from the framegraph setRenderViewConfigFromFrameGraphLeafNode(m_renderView, m_fgLeaf); diff --git a/src/render/jobs/renderviewinitializerjob_p.h b/src/render/jobs/renderviewinitializerjob_p.h index dbc80c162..0ee017df9 100644 --- a/src/render/jobs/renderviewinitializerjob_p.h +++ b/src/render/jobs/renderviewinitializerjob_p.h @@ -73,8 +73,6 @@ public: ~RenderViewInitializerJob(); inline void setRenderer(Renderer *renderer) { m_renderer = renderer; } - inline void setSurfaceSize(const QSize &size) { m_surfaceSize = size; } - inline void setDevicePixelRatio(qreal r) { m_devicePixelRatio = r; } inline RenderView *renderView() const Q_DECL_NOTHROW { return m_renderView; } inline void setFrameGraphLeafNode(FrameGraphNode *fgLeaf) @@ -88,14 +86,12 @@ public: // a shadow map texture is submitted before the RenderView that // contains commands making use of the shadow map inline void setSubmitOrderIndex(int index) { m_index = index; } + inline int submitOrderIndex() const { return m_index; } -protected: void run() Q_DECL_OVERRIDE; private: Renderer *m_renderer; - QSize m_surfaceSize; - qreal m_devicePixelRatio; FrameGraphNode *m_fgLeaf; int m_index; RenderView *m_renderView; diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp index 765e5e1de..d6dcd7f30 100644 --- a/src/render/jobs/renderviewjobutils.cpp +++ b/src/render/jobs/renderviewjobutils.cpp @@ -62,6 +62,7 @@ #include <Qt3DRender/private/statesetnode_p.h> #include <Qt3DRender/private/dispatchcompute_p.h> #include <Qt3DRender/private/rendersurfaceselector_p.h> +#include <Qt3DRender/private/rendercapture_p.h> #include <Qt3DRender/private/stringtoint_p.h> QT_BEGIN_NAMESPACE @@ -223,6 +224,15 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN } break; } + case FrameGraphNode::RenderCapture: { + auto *renderCapture = const_cast<Render::RenderCapture *>( + static_cast<const Render::RenderCapture *>(node)); + if (rv->renderCaptureNodeId().isNull() && renderCapture->wasCaptureRequested()) { + renderCapture->acknowledgeCaptureRequest(); + rv->setRenderCaptureNodeId(renderCapture->peerId()); + } + break; + } default: // Should never get here @@ -253,8 +263,8 @@ Technique *findTechniqueForEffect(Renderer *renderer, for (const QNodeId techniqueId : techniqueIds) { Technique *technique = manager->techniqueManager()->lookupResource(techniqueId); - if (!technique) - continue; + // Should be valid, if not there likely a problem with node addition/destruction changes + Q_ASSERT(technique); // We need to be sure the renderer is still running <=> still has a GraphicsContext if (renderer->isRunning() && *renderer->contextInfo() == *technique->graphicsApiFilter()) { @@ -384,7 +394,7 @@ void addParametersForIds(ParameterInfoList *params, ParameterManager *manager, Parameter *param = manager->lookupResource(paramId); ParameterInfoList::iterator it = std::lower_bound(params->begin(), params->end(), param->nameId()); if (it == params->end() || it->nameId != param->nameId()) - params->insert(it, ParameterInfo(param->nameId(), param->value())); + params->insert(it, ParameterInfo(param->nameId(), param->uniformValue())); } } @@ -493,7 +503,7 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapStructHelper(Shader } } -ParameterInfo::ParameterInfo(const int nameId, const QVariant &value) +ParameterInfo::ParameterInfo(const int nameId, const UniformValue &value) : nameId(nameId) , value(value) {} diff --git a/src/render/jobs/renderviewjobutils_p.h b/src/render/jobs/renderviewjobutils_p.h index fa133ef4c..ad86685a9 100644 --- a/src/render/jobs/renderviewjobutils_p.h +++ b/src/render/jobs/renderviewjobutils_p.h @@ -56,6 +56,7 @@ #include <QtCore/qhash.h> #include <QtCore/qvariant.h> #include <QMatrix4x4> +#include <Qt3DRender/private/uniform_p.h> QT_BEGIN_NAMESPACE @@ -107,15 +108,14 @@ Q_AUTOTEST_EXPORT inline T variant_value(const QVariant &v) struct ParameterInfo { - explicit ParameterInfo(const int nameId = -1, const QVariant &value = QVariant()); + explicit ParameterInfo(const int nameId = -1, const UniformValue &value = UniformValue()); int nameId; - QVariant value; + UniformValue value; bool operator<(const int otherNameId) const Q_DECL_NOEXCEPT; bool operator<(const ParameterInfo &other) const Q_DECL_NOEXCEPT; }; -QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, ParameterInfo, Q_MOVABLE_TYPE) typedef QVector<ParameterInfo> ParameterInfoList; struct RenderPassParameterData diff --git a/src/render/jobs/sendrendercapturejob.cpp b/src/render/jobs/sendrendercapturejob.cpp new file mode 100644 index 000000000..6dd9387e0 --- /dev/null +++ b/src/render/jobs/sendrendercapturejob.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sendrendercapturejob_p.h" + +#include "Qt3DRender/private/renderer_p.h" +#include "Qt3DRender/private/nodemanagers_p.h" +#include "Qt3DRender/private/rendercapture_p.h" +#include <Qt3DRender/private/job_common_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +SendRenderCaptureJob::SendRenderCaptureJob(Renderer *renderer) + : Qt3DCore::QAspectJob() + , m_renderer(renderer) +{ + SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendRenderCapture, 0); +} + +SendRenderCaptureJob::~SendRenderCaptureJob() +{ + +} + +void SendRenderCaptureJob::setManagers(NodeManagers *managers) +{ + m_managers = managers; +} + +void SendRenderCaptureJob::run() +{ + const auto pendingCaptures = m_renderer->takePendingRenderCaptureSendRequests(); + for (Qt3DCore::QNodeId id : pendingCaptures) { + auto *node = static_cast<Qt3DRender::Render::RenderCapture *> + (m_managers->frameGraphManager()->lookupNode(id)); + node->sendRenderCaptures(); + } +} + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/jobs/sendrendercapturejob_p.h b/src/render/jobs/sendrendercapturejob_p.h new file mode 100644 index 000000000..a6a7f7e79 --- /dev/null +++ b/src/render/jobs/sendrendercapturejob_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SENDRENDERCAPTUREJOB_P_H +#define SENDRENDERCAPTUREJOB_P_H + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DCore/qaspectjob.h> +#include <Qt3DRender/qt3drender_global.h> +#include <Qt3DRender/private/qt3drender_global_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class NodeManagers; +class Entity; +class Renderer; + +class QT3DRENDERSHARED_PRIVATE_EXPORT SendRenderCaptureJob : public Qt3DCore::QAspectJob +{ +public: + explicit SendRenderCaptureJob(Renderer *renderer); + ~SendRenderCaptureJob(); + + void setManagers(NodeManagers *managers); + + void run() Q_DECL_FINAL; + +private: + Renderer *m_renderer; + NodeManagers *m_managers; +}; + +typedef QSharedPointer<SendRenderCaptureJob> SendRenderCaptureJobPtr; + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // SENDRENDERCAPTUREJOB_P_H diff --git a/src/render/jobs/updatemeshtrianglelistjob.cpp b/src/render/jobs/updatemeshtrianglelistjob.cpp new file mode 100644 index 000000000..dd3934948 --- /dev/null +++ b/src/render/jobs/updatemeshtrianglelistjob.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "updatemeshtrianglelistjob_p.h" +#include <Qt3DRender/private/job_common_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DRender/private/light_p.h> +#include <Qt3DRender/private/sphere_p.h> +#include <Qt3DRender/private/attribute_p.h> +#include <Qt3DRender/private/geometryrenderer_p.h> +#include <Qt3DRender/private/geometry_p.h> +#include <Qt3DRender/private/attribute_p.h> +#include <Qt3DRender/private/buffer_p.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/buffermanager_p.h> +#include <Qt3DRender/private/geometryrenderermanager_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +UpdateMeshTriangleListJob::UpdateMeshTriangleListJob() + : m_manager(nullptr) +{ + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateMeshTriangleList, 0); +} + +UpdateMeshTriangleListJob::~UpdateMeshTriangleListJob() +{ +} + +void UpdateMeshTriangleListJob::setManagers(NodeManagers *manager) +{ + m_manager = manager; +} + +void UpdateMeshTriangleListJob::run() +{ + GeometryRendererManager *geomRenderermanager = m_manager->geometryRendererManager(); + GeometryManager *geomManager = m_manager->geometryManager(); + BufferManager *bufferManager = m_manager->bufferManager(); + AttributeManager *attributeManager = m_manager->attributeManager(); + + const QVector<HGeometryRenderer> handles = geomRenderermanager->activeHandles(); + + for (const HGeometryRenderer handle : handles) { + // Look if for the GeometryRender/Geometry the attributes and or buffers are dirty + // in which case we need to recompute the triangle list + const GeometryRenderer *geomRenderer = geomRenderermanager->data(handle); + if (geomRenderer != nullptr) { + const Geometry *geom = geomManager->lookupResource(geomRenderer->geometryId()); + if (geom != nullptr) { + const Qt3DCore::QNodeId geomRendererId = geomRenderer->peerId(); + if (!geomRenderermanager->isGeometryRendererScheduledForTriangleDataRefresh(geomRendererId)) { + // Check if the attributes or buffers are dirty + bool dirty = geomRenderer->isDirty(); + const auto attrIds = geom->attributes(); + for (const Qt3DCore::QNodeId attrId : attrIds) { + const Attribute *attr = attributeManager->lookupResource(attrId); + if (attr != nullptr) { + dirty |= attr->isDirty(); + if (!dirty) { + const Buffer *buffer = bufferManager->lookupResource(attr->bufferId()); + if (buffer != nullptr) + dirty = buffer->isDirty(); + } + if (dirty) + break; + } + } + if (dirty) + m_manager->geometryRendererManager()->requestTriangleDataRefreshForGeometryRenderer(geomRendererId); + } + } + } + } +} + +NodeManagers *UpdateMeshTriangleListJob::managers() const +{ + return m_manager; +} + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/jobs/updatemeshtrianglelistjob_p.h b/src/render/jobs/updatemeshtrianglelistjob_p.h new file mode 100644 index 000000000..9c0383739 --- /dev/null +++ b/src/render/jobs/updatemeshtrianglelistjob_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_UPDATEMESHTRIANGLELISTJOB_H +#define QT3DRENDER_RENDER_UPDATEMESHTRIANGLELISTJOB_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DCore/qaspectjob.h> +#include <Qt3DRender/private/qt3drender_global_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class NodeManagers; + +class QT3DRENDERSHARED_PRIVATE_EXPORT UpdateMeshTriangleListJob : public Qt3DCore::QAspectJob +{ +public: + UpdateMeshTriangleListJob(); + ~UpdateMeshTriangleListJob(); + + void setManagers(NodeManagers *manager); + void run() Q_DECL_FINAL; + + NodeManagers *managers() const; + +private: + NodeManagers *m_manager; +}; + +typedef QSharedPointer<UpdateMeshTriangleListJob> UpdateMeshTriangleListJobPtr; + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_UPDATEMESHTRIANGLELISTJOB_H diff --git a/src/render/jobs/framepreparationjob.cpp b/src/render/jobs/updateshaderdatatransformjob.cpp index ef5b4bdb4..243edb4f7 100644 --- a/src/render/jobs/framepreparationjob.cpp +++ b/src/render/jobs/updateshaderdatatransformjob.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "framepreparationjob_p.h" +#include "updateshaderdatatransformjob_p.h" #include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/entity_p.h> #include <Qt3DRender/private/shaderdata_p.h> @@ -58,71 +58,38 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { -FramePreparationJob::FramePreparationJob() - : m_root(nullptr) - , m_manager(nullptr) +UpdateShaderDataTransformJob::UpdateShaderDataTransformJob() + : m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::FramePreparation, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateShaderDataTransform, 0); } -FramePreparationJob::~FramePreparationJob() +UpdateShaderDataTransformJob::~UpdateShaderDataTransformJob() { } -void FramePreparationJob::setRoot(Entity *root) -{ - m_root = root; -} - -void FramePreparationJob::setManagers(NodeManagers *manager) +void UpdateShaderDataTransformJob::setManagers(NodeManagers *manager) { m_manager = manager; } -void FramePreparationJob::run() +NodeManagers *UpdateShaderDataTransformJob::managers() const { - parseNodeTree(m_root); + return m_manager; } -void FramePreparationJob::parseNodeTree(Entity *node) +void UpdateShaderDataTransformJob::run() { - // Update transform properties in ShaderDatas and Lights - const QVector<ShaderData *> shaderDatas = node->renderComponents<ShaderData>(); - for (ShaderData *r : shaderDatas) - r->updateWorldTransform(*node->worldTransform()); + EntityManager *manager = m_manager->renderNodesManager(); + const QVector<HEntity> handles = manager->activeHandles(); - // Look if for the GeometryRender/Geometry the attributes and or buffers are dirty - // in which case we need to recompute the triangle list - GeometryRenderer *geomRenderer = node->renderComponent<GeometryRenderer>(); - const Qt3DCore::QNodeId geomRendererId = node->componentUuid<GeometryRenderer>(); - Geometry *geom = nullptr; - if (geomRenderer && - (geom = m_manager->lookupResource<Geometry, GeometryManager>(geomRenderer->geometryId())) != nullptr) { - if (!m_manager->geometryRendererManager()->isGeometryRendererScheduledForTriangleDataRefresh(geomRendererId)) { - // Check if the attributes or buffers are dirty - bool dirty = geomRenderer->isDirty(); - Attribute *attr = nullptr; - const auto attrIds = geom->attributes(); - for (const Qt3DCore::QNodeId attrId : attrIds) { - if ((attr = m_manager->attributeManager()->lookupResource(attrId)) != nullptr) { - dirty |= attr->isDirty(); - if (!dirty) { - Buffer *buffer = nullptr; - if ((buffer = m_manager->bufferManager()->lookupResource(attr->bufferId())) != nullptr) - dirty = buffer->isDirty(); - } - if (dirty) - break; - } - } - if (dirty) - m_manager->geometryRendererManager()->requestTriangleDataRefreshForGeometryRenderer(geomRendererId); - } + for (const HEntity handle : handles) { + Entity *node = manager->data(handle); + // Update transform properties in ShaderDatas and Lights + const QVector<ShaderData *> shaderDatas = node->renderComponents<ShaderData>(); + for (ShaderData *r : shaderDatas) + r->updateWorldTransform(*node->worldTransform()); } - - const QVector<Entity *> children = node->children(); - for (Entity *c : children) - parseNodeTree(c); } } // namespace Render diff --git a/src/render/jobs/framepreparationjob_p.h b/src/render/jobs/updateshaderdatatransformjob_p.h index 35db5862d..6fe365b6b 100644 --- a/src/render/jobs/framepreparationjob_p.h +++ b/src/render/jobs/updateshaderdatatransformjob_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QT3DRENDER_RENDER_FRAMEPREPARATIONJOB_H -#define QT3DRENDER_RENDER_FRAMEPREPARATIONJOB_H +#ifndef QT3DRENDER_RENDER_UPDATESHADERDATATRANSFORMJOB_H +#define QT3DRENDER_RENDER_UPDATESHADERDATATRANSFORMJOB_H // // W A R N I N G @@ -61,28 +61,23 @@ namespace Qt3DRender { namespace Render { class NodeManagers; -class Entity; -class QT3DRENDERSHARED_PRIVATE_EXPORT FramePreparationJob : public Qt3DCore::QAspectJob +class QT3DRENDERSHARED_PRIVATE_EXPORT UpdateShaderDataTransformJob : public Qt3DCore::QAspectJob { public: - FramePreparationJob(); - ~FramePreparationJob(); + UpdateShaderDataTransformJob(); + ~UpdateShaderDataTransformJob(); - void setRoot(Entity *root); void setManagers(NodeManagers *manager); + NodeManagers *managers() const; -protected: void run() Q_DECL_FINAL; private: - void parseNodeTree(Entity *node); - - Entity *m_root; NodeManagers *m_manager; }; -typedef QSharedPointer<FramePreparationJob> FramePreparationJobPtr; +typedef QSharedPointer<UpdateShaderDataTransformJob> UpdateShaderDataTransformJobPtr; } // namespace Render @@ -90,4 +85,4 @@ typedef QSharedPointer<FramePreparationJob> FramePreparationJobPtr; QT_END_NAMESPACE -#endif // QT3DRENDER_RENDER_FRAMEPREPARATIONJOB_H +#endif // QT3DRENDER_RENDER_UPDATESHADERDATATRANSFORMJOB_H diff --git a/src/render/jobs/updateworldboundingvolumejob_p.h b/src/render/jobs/updateworldboundingvolumejob_p.h index 06e8f1005..14717eb4e 100644 --- a/src/render/jobs/updateworldboundingvolumejob_p.h +++ b/src/render/jobs/updateworldboundingvolumejob_p.h @@ -68,8 +68,6 @@ public: UpdateWorldBoundingVolumeJob(); inline void setManager(EntityManager *manager) Q_DECL_NOTHROW { m_manager = manager; } - -protected: void run() Q_DECL_OVERRIDE; private: diff --git a/src/render/jobs/updateworldtransformjob_p.h b/src/render/jobs/updateworldtransformjob_p.h index 11c2dce21..70e54b840 100644 --- a/src/render/jobs/updateworldtransformjob_p.h +++ b/src/render/jobs/updateworldtransformjob_p.h @@ -69,8 +69,6 @@ public: UpdateWorldTransformJob(); void setRoot(Entity *root); - -protected: void run() Q_DECL_OVERRIDE; private: diff --git a/src/render/lights/light_p.h b/src/render/lights/light_p.h index 31901bf11..19deb1bcc 100644 --- a/src/render/lights/light_p.h +++ b/src/render/lights/light_p.h @@ -92,6 +92,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::Render::Light*) +Q_DECLARE_METATYPE(Qt3DRender::Render::Light*) // LCOV_EXCL_LINE #endif // QT3DRENDER_RENDER_LIGHT_P_H diff --git a/src/render/lights/qabstractlight.h b/src/render/lights/qabstractlight.h index 7cc98b57b..33a88b215 100644 --- a/src/render/lights/qabstractlight.h +++ b/src/render/lights/qabstractlight.h @@ -67,7 +67,7 @@ public: DirectionalLight, SpotLight }; - Q_ENUM(Type) + Q_ENUM(Type) // LCOV_EXCL_LINE Type type() const; QColor color() const; diff --git a/src/render/materialsystem/effect.cpp b/src/render/materialsystem/effect.cpp index 8e25e74fc..29d05ed01 100644 --- a/src/render/materialsystem/effect.cpp +++ b/src/render/materialsystem/effect.cpp @@ -69,6 +69,8 @@ Effect::~Effect() void Effect::cleanup() { QBackendNode::setEnabled(false); + m_parameterPack.clear(); + m_techniques.clear(); } void Effect::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) diff --git a/src/render/materialsystem/effect_p.h b/src/render/materialsystem/effect_p.h index 50d470d8e..62435b582 100644 --- a/src/render/materialsystem/effect_p.h +++ b/src/render/materialsystem/effect_p.h @@ -63,7 +63,7 @@ class QTechnique; namespace Render { -class Effect : public BackendNode +class Q_AUTOTEST_EXPORT Effect : public BackendNode { public: Effect(); diff --git a/src/render/materialsystem/filterkey.cpp b/src/render/materialsystem/filterkey.cpp index db139f1fe..fd911c419 100644 --- a/src/render/materialsystem/filterkey.cpp +++ b/src/render/materialsystem/filterkey.cpp @@ -60,6 +60,9 @@ FilterKey::~FilterKey() void FilterKey::cleanup() { + QBackendNode::setEnabled(false); + m_name.clear(); + m_value.clear(); } void FilterKey::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) @@ -70,12 +73,12 @@ void FilterKey::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &ch m_value = data.value; } -QVariant FilterKey::criterionValue() const +QVariant FilterKey::value() const { return m_value; } -QString FilterKey::criterionName() const +QString FilterKey::name() const { return m_name; } @@ -103,8 +106,8 @@ bool FilterKey::operator ==(const FilterKey &other) { if (&other == this) return true; - return ((other.criterionName() == criterionName()) && - (other.criterionValue() == criterionValue())); + return ((other.name() == name()) && + (other.value() == value())); } bool FilterKey::operator !=(const FilterKey &other) diff --git a/src/render/materialsystem/filterkey_p.h b/src/render/materialsystem/filterkey_p.h index 8291e32f0..4aea3d78a 100644 --- a/src/render/materialsystem/filterkey_p.h +++ b/src/render/materialsystem/filterkey_p.h @@ -62,15 +62,15 @@ class QFilterKey; namespace Render { -class FilterKey : public BackendNode +class Q_AUTOTEST_EXPORT FilterKey : public BackendNode { public: FilterKey(); ~FilterKey(); void cleanup(); - QVariant criterionValue() const; - QString criterionName() const; + QVariant value() const; + QString name() const; void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; bool operator ==(const FilterKey &other); bool operator !=(const FilterKey &other); diff --git a/src/render/materialsystem/material_p.h b/src/render/materialsystem/material_p.h index b415e2975..fe2707549 100644 --- a/src/render/materialsystem/material_p.h +++ b/src/render/materialsystem/material_p.h @@ -54,7 +54,7 @@ #include <QVariant> #include <Qt3DRender/private/backendnode_p.h> -#include <Qt3DRender/private/quniformvalue_p.h> +#include <Qt3DRender/private/shaderparameterpack_p.h> #include <Qt3DRender/private/parameterpack_p.h> QT_BEGIN_NAMESPACE diff --git a/src/render/materialsystem/parameter.cpp b/src/render/materialsystem/parameter.cpp index b13c0d5ae..9c40c199a 100644 --- a/src/render/materialsystem/parameter.cpp +++ b/src/render/materialsystem/parameter.cpp @@ -62,13 +62,21 @@ Parameter::Parameter() { } +void Parameter::cleanup() +{ + QBackendNode::setEnabled(false); + m_nameId = -1; + m_name.clear(); + m_uniformValue = UniformValue(); +} + void Parameter::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) { const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QParameterData>>(change); const auto &data = typedChange->data; m_name = data.name; m_nameId = StringToInt::lookupId(m_name); - m_value = data.backendValue; + m_uniformValue = UniformValue::fromVariant(data.backendValue); } void Parameter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -80,7 +88,7 @@ void Parameter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) m_name = propertyChange->value().toString(); m_nameId = StringToInt::lookupId(m_name); } else if (propertyChange->propertyName() == QByteArrayLiteral("value")) { - m_value = propertyChange->value(); + m_uniformValue = UniformValue::fromVariant(propertyChange->value()); } markDirty(AbstractRenderer::AllDirty); } @@ -93,14 +101,14 @@ QString Parameter::name() const return m_name; } -QVariant Parameter::value() const +int Parameter::nameId() const Q_DECL_NOTHROW { - return m_value; + return m_nameId; } -int Parameter::nameId() const Q_DECL_NOTHROW +UniformValue Parameter::uniformValue() const { - return m_nameId; + return m_uniformValue; } } // namespace Render diff --git a/src/render/materialsystem/parameter_p.h b/src/render/materialsystem/parameter_p.h index c5c94243d..6830ef07d 100644 --- a/src/render/materialsystem/parameter_p.h +++ b/src/render/materialsystem/parameter_p.h @@ -52,6 +52,7 @@ // #include <Qt3DRender/private/backendnode_p.h> +#include <Qt3DRender/private/uniform_p.h> #include <QVariant> QT_BEGIN_NAMESPACE @@ -62,24 +63,25 @@ namespace Render { class ParameterManager; class ShaderDataManager; -class TextureManager; -class Parameter : public BackendNode +class Q_AUTOTEST_EXPORT Parameter : public BackendNode { public: Parameter(); + void cleanup(); + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; QString name() const; - QVariant value() const; int nameId() const Q_DECL_NOTHROW; + UniformValue uniformValue() const; private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; QString m_name; - QVariant m_value; + UniformValue m_uniformValue; int m_nameId; }; diff --git a/src/render/materialsystem/qgraphicsapifilter.h b/src/render/materialsystem/qgraphicsapifilter.h index c618358dd..488d8bd4b 100644 --- a/src/render/materialsystem/qgraphicsapifilter.h +++ b/src/render/materialsystem/qgraphicsapifilter.h @@ -67,14 +67,14 @@ public: OpenGLES = QSurfaceFormat::OpenGLES, OpenGL = QSurfaceFormat::OpenGL }; - Q_ENUM(Api) + Q_ENUM(Api) // LCOV_EXCL_LINE enum OpenGLProfile { NoProfile = QSurfaceFormat::NoProfile, CoreProfile = QSurfaceFormat::CoreProfile, CompatibilityProfile = QSurfaceFormat::CompatibilityProfile }; - Q_ENUM(OpenGLProfile) + Q_ENUM(OpenGLProfile) // LCOV_EXCL_LINE explicit QGraphicsApiFilter(QObject *parent = nullptr); ~QGraphicsApiFilter(); diff --git a/src/render/materialsystem/qgraphicsapifilter_p.h b/src/render/materialsystem/qgraphicsapifilter_p.h index fed9df2ab..723eb14c2 100644 --- a/src/render/materialsystem/qgraphicsapifilter_p.h +++ b/src/render/materialsystem/qgraphicsapifilter_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { -struct GraphicsApiFilterData +struct Q_AUTOTEST_EXPORT GraphicsApiFilterData { GraphicsApiFilterData(); @@ -74,7 +74,7 @@ struct GraphicsApiFilterData bool operator <(const GraphicsApiFilterData &other) const; }; -class QGraphicsApiFilterPrivate : public QObjectPrivate +class Q_AUTOTEST_EXPORT QGraphicsApiFilterPrivate : public QObjectPrivate { public: QGraphicsApiFilterPrivate() @@ -92,6 +92,6 @@ public: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::GraphicsApiFilterData); +Q_DECLARE_METATYPE(Qt3DRender::GraphicsApiFilterData); // LCOV_EXCL_LINE #endif // QT3DRENDER_QGRAPHICSAPIFILTER_P_H diff --git a/src/render/materialsystem/qshaderdata.h b/src/render/materialsystem/qshaderdata.h index 767f4043f..e695d1eb0 100644 --- a/src/render/materialsystem/qshaderdata.h +++ b/src/render/materialsystem/qshaderdata.h @@ -82,7 +82,7 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QShaderData*) -Q_DECLARE_METATYPE(QVector<Qt3DRender::QShaderData*>) +Q_DECLARE_METATYPE(Qt3DRender::QShaderData*) // LCOV_EXCL_LINE +Q_DECLARE_METATYPE(QVector<Qt3DRender::QShaderData*>) // LCOV_EXCL_LINE #endif // QT3DRENDER_QSHADERDATA_H diff --git a/src/render/materialsystem/qshaderprogram.h b/src/render/materialsystem/qshaderprogram.h index f5a577de5..442a25b2e 100644 --- a/src/render/materialsystem/qshaderprogram.h +++ b/src/render/materialsystem/qshaderprogram.h @@ -71,7 +71,7 @@ public: Geometry, Compute }; - Q_ENUM(ShaderType) + Q_ENUM(ShaderType) // LCOV_EXCL_LINE // Source code in-line QByteArray vertexShaderCode() const; diff --git a/src/render/materialsystem/renderpass.cpp b/src/render/materialsystem/renderpass.cpp index c589b3df6..e0fadddd9 100644 --- a/src/render/materialsystem/renderpass.cpp +++ b/src/render/materialsystem/renderpass.cpp @@ -70,6 +70,7 @@ RenderPass::~RenderPass() void RenderPass::cleanup() { + QBackendNode::setEnabled(false); m_renderStates.clear(); m_filterKeyList.clear(); m_parameterPack.clear(); diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h index 1382e287e..283e5a94c 100644 --- a/src/render/materialsystem/shader_p.h +++ b/src/render/materialsystem/shader_p.h @@ -52,7 +52,7 @@ // #include <Qt3DRender/private/backendnode_p.h> -#include <Qt3DRender/private/quniformvalue_p.h> +#include <Qt3DRender/private/shaderparameterpack_p.h> #include <Qt3DRender/private/shadervariables_p.h> #include <QMutex> #include <QVector> diff --git a/src/render/materialsystem/shaderdata_p.h b/src/render/materialsystem/shaderdata_p.h index 6ce0c734c..987687eab 100644 --- a/src/render/materialsystem/shaderdata_p.h +++ b/src/render/materialsystem/shaderdata_p.h @@ -145,6 +145,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::Render::ShaderData*) +Q_DECLARE_METATYPE(Qt3DRender::Render::ShaderData*) // LCOV_EXCL_LINE #endif // QT3DRENDER_RENDER_SHADERDATA_P_H diff --git a/src/render/materialsystem/technique.cpp b/src/render/materialsystem/technique.cpp index a3a650f7a..6ab64c9d3 100644 --- a/src/render/materialsystem/technique.cpp +++ b/src/render/materialsystem/technique.cpp @@ -51,6 +51,8 @@ #include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/qpropertynodeaddedchange.h> #include <Qt3DCore/qpropertynoderemovedchange.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> #include <QDebug> @@ -63,6 +65,8 @@ namespace Render { Technique::Technique() : BackendNode() + , m_isCompatibleWithRenderer(false) + , m_nodeManager(nullptr) { } @@ -77,6 +81,7 @@ void Technique::cleanup() m_parameterPack.clear(); m_renderPasses.clear(); m_filterKeyList.clear(); + m_isCompatibleWithRenderer = false; } void Technique::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) @@ -98,6 +103,9 @@ void Technique::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) if (change->propertyName() == QByteArrayLiteral("graphicsApiFilterData")) { GraphicsApiFilterData filterData = change->value().value<GraphicsApiFilterData>(); m_graphicsApiFilterData = filterData; + // Notify the manager that our graphicsApiFilterData has changed + // and that we therefore need to be check for compatibility again + m_isCompatibleWithRenderer = false; } break; } @@ -162,6 +170,55 @@ const GraphicsApiFilterData *Technique::graphicsApiFilter() const return &m_graphicsApiFilterData; } +bool Technique::isCompatibleWithRenderer() const +{ + return m_isCompatibleWithRenderer; +} + +void Technique::setCompatibleWithRenderer(bool compatible) +{ + m_isCompatibleWithRenderer = compatible; +} + +bool Technique::isCompatibleWithFilters(const QNodeIdVector &filterKeyIds) +{ + // There is a technique filter so we need to check for a technique with suitable criteria. + // Check for early bail out if the technique doesn't have sufficient number of criteria and + // can therefore never satisfy the filter + if (m_filterKeyList.size() < filterKeyIds.size()) + return false; + + // Iterate through the filter criteria and for each one search for a criteria on the + // technique that satisfies it + for (const QNodeId filterKeyId : filterKeyIds) { + FilterKey *filterKey = m_nodeManager->filterKeyManager()->lookupResource(filterKeyId); + + bool foundMatch = false; + + for (const QNodeId techniqueFilterKeyId : qAsConst(m_filterKeyList)) { + FilterKey *techniqueFilterKey = m_nodeManager->filterKeyManager()->lookupResource(techniqueFilterKeyId); + if ((foundMatch = (*techniqueFilterKey == *filterKey))) + break; + } + + // No match for TechniqueFilter criterion in any of the technique's criteria. + // So no way this can match. Don't bother checking the rest of the criteria. + if (!foundMatch) + return false; + } + return true; +} + +void Technique::setNodeManager(NodeManagers *nodeManager) +{ + m_nodeManager = nodeManager; +} + +NodeManagers *Technique::nodeManager() const +{ + return m_nodeManager; +} + void Technique::appendFilterKey(Qt3DCore::QNodeId criterionId) { if (!m_filterKeyList.contains(criterionId)) @@ -173,6 +230,31 @@ void Technique::removeFilterKey(Qt3DCore::QNodeId criterionId) m_filterKeyList.removeOne(criterionId); } +TechniqueFunctor::TechniqueFunctor(AbstractRenderer *renderer, NodeManagers *manager) + : m_manager(manager) + , m_renderer(renderer) +{ +} + +QBackendNode *TechniqueFunctor::create(const QNodeCreatedChangeBasePtr &change) const +{ + Technique *technique = m_manager->techniqueManager()->getOrCreateResource(change->subjectId()); + technique->setNodeManager(m_manager); + technique->setRenderer(m_renderer); + return technique; +} + +QBackendNode *TechniqueFunctor::get(QNodeId id) const +{ + return m_manager->techniqueManager()->lookupResource(id); +} + +void TechniqueFunctor::destroy(QNodeId id) const +{ + m_manager->techniqueManager()->releaseResource(id); + +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/materialsystem/technique_p.h b/src/render/materialsystem/technique_p.h index 541076a0b..85fa09c02 100644 --- a/src/render/materialsystem/technique_p.h +++ b/src/render/materialsystem/technique_p.h @@ -73,7 +73,7 @@ namespace Render { class TechniqueManager; -class Technique : public BackendNode +class Q_AUTOTEST_EXPORT Technique : public BackendNode { public: Technique(); @@ -93,6 +93,14 @@ public: QVector<Qt3DCore::QNodeId> renderPasses() const; const GraphicsApiFilterData *graphicsApiFilter() const; + bool isCompatibleWithRenderer() const; + void setCompatibleWithRenderer(bool compatible); + + bool isCompatibleWithFilters(const Qt3DCore::QNodeIdVector &filterKeyIds); + + void setNodeManager(NodeManagers *nodeManager); + NodeManagers *nodeManager() const; + private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; @@ -100,6 +108,20 @@ private: ParameterPack m_parameterPack; QVector<Qt3DCore::QNodeId> m_filterKeyList; QVector<Qt3DCore::QNodeId> m_renderPasses; + bool m_isCompatibleWithRenderer; + NodeManagers *m_nodeManager; +}; + +class TechniqueFunctor : public Qt3DCore::QBackendNodeMapper +{ +public: + explicit TechniqueFunctor(AbstractRenderer *renderer, NodeManagers *manager); + Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_OVERRIDE; + Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE; + void destroy(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE; +private: + NodeManagers *m_manager; + AbstractRenderer *m_renderer; }; } // namespace Render diff --git a/src/render/picking/qpickevent.cpp b/src/render/picking/qpickevent.cpp index ee9d6e867..c29c13cff 100644 --- a/src/render/picking/qpickevent.cpp +++ b/src/render/picking/qpickevent.cpp @@ -77,16 +77,34 @@ QPickEvent::QPickEvent() \fn Qt3DRender::QPickEvent::QPickEvent(const QPointF &position, const QVector3D &intersection, const QVector3D &localIntersection, float distance) Constructs a new QPickEvent with the given parameters: \a position, \a intersection, \a localIntersection and \a distance */ -QPickEvent::QPickEvent(const QPointF &position, const QVector3D &intersection, const QVector3D &localIntersection, float distance) +// NOTE: remove in Qt6 +QPickEvent::QPickEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance) : QObject(*new QPickEventPrivate()) { Q_D(QPickEvent); d->m_position = position; d->m_distance = distance; - d->m_worldIntersection = intersection; + d->m_worldIntersection = worldIntersection; d->m_localIntersection = localIntersection; } +/*! + \fn Qt3DRender::QPickEvent::QPickEvent(const QPointF &position, const QVector3D &intersection, const QVector3D &localIntersection, float distance) + Constructs a new QPickEvent with the given parameters: \a position, \a intersection, \a localIntersection, \a distance, \a button, \a buttons and \a modifiers + */ +QPickEvent::QPickEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance, QPickEvent::Buttons button, int buttons, int modifiers) + : QObject(*new QPickEventPrivate()) +{ + Q_D(QPickEvent); + d->m_position = position; + d->m_distance = distance; + d->m_worldIntersection = worldIntersection; + d->m_localIntersection = localIntersection; + d->m_button = button; + d->m_buttons = buttons; + d->m_modifiers = modifiers; +} + /*! \internal */ QPickEvent::QPickEvent(QObjectPrivate &dd, QObject *parent) : QObject(dd, parent) @@ -200,6 +218,81 @@ QVector3D QPickEvent::localIntersection() const return d->m_localIntersection; } +/*! + * \enum Qt3DRender::QPickEvent::Buttons + * + * \value LeftButton + * \value RightButton + * \value MiddleButton + * \value BackButton + * \value NoButton + */ + +/*! + \qmlproperty bool Qt3D.Render::PickEvent::button + Specifies mouse button that caused the event +*/ +/*! + \property Qt3DRender::QPickEvent::button + Specifies mouse button that caused the event + */ +/*! + * \brief QPickEvent::button + * \return mouse button that caused the event + */ +QPickEvent::Buttons QPickEvent::button() const +{ + Q_D(const QPickEvent); + return d->m_button; +} + +/*! + \qmlproperty bool Qt3D.Render::PickEvent::buttons + Specifies state of the mouse buttons for the event +*/ +/*! + \property Qt3DRender::QPickEvent::buttons + Specifies state of the mouse buttons for the event + */ +/*! + * \brief QPickEvent::buttons + * \return bitfield to be used to check for mouse buttons that may be accompanying the pick event. + */ +int QPickEvent::buttons() const +{ + Q_D(const QPickEvent); + return d->m_buttons; +} + +/*! + * \enum Qt3DRender::QPickEvent::Modifiers + * + * \value NoModifier + * \value ShiftModifier + * \value ControlModifier + * \value AltModifier + * \value MetaModifier + * \value KeypadModifier + */ + +/*! + \qmlproperty bool Qt3D.Render::PickEvent::modifiers + Specifies state of the mouse buttons for the event +*/ +/*! + \property Qt3DRender::QPickEvent::modifiers + Specifies state of the mouse buttons for the event + */ +/*! + * \brief QPickEvent::modifiers + * \return bitfield to be used to check for keyboard modifiers that may be accompanying the pick event. + */ +int QPickEvent::modifiers() const +{ + Q_D(const QPickEvent); + return d->m_modifiers; +} + } // Qt3DRender QT_END_NAMESPACE diff --git a/src/render/picking/qpickevent.h b/src/render/picking/qpickevent.h index 431fe1927..3fbee0d30 100644 --- a/src/render/picking/qpickevent.h +++ b/src/render/picking/qpickevent.h @@ -62,9 +62,32 @@ class QT3DRENDERSHARED_EXPORT QPickEvent : public QObject Q_PROPERTY(float distance READ distance CONSTANT) Q_PROPERTY(QVector3D localIntersection READ localIntersection CONSTANT) Q_PROPERTY(QVector3D worldIntersection READ worldIntersection CONSTANT) + Q_PROPERTY(Qt3DRender::QPickEvent::Buttons button READ button CONSTANT) + Q_PROPERTY(int buttons READ buttons CONSTANT) + Q_PROPERTY(int modifiers READ modifiers CONSTANT) public: + enum Buttons { + LeftButton = Qt::LeftButton, + RightButton = Qt::RightButton, + MiddleButton = Qt::MiddleButton, + BackButton = Qt::BackButton, + NoButton = Qt::NoButton + }; + Q_ENUM(Buttons) // LCOV_EXCL_LINE + + enum Modifiers { + NoModifier = Qt::NoModifier, + ShiftModifier = Qt::ShiftModifier, + ControlModifier = Qt::ControlModifier, + AltModifier = Qt::AltModifier, + MetaModifier = Qt::MetaModifier, + KeypadModifier = Qt::KeypadModifier + }; + Q_ENUM(Modifiers) // LCOV_EXCL_LINE + QPickEvent(); QPickEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance); + QPickEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance, Buttons button, int buttons, int modifiers); ~QPickEvent(); bool isAccepted() const; @@ -77,6 +100,9 @@ public: float distance() const; QVector3D worldIntersection() const; QVector3D localIntersection() const; + Buttons button() const; + int buttons() const; + int modifiers() const; Q_SIGNALS: void acceptedChanged(bool accepted); @@ -92,6 +118,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QPickEvent*) +Q_DECLARE_METATYPE(Qt3DRender::QPickEvent*) // LCOV_EXCL_LINE #endif // QT3DRENDER_QPICKEVENT_H diff --git a/src/render/picking/qpickevent_p.h b/src/render/picking/qpickevent_p.h index fd9ed36a2..399795619 100644 --- a/src/render/picking/qpickevent_p.h +++ b/src/render/picking/qpickevent_p.h @@ -61,6 +61,9 @@ public: : QObjectPrivate() , m_accepted(true) , m_distance(-1.f) + , m_button(QPickEvent::NoButton) + , m_buttons(QPickEvent::NoButton) + , m_modifiers(QPickEvent::NoModifier) { } @@ -69,6 +72,9 @@ public: QVector3D m_worldIntersection; QVector3D m_localIntersection; float m_distance; + QPickEvent::Buttons m_button; + int m_buttons; + int m_modifiers; }; } // Qt3DRender diff --git a/src/render/picking/qpicktriangleevent.cpp b/src/render/picking/qpicktriangleevent.cpp index b636638e6..5c77b3ab8 100644 --- a/src/render/picking/qpicktriangleevent.cpp +++ b/src/render/picking/qpicktriangleevent.cpp @@ -69,7 +69,7 @@ public: \brief The QPickTriangleEvent class holds information when a triangle is picked - \sa QPickEvent, QPickSettings + \sa QPickEvent \since 5.7 */ @@ -78,7 +78,7 @@ public: * \instantiates Qt3DRender::QPickTriangleEvent * \inqmlmodule Qt3D.Render * \brief PickTriangleEvent holds information when a triangle is picked. - * \sa ObjectPicker, PickSettings + * \sa ObjectPicker */ @@ -102,14 +102,15 @@ QPickTriangleEvent::QPickTriangleEvent() * \a vertex2Index and * \a vertex3Index */ -QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D &intersection, const QVector3D &localIntersection, float distance, +// NOTE: remove in Qt6 +QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance, uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index) : QPickEvent(*new QPickTriangleEventPrivate()) { Q_D(QPickTriangleEvent); d->m_position = position; d->m_distance = distance; - d->m_worldIntersection = intersection; + d->m_worldIntersection = worldIntersection; d->m_localIntersection = localIntersection; d->m_triangleIndex = triangleIndex; d->m_vertex1Index = vertex1Index; @@ -117,6 +118,23 @@ QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D d->m_vertex3Index = vertex3Index; } +QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance, uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index, QPickEvent::Buttons button, int buttons, int modifiers) + : QPickEvent(*new QPickTriangleEventPrivate()) +{ + Q_D(QPickTriangleEvent); + d->m_position = position; + d->m_distance = distance; + d->m_worldIntersection = worldIntersection; + d->m_localIntersection = localIntersection; + d->m_triangleIndex = triangleIndex; + d->m_vertex1Index = vertex1Index; + d->m_vertex2Index = vertex2Index; + d->m_vertex3Index = vertex3Index; + d->m_button = button; + d->m_buttons = buttons; + d->m_modifiers = modifiers; +} + /*! \internal */ QPickTriangleEvent::~QPickTriangleEvent() { @@ -132,7 +150,7 @@ QPickTriangleEvent::~QPickTriangleEvent() */ /*! * \brief QPickTriangleEvent::triangleIndex - * \return the index of the picked triangle + * Returns the index of the picked triangle */ uint QPickTriangleEvent::triangleIndex() const { @@ -150,7 +168,7 @@ uint QPickTriangleEvent::triangleIndex() const */ /*! * \brief QPickTriangleEvent::vertex1Index - * \returns index of first point of picked triangle + * Returns the index of the first point of the picked triangle */ uint QPickTriangleEvent::vertex1Index() const { @@ -168,7 +186,7 @@ uint QPickTriangleEvent::vertex1Index() const */ /*! * \brief QPickTriangleEvent::vertex2Index - * \returns index of second point of picked triangle + * Returns the index of the second point of the picked triangle */ uint QPickTriangleEvent::vertex2Index() const { diff --git a/src/render/picking/qpicktriangleevent.h b/src/render/picking/qpicktriangleevent.h index e60a81dd6..7cafa1aeb 100644 --- a/src/render/picking/qpicktriangleevent.h +++ b/src/render/picking/qpicktriangleevent.h @@ -58,6 +58,8 @@ public: QPickTriangleEvent(); QPickTriangleEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance, uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index); + QPickTriangleEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance, + uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index, Buttons button, int buttons, int modifiers); ~QPickTriangleEvent(); public: diff --git a/src/render/raycasting/qabstractcollisionqueryservice_p.h b/src/render/raycasting/qabstractcollisionqueryservice_p.h index a2bb7873b..d26eacb98 100644 --- a/src/render/raycasting/qabstractcollisionqueryservice_p.h +++ b/src/render/raycasting/qabstractcollisionqueryservice_p.h @@ -105,6 +105,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QAbstractCollisionQueryService::QueryMode) +Q_DECLARE_METATYPE(Qt3DRender::QAbstractCollisionQueryService::QueryMode) // LCOV_EXCL_LINE #endif // QT3DRENDER_QABSTRACTCOLLISIONQUERYSERVICE_P_H diff --git a/src/render/raycasting/qboundingvolume_p.h b/src/render/raycasting/qboundingvolume_p.h index 87f7e45f5..a69530246 100644 --- a/src/render/raycasting/qboundingvolume_p.h +++ b/src/render/raycasting/qboundingvolume_p.h @@ -79,6 +79,6 @@ public: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QBoundingVolume*) +Q_DECLARE_METATYPE(Qt3DRender::QBoundingVolume*) // LCOV_EXCL_LINE #endif // QT3DRENDER_QBOUNDINGVOLUME_P_H diff --git a/src/render/raycasting/qray3d_p.h b/src/render/raycasting/qray3d_p.h index 3e454e7c8..d1fce726d 100644 --- a/src/render/raycasting/qray3d_p.h +++ b/src/render/raycasting/qray3d_p.h @@ -118,6 +118,6 @@ inline bool qFuzzyCompare(const Qt3DRender::QRay3D &ray1, const Qt3DRender::QRay qFuzzyCompare(ray1.direction(), ray2.direction()); } -Q_DECLARE_METATYPE(Qt3DRender::QRay3D) +Q_DECLARE_METATYPE(Qt3DRender::QRay3D) // LCOV_EXCL_LINE #endif // QT3DRENDER_QRAY3D_H diff --git a/src/render/render.pro b/src/render/render.pro index b3c5fa1ad..bcfcadd97 100644 --- a/src/render/render.pro +++ b/src/render/render.pro @@ -24,7 +24,6 @@ include (texture/texture.pri) DEFINES += QT_NO_FOREACH gcov { - CONFIG += static QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage } @@ -34,8 +33,6 @@ HEADERS += \ qt3drender_global.h \ qt3drender_global_p.h -!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL - # otherwise mingw headers do not declare common functions like ::strcasecmp win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x diff --git a/src/render/renderstates/qalphatest.h b/src/render/renderstates/qalphatest.h index 49a5fac43..67106ade5 100644 --- a/src/render/renderstates/qalphatest.h +++ b/src/render/renderstates/qalphatest.h @@ -66,7 +66,7 @@ public: Greater = 0x0204, NotEqual = 0x0205 }; - Q_ENUM(AlphaFunction) + Q_ENUM(AlphaFunction) // LCOV_EXCL_LINE explicit QAlphaTest(Qt3DCore::QNode *parent = nullptr); ~QAlphaTest(); diff --git a/src/render/renderstates/qblendequation.h b/src/render/renderstates/qblendequation.h index 6810cf96e..8bdfe4907 100644 --- a/src/render/renderstates/qblendequation.h +++ b/src/render/renderstates/qblendequation.h @@ -63,7 +63,7 @@ public: Min = 0x8007, Max = 0x8008 }; - Q_ENUM(BlendFunction) + Q_ENUM(BlendFunction) // LCOV_EXCL_LINE explicit QBlendEquation(Qt3DCore::QNode *parent = nullptr); ~QBlendEquation(); diff --git a/src/render/renderstates/qblendequationarguments.cpp b/src/render/renderstates/qblendequationarguments.cpp index 58c048138..7ea020083 100644 --- a/src/render/renderstates/qblendequationarguments.cpp +++ b/src/render/renderstates/qblendequationarguments.cpp @@ -121,7 +121,8 @@ QBlendEquationArguments::QBlendEquationArguments(QBlendEquationArgumentsPrivate \value OneMinusConstantColor GL_ONE_MINUS_CONSTANT_COLOR \value OneMinusConstantAlpha GL_ONE_MINUS_CONSTANT_ALPHA \value OneMinusSource1Alpha GL_ONE_MINUS_SRC1_ALPHA - \value OneMinusSource1Color0 GL_ONE_MINUS_SRC1_COLOR + \value OneMinusSource1Color GL_ONE_MINUS_SRC1_COLOR + \value OneMinusSource1Color0 GL_ONE_MINUS_SRC1_COLOR (deprecated) */ /*! diff --git a/src/render/renderstates/qblendequationarguments.h b/src/render/renderstates/qblendequationarguments.h index 2f844b8cf..5f613770a 100644 --- a/src/render/renderstates/qblendequationarguments.h +++ b/src/render/renderstates/qblendequationarguments.h @@ -80,9 +80,10 @@ public: OneMinusConstantColor = 0x8002, OneMinusConstantAlpha = 0x8004, OneMinusSource1Alpha, - OneMinusSource1Color0 + OneMinusSource1Color, + OneMinusSource1Color0 = OneMinusSource1Color // ### Qt 6: Remove }; - Q_ENUM(Blending) + Q_ENUM(Blending) // LCOV_EXCL_LINE explicit QBlendEquationArguments(Qt3DCore::QNode *parent = nullptr); ~QBlendEquationArguments(); diff --git a/src/render/renderstates/qcullface.h b/src/render/renderstates/qcullface.h index 3474fe009..8598d3b88 100644 --- a/src/render/renderstates/qcullface.h +++ b/src/render/renderstates/qcullface.h @@ -64,7 +64,7 @@ public: Back = 0x0405, FrontAndBack = 0x0408 }; - Q_ENUM(CullingMode) + Q_ENUM(CullingMode) // LCOV_EXCL_LINE explicit QCullFace(Qt3DCore::QNode *parent = nullptr); ~QCullFace(); diff --git a/src/render/renderstates/qdepthtest.h b/src/render/renderstates/qdepthtest.h index 16b4a5b85..9482ef9a5 100644 --- a/src/render/renderstates/qdepthtest.h +++ b/src/render/renderstates/qdepthtest.h @@ -65,7 +65,7 @@ public: Greater = 0x0204, NotEqual = 0x0205 }; - Q_ENUM(DepthFunction) + Q_ENUM(DepthFunction) // LCOV_EXCL_LINE explicit QDepthTest(Qt3DCore::QNode *parent = nullptr); ~QDepthTest(); diff --git a/src/render/renderstates/qfrontface.h b/src/render/renderstates/qfrontface.h index dd8a7f5fe..0f1061280 100644 --- a/src/render/renderstates/qfrontface.h +++ b/src/render/renderstates/qfrontface.h @@ -60,7 +60,7 @@ public: ClockWise = 0x0900, CounterClockWise = 0x0901 }; - Q_ENUM(WindingDirection) + Q_ENUM(WindingDirection) // LCOV_EXCL_LINE explicit QFrontFace(Qt3DCore::QNode *parent = nullptr); ~QFrontFace(); diff --git a/src/render/renderstates/qpointsize.h b/src/render/renderstates/qpointsize.h index fdfa54a9c..621d983b8 100644 --- a/src/render/renderstates/qpointsize.h +++ b/src/render/renderstates/qpointsize.h @@ -58,7 +58,7 @@ public: Fixed = 0, Programmable = 1 }; - Q_ENUM(SizeMode) + Q_ENUM(SizeMode) // LCOV_EXCL_LINE explicit QPointSize(Qt3DCore::QNode *parent = nullptr); ~QPointSize(); diff --git a/src/render/renderstates/qrenderstatecreatedchange.cpp b/src/render/renderstates/qrenderstatecreatedchange.cpp index 4842ae303..a3466ca66 100644 --- a/src/render/renderstates/qrenderstatecreatedchange.cpp +++ b/src/render/renderstates/qrenderstatecreatedchange.cpp @@ -45,6 +45,7 @@ namespace Qt3DRender { * \class Qt3DRender::QRenderStateCreatedChange * \brief The QRenderStateCreatedChange class * \since 5.7 + * \inmodule Qt3DRender * \ingroup renderstates */ diff --git a/src/render/renderstates/qstenciloperationarguments.h b/src/render/renderstates/qstenciloperationarguments.h index 31d32f4d5..db80ecc19 100644 --- a/src/render/renderstates/qstenciloperationarguments.h +++ b/src/render/renderstates/qstenciloperationarguments.h @@ -65,7 +65,7 @@ public: Back = 0x0405, FrontAndBack = 0x0408 }; - Q_ENUM(FaceMode) + Q_ENUM(FaceMode) // LCOV_EXCL_LINE enum Operation { @@ -78,7 +78,7 @@ public: DecrementWrap = 0x8508, Invert = 0x150A }; - Q_ENUM(Operation) + Q_ENUM(Operation) // LCOV_EXCL_LINE ~QStencilOperationArguments(); diff --git a/src/render/renderstates/qstenciltestarguments.h b/src/render/renderstates/qstenciltestarguments.h index 17d9fa21e..f20885d03 100644 --- a/src/render/renderstates/qstenciltestarguments.h +++ b/src/render/renderstates/qstenciltestarguments.h @@ -65,7 +65,7 @@ public: Back = 0x0405, FrontAndBack = 0x0408 }; - Q_ENUM(StencilFaceMode) + Q_ENUM(StencilFaceMode) // LCOV_EXCL_LINE enum StencilFunction { @@ -78,7 +78,7 @@ public: Greater = 0x0204, NotEqual = 0x0205 }; - Q_ENUM(StencilFunction) + Q_ENUM(StencilFunction) // LCOV_EXCL_LINE ~QStencilTestArguments(); diff --git a/src/render/texture/apitexturemanager_p.h b/src/render/texture/apitexturemanager_p.h new file mode 100644 index 000000000..1be5a1af8 --- /dev/null +++ b/src/render/texture/apitexturemanager_p.h @@ -0,0 +1,376 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_APITEXTUREMANAGER_P_H +#define QT3DRENDER_RENDER_APITEXTUREMANAGER_P_H + +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/texturedatamanager_p.h> +#include <Qt3DRender/private/textureimage_p.h> +#include <Qt3DRender/private/texture_p.h> +#include <Qt3DRender/qtexturegenerator.h> +#include <Qt3DRender/qtextureimagedatagenerator.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +// Manages instances of APITexture. This includes sharing between multiple +// Texture nodes, updating APITextures and deleting abandoned instances. +template <class APITexture, class APITextureImage> +class APITextureManager +{ +public: + + explicit APITextureManager(TextureImageManager *textureImageManager, + TextureDataManager *textureDataManager, + TextureImageDataManager *textureImageDataManager) + : m_textureImageManager(textureImageManager) + , m_textureDataManager(textureDataManager) + , m_textureImageDataManager(textureImageDataManager) + { + } + + ~APITextureManager() + { + qDeleteAll(activeResources()); + m_nodeIdToGLTexture.clear(); + m_sharedTextures.clear(); + m_updatedTextures.clear(); + } + + // Used to retrieve all resources that needs to be destroyed on the GPU + QVector<APITexture *> activeResources() const + { + // Active Resources are + // all shared textures + // all unique textures + // all textures that haven't yet been destroyed + // Note: updatedTextures only referenced textures in one of these 3 vectors + return m_sharedTextures.keys().toVector() + m_uniqueTextures + m_abandonedTextures; + } + + APITexture *lookupResource(Qt3DCore::QNodeId textureId) + { + return m_nodeIdToGLTexture.value(textureId); + } + + // Returns a APITexture that matches the given QTexture node. Will make sure + // that texture data generator jobs are launched, if necessary. The APITexture + // may be shared between multiple texture backend nodes + APITexture *getOrCreateShared(const Texture *node) + { + Q_ASSERT(node); + + APITexture *shared = findMatchingShared(node); + + // no matching shared texture was found; create a new one: + if (shared == nullptr) + shared = createTexture(node, false); + + // store texture node to shared texture relationship + adoptShared(shared, node); + + return shared; + } + + // Store that the shared texture references node + void adoptShared(APITexture *sharedApiTexture, const Texture *node) + { + if (!m_sharedTextures[sharedApiTexture].contains(node->peerId())) { + m_sharedTextures[sharedApiTexture].push_back(node->peerId()); + m_nodeIdToGLTexture.insert(node->peerId(), sharedApiTexture); + } + } + + // If there is already a shared texture with the properties of the given + // texture node, return this instance, else NULL. + // Note: the reference to the texture node is added if the shared texture + // wasn't referencing it already + APITexture *findMatchingShared(const Texture *node) + { + Q_ASSERT(node); + + // search for existing texture + const auto end = m_sharedTextures.end(); + for (auto it = m_sharedTextures.begin(); it != end; ++it) + if (isSameTexture(it.key(), node)) + return it.key(); + return nullptr; + } + + // Returns a APITexture that matches the given QTexture node. Will make sure + // that texture data generator jobs are launched, if necessary. + APITexture *createUnique(const Texture *node) + { + Q_ASSERT(node); + APITexture *uniqueTex = createTexture(node, true); + m_uniqueTextures.push_back(uniqueTex); + m_nodeIdToGLTexture.insert(node->peerId(), uniqueTex); + return uniqueTex; + } + + // De-associate the given APITexture from the backend node. If the texture + // is no longer referenced by any other node, it will be deleted. + void abandon(APITexture *tex, const Texture *node) + { + APITexture *apiTexture = m_nodeIdToGLTexture.take(node->peerId()); + Q_ASSERT(tex == apiTexture); + + if (Q_UNLIKELY(!apiTexture)) { + qWarning() << "[Qt3DRender::TextureManager] abandon: could not find Texture"; + return; + } + + if (tex->isUnique()) { + m_uniqueTextures.removeAll(apiTexture); + m_abandonedTextures.push_back(apiTexture); + } else { + QVector<Qt3DCore::QNodeId> &referencedTextureNodes = m_sharedTextures[apiTexture]; + referencedTextureNodes.removeAll(node->peerId()); + + // If no texture nodes is referencing the shared APITexture, remove it + if (referencedTextureNodes.empty()) { + m_abandonedTextures.push_back(apiTexture); + m_sharedTextures.remove(apiTexture); + } + } + } + + // Change the properties of the given texture, if it is a non-shared texture + // Returns true, if it was changed successfully, false otherwise + bool setProperties(APITexture *tex, const TextureProperties &props) + { + Q_ASSERT(tex); + + if (isShared(tex)) + return false; + + tex->setProperties(props); + m_updatedTextures.push_back(tex); + + return true; + } + + // Change the parameters of the given texture, if it is a non-shared texture + // Returns true, if it was changed successfully, false otherwise + bool setParameters(APITexture *tex, const TextureParameters ¶ms) + { + Q_ASSERT(tex); + + if (isShared(tex)) + return false; + + tex->setParameters(params); + m_updatedTextures.push_back(tex); + + return true; + } + + // Change the texture images of the given texture, if it is a non-shared texture + // Return true, if it was changed successfully, false otherwise + bool setImages(APITexture *tex, const QVector<HTextureImage> &images) + { + Q_ASSERT(tex); + + if (isShared(tex)) + return false; + + // create Image structs + QVector<APITextureImage> texImgs = texImgsFromNodes(images); + if (texImgs.size() != images.size()) + return false; + + tex->setImages(texImgs); + m_updatedTextures.push_back(tex); + + return true; + } + + // Retrieves abandoned textures. This should be regularly called from the OpenGL thread + // to make sure needed GL resources are de-allocated. + QVector<APITexture*> takeAbandonedTextures() + { + return std::move(m_abandonedTextures); + } + + // Retrieves textures that have been modified + QVector<APITexture*> takeUpdatedTextures() + { + return std::move(m_updatedTextures); + } + + // Returns whether the given APITexture is shared between multiple TextureNodes + bool isShared(APITexture *impl) + { + Q_ASSERT(impl); + + if (impl->isUnique()) + return false; + + auto it = m_sharedTextures.find(impl); + if (it == m_sharedTextures.cend()) + return false; + + return it.value().size() > 1; + } + +private: + + // Check if the given APITexture matches the TextureNode + bool isSameTexture(const APITexture *tex, const Texture *texNode) + { + // make sure there either are no texture generators, or the two are the same + if (tex->textureGenerator().isNull() != texNode->dataGenerator().isNull()) + return false; + if (!tex->textureGenerator().isNull() && !(*tex->textureGenerator() == *texNode->dataGenerator())) + return false; + + // make sure the image generators are the same + const QVector<APITextureImage> texImgGens = tex->images(); + const QVector<HTextureImage> texImgs = texNode->textureImages(); + if (texImgGens.size() != texImgs.size()) + return false; + for (int i = 0; i < texImgGens.size(); ++i) { + const TextureImage *img = m_textureImageManager->data(texImgs[i]); + Q_ASSERT(img != nullptr); + if (!(*img->dataGenerator() == *texImgGens[i].generator) + || img->layer() != texImgGens[i].layer + || img->face() != texImgGens[i].face + || img->mipLevel() != texImgGens[i].mipLevel) + return false; + } + + // if the texture has a texture generator, this generator will mostly determine + // the properties of the texture. + if (!tex->textureGenerator().isNull()) + return (tex->properties().generateMipMaps == texNode->properties().generateMipMaps + && tex->parameters() == texNode->parameters()); + + // if it doesn't have a texture generator, but texture image generators, + // few more properties will influence the texture type + if (!texImgGens.empty()) + return (tex->properties().target == texNode->properties().target + && tex->properties().format == texNode->properties().format + && tex->properties().generateMipMaps == texNode->properties().generateMipMaps + && tex->parameters() == texNode->parameters()); + + // texture without images + return tex->properties() == texNode->properties() + && tex->parameters() == texNode->parameters(); + } + + // Create APITexture from given TextureNode. Also make sure the generators + // will be executed by jobs soon. + APITexture *createTexture(const Texture *node, bool unique) + { + // create Image structs + const QVector<APITextureImage> texImgs = texImgsFromNodes(node->textureImages()); + if (texImgs.empty() && !node->textureImages().empty()) + return nullptr; + + // no matching shared texture was found, create a new one + APITexture *newTex = new APITexture(m_textureDataManager, m_textureImageDataManager, node->dataGenerator(), unique); + newTex->setProperties(node->properties()); + newTex->setParameters(node->parameters()); + newTex->setImages(texImgs); + + m_updatedTextures.push_back(newTex); + + return newTex; + } + + QVector<APITextureImage> texImgsFromNodes(const QVector<HTextureImage> &images) const + { + QVector<APITextureImage> ret; + ret.resize(images.size()); + + for (int i = 0; i < images.size(); ++i) { + const TextureImage *img = m_textureImageManager->data(images[i]); + if (!img) { + qWarning() << "[Qt3DRender::TextureManager] invalid TextureImage handle"; + return QVector<APITextureImage>(); + } + + ret[i].generator = img->dataGenerator(); + ret[i].face = img->face(); + ret[i].layer = img->layer(); + ret[i].mipLevel = img->mipLevel(); + } + + return ret; + } + + TextureImageManager *m_textureImageManager; + TextureDataManager *m_textureDataManager; + TextureImageDataManager *m_textureImageDataManager; + + /* each non-unique texture is associated with a number of Texture nodes referencing it */ + QHash<APITexture*, QVector<Qt3DCore::QNodeId>> m_sharedTextures; + + // Texture id -> APITexture (both shared and unique ones) + QHash<Qt3DCore::QNodeId, APITexture *> m_nodeIdToGLTexture; + + QVector<APITexture*> m_uniqueTextures; + QVector<APITexture*> m_abandonedTextures; + QVector<APITexture*> m_updatedTextures; +}; + + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE + + +#endif // QT3DRENDER_RENDER_APITEXTUREMANAGER_P_H diff --git a/src/render/texture/gltexture.cpp b/src/render/texture/gltexture.cpp new file mode 100644 index 000000000..7916e390d --- /dev/null +++ b/src/render/texture/gltexture.cpp @@ -0,0 +1,413 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qhash.h> +#include "gltexture_p.h" + +#include <QDebug> +#include <QOpenGLFunctions> +#include <QOpenGLTexture> +#include <QOpenGLPixelTransferOptions> +#include <Qt3DRender/qtexture.h> +#include <Qt3DRender/qtexturedata.h> +#include <Qt3DRender/qtextureimagedata.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/texturedatamanager_p.h> +#include <Qt3DRender/private/qabstracttexture_p.h> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include <Qt3DCore/qpropertynodeaddedchange.h> +#include <Qt3DCore/qpropertynoderemovedchange.h> + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DRender { +namespace Render { + +GLTexture::GLTexture(TextureDataManager *texDataMgr, + TextureImageDataManager *texImgDataMgr, + const QTextureGeneratorPtr &texGen, + bool unique) + : m_unique(unique) + , m_gl(nullptr) + , m_textureDataManager(texDataMgr) + , m_textureImageDataManager(texImgDataMgr) + , m_dataFunctor(texGen) +{ + // make sure texture generator is executed + if (!texGen.isNull()) + m_textureDataManager->requestData(texGen, this); +} + +GLTexture::~GLTexture() +{ + if (m_gl) { + qWarning() << "[Qt3DRender::GLTexture] Destructor called without properly deleting texture"; + delete m_gl; + } + + // release texture data + for (const Image &img : qAsConst(m_images)) + m_textureImageDataManager->releaseData(img.generator, this); + + if (m_dataFunctor) + m_textureDataManager->releaseData(m_dataFunctor, this); +} + +void GLTexture::destroyGLTexture() +{ + delete m_gl; + m_gl = nullptr; + m_dirty = 0; +} + +QOpenGLTexture* GLTexture::getOrCreateGLTexture() +{ + bool needUpload = false; + bool texturedDataInvalid = false; + + // on the first invocation in the render thread, make sure to + // evaluate the texture data generator output + // (this might change some property values) + if (m_dataFunctor && !m_textureData) { + m_textureData = m_textureDataManager->getData(m_dataFunctor); + + // if there is a texture generator, most properties will be defined by it + if (m_textureData) { + if (m_properties.target != QAbstractTexture::TargetAutomatic) + qWarning() << "[Qt3DRender::GLTexture] When a texture provides a generator, it's target is expected to be TargetAutomatic"; + + m_properties.target = m_textureData->target(); + m_properties.width = m_textureData->width(); + m_properties.height = m_textureData->height(); + m_properties.depth = m_textureData->depth(); + m_properties.layers = m_textureData->layers(); + m_properties.format = m_textureData->format(); + + const QVector<QTextureImageDataPtr> imageData = m_textureData->imageData(); + + if (imageData.size() > 0) { + // Set the mips level based on the first image if autoMipMapGeneration is disabled + if (!m_properties.generateMipMaps) + m_properties.mipLevels = imageData.first()->mipLevels(); + } + + m_dirty |= Properties; + needUpload = true; + } else { + qWarning() << "[Qt3DRender::GLTexture] No QTextureData generated from Texture Generator"; + texturedDataInvalid = true; + } + } + + // additional texture images may be defined through image data generators + if (m_dirty.testFlag(TextureData)) { + m_imageData.clear(); + needUpload = true; + + for (const Image &img : qAsConst(m_images)) { + const QTextureImageDataPtr imgData = m_textureImageDataManager->getData(img.generator); + + if (imgData) { + m_imageData << imgData; + + // If the texture doesn't have a texture generator, we will + // derive some properties from the first TextureImage (layer=0, miplvl=0, face=0) + if (!m_textureData && img.layer == 0 && img.mipLevel == 0 && img.face == QAbstractTexture::CubeMapPositiveX) { + if (imgData->width() != -1 && imgData->height() != -1 && imgData->depth() != -1) { + m_properties.width = imgData->width(); + m_properties.height = imgData->height(); + m_properties.depth = imgData->depth(); + } + + // Set the format of the texture if the texture format is set to Automatic + if (m_properties.format == QAbstractTexture::Automatic) { + m_properties.format = static_cast<QAbstractTexture::TextureFormat>(imgData->format()); + } + + m_dirty |= Properties; + } + } else { + qWarning() << "[Qt3DRender::GLTexture] No QTextureImageData generated from functor"; + texturedDataInvalid = true; + } + } + } + + + // if the properties changed, we need to re-allocate the texture + if (m_dirty.testFlag(Properties)) { + delete m_gl; + m_gl = nullptr; + } + + if (!m_gl) { + m_gl = buildGLTexture(); + m_gl->allocateStorage(); + if (!m_gl->isStorageAllocated()) { + qWarning() << Q_FUNC_INFO << "texture storage allocation failed"; + return nullptr; + } + } + + // need to (re-)upload texture data? + if (needUpload && !texturedDataInvalid) { + uploadGLTextureData(); + } + + // need to set texture parameters? + if (m_dirty.testFlag(Properties) || m_dirty.testFlag(Parameters)) { + updateGLTextureParameters(); + } + + m_dirty = 0; + + return m_gl; +} + +void GLTexture::setParameters(const TextureParameters ¶ms) +{ + if (m_parameters != params) { + m_parameters = params; + m_dirty |= Parameters; + } +} + +void GLTexture::setProperties(const TextureProperties &props) +{ + if (m_properties != props) { + m_properties = props; + m_dirty |= Properties; + } +} + +void GLTexture::setImages(const QVector<Image> &images) +{ + // check if something has changed at all + bool same = (images.size() == m_images.size()); + if (same) { + for (int i = 0; i < images.size(); i++) { + if (images[i] != m_images[i]) + same = false; + } + } + + // de-reference all old texture image generators that will no longer be used. + // we need to check all generators against each other to make sure we don't + // de-ref a texture that would still be in use, thus maybe causing it to + // be deleted + if (!same) { + for (const Image &oldImg : qAsConst(m_images)) { + bool stillHaveThatImage = false; + + for (const Image &newImg : images) { + if (oldImg.generator == newImg.generator) { + stillHaveThatImage = true; + break; + } + } + + if (!stillHaveThatImage) + m_textureImageDataManager->releaseData(oldImg.generator, this); + } + + m_images = images; + m_dirty |= TextureData; + + // make sure the generators are executed + for (const Image& img : qAsConst(images)) { + m_textureImageDataManager->requestData(img.generator, this); + } + } +} + +QOpenGLTexture *GLTexture::buildGLTexture() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx) { + qWarning() << Q_FUNC_INFO << "requires an OpenGL context"; + return nullptr; + } + + if (m_properties.target == QAbstractTexture::TargetAutomatic) { + qWarning() << Q_FUNC_INFO << "something went wrong, target shouldn't be automatic at this point"; + return nullptr; + } + + QOpenGLTexture* glTex = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(m_properties.target)); + + // m_format may not be ES2 compatible. Now it's time to convert it, if necessary. + QAbstractTexture::TextureFormat format = m_properties.format; + if (ctx->isOpenGLES() && ctx->format().majorVersion() < 3) { + switch (m_properties.format) { + case QOpenGLTexture::RGBA8_UNorm: + case QOpenGLTexture::RGBAFormat: + format = QAbstractTexture::RGBAFormat; + break; + case QOpenGLTexture::RGB8_UNorm: + case QOpenGLTexture::RGBFormat: + format = QAbstractTexture::RGBFormat; + break; + case QOpenGLTexture::DepthFormat: + format = QAbstractTexture::DepthFormat; + break; + default: + qWarning() << Q_FUNC_INFO << "could not find a matching OpenGL ES 2.0 unsized texture format"; + break; + } + } + + // Map ETC1 to ETC2 when supported. This allows using features like + // immutable storage as ETC2 is standard in GLES 3.0, while the ETC1 extension + // is written against GLES 1.0. + if (m_properties.format == QAbstractTexture::RGB8_ETC1) { + if ((ctx->isOpenGLES() && ctx->format().majorVersion() >= 3) + || ctx->hasExtension(QByteArrayLiteral("GL_OES_compressed_ETC2_RGB8_texture")) + || ctx->hasExtension(QByteArrayLiteral("GL_ARB_ES3_compatibility"))) + format = m_properties.format = QAbstractTexture::RGB8_ETC2; + } + + glTex->setFormat(m_properties.format == QAbstractTexture::Automatic ? + QOpenGLTexture::NoFormat : + static_cast<QOpenGLTexture::TextureFormat>(format)); + glTex->setSize(m_properties.width, m_properties.height, m_properties.depth); + // Set layers count if texture array + if (m_properties.target == QAbstractTexture::Target1DArray || + m_properties.target == QAbstractTexture::Target2DArray || + m_properties.target == QAbstractTexture::Target3D || + m_properties.target == QAbstractTexture::Target2DMultisampleArray || + m_properties.target == QAbstractTexture::TargetCubeMapArray) { + glTex->setLayers(m_properties.layers); + } + + if (m_properties.target == QAbstractTexture::Target2DMultisample || + m_properties.target == QAbstractTexture::Target2DMultisampleArray) { + // Set samples count if multisampled texture + // (multisampled textures don't have mipmaps) + glTex->setSamples(m_properties.samples); + } else if (m_properties.generateMipMaps) { + glTex->setMipLevels(glTex->maximumMipLevels()); + } else { + glTex->setAutoMipMapGenerationEnabled(false); + glTex->setMipBaseLevel(0); + glTex->setMipMaxLevel(m_properties.mipLevels - 1); + glTex->setMipLevels(m_properties.mipLevels); + } + + if (!glTex->create()) { + qWarning() << Q_FUNC_INFO << "creating QOpenGLTexture failed"; + return nullptr; + } + + return glTex; +} + +static void uploadGLData(QOpenGLTexture *glTex, + int level, int layer, QOpenGLTexture::CubeMapFace face, + const QByteArray &bytes, const QTextureImageDataPtr &data) +{ + if (data->isCompressed()) { + glTex->setCompressedData(level, layer, face, bytes.size(), bytes.constData()); + } else { + QOpenGLPixelTransferOptions uploadOptions; + uploadOptions.setAlignment(1); + glTex->setData(level, layer, face, data->pixelFormat(), data->pixelType(), bytes.constData(), &uploadOptions); + } +} + +void GLTexture::uploadGLTextureData() +{ + // Upload all QTexImageData set by the QTextureGenerator + if (m_textureData) { + const QVector<QTextureImageDataPtr> imgData = m_textureData->imageData(); + + for (const QTextureImageDataPtr &data : imgData) { + const int mipLevels = m_properties.generateMipMaps ? 1 : data->mipLevels(); + + for (int layer = 0; layer < data->layers(); layer++) { + for (int face = 0; face < data->faces(); face++) { + for (int level = 0; level < mipLevels; level++) { + // ensure we don't accidently cause a detach / copy of the raw bytes + const QByteArray bytes(data->data(layer, face, level)); + uploadGLData(m_gl, level, layer, + static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face), + bytes, data); + } + } + } + } + } + + // Upload all QTexImageData references by the TextureImages + for (int i = 0; i < m_images.size(); i++) { + const QTextureImageDataPtr &imgData = m_imageData.at(i); + + // ensure we don't accidently cause a detach / copy of the raw bytes + const QByteArray bytes(imgData->data()); + uploadGLData(m_gl, m_images[i].mipLevel, m_images[i].layer, + static_cast<QOpenGLTexture::CubeMapFace>(m_images[i].face), + bytes, imgData); + } +} + +void GLTexture::updateGLTextureParameters() +{ + m_gl->setWrapMode(QOpenGLTexture::DirectionS, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeX)); + if (m_properties.target != QAbstractTexture::Target1D && + m_properties.target != QAbstractTexture::Target1DArray && + m_properties.target != QAbstractTexture::TargetBuffer) + m_gl->setWrapMode(QOpenGLTexture::DirectionT, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeY)); + if (m_properties.target == QAbstractTexture::Target3D) + m_gl->setWrapMode(QOpenGLTexture::DirectionR, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeZ)); + m_gl->setMinMagFilters(static_cast<QOpenGLTexture::Filter>(m_parameters.minificationFilter), + static_cast<QOpenGLTexture::Filter>(m_parameters.magnificationFilter)); + if (m_gl->hasFeature(QOpenGLTexture::AnisotropicFiltering)) + m_gl->setMaximumAnisotropy(m_parameters.maximumAnisotropy); + if (m_gl->hasFeature(QOpenGLTexture::TextureComparisonOperators)) { + m_gl->setComparisonFunction(static_cast<QOpenGLTexture::ComparisonFunction>(m_parameters.comparisonFunction)); + m_gl->setComparisonMode(static_cast<QOpenGLTexture::ComparisonMode>(m_parameters.comparisonMode)); + } +} + + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/texture/gltexture_p.h b/src/render/texture/gltexture_p.h new file mode 100644 index 000000000..f911262be --- /dev/null +++ b/src/render/texture/gltexture_p.h @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_GLTEXTURE_H +#define QT3DRENDER_RENDER_GLTEXTURE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DRender/qtexture.h> +#include <Qt3DRender/qtextureimagedata.h> +#include <Qt3DRender/qtexturegenerator.h> +#include <Qt3DRender/private/backendnode_p.h> +#include <Qt3DRender/private/handle_types_p.h> +#include <Qt3DRender/private/texture_p.h> +#include <QOpenGLContext> +#include <QFlags> +#include <QMutex> +#include <QSize> + +QT_BEGIN_NAMESPACE + +class QOpenGLTexture; + +namespace Qt3DRender { +namespace Render { + +class TextureImageManager; +class TextureDataManager; +class TextureImageDataManager; + +/** + * @brief + * Actual implementation of the OpenGL texture object. Makes sure the + * QOpenGLTexture is up-to-date with the generators, properties and parameters + * that were set for this GLTexture. + * + * Can be shared among multiple QTexture backend nodes through the + * GLTextureManager, which will make sure that there are no two GLTextures + * sharing the same texture data. + * + * A GLTexture can be unique though. In that case, it will not be shared + * between QTextures, but private to one QTexture only. + */ +class Q_AUTOTEST_EXPORT GLTexture +{ +public: + GLTexture(TextureDataManager *texDataMgr, + TextureImageDataManager *texImgDataMgr, + const QTextureGeneratorPtr &texGen, + bool unique); + + ~GLTexture(); + + /** + * Helper class to hold the defining properties of TextureImages + */ + struct Image { + QTextureImageDataGeneratorPtr generator; + int layer; + int mipLevel; + QAbstractTexture::CubeMapFace face; + + inline bool operator==(const Image &o) const { + bool sameGenerators = (generator == o.generator) + || (!generator.isNull() && !o.generator.isNull() && *generator == *o.generator); + return sameGenerators && layer == o.layer && mipLevel == o.mipLevel && face == o.face; + } + inline bool operator!=(const Image &o) const { return !(*this == o); } + }; + + inline bool isUnique() const { return m_unique; } + + inline TextureProperties properties() const { return m_properties; } + inline TextureParameters parameters() const { return m_parameters; } + inline QTextureGeneratorPtr textureGenerator() const { return m_dataFunctor; } + inline QVector<Image> images() const { return m_images; } + + inline QSize size() const { return QSize(m_properties.width, m_properties.height); } + inline QOpenGLTexture *getGLTexture() const { return m_gl; } + + /** + * @brief + * Returns the QOpenGLTexture for this GLTexture. If necessary, + * the GL texture will be created from the TextureImageDatas associated + * with the texture and image functors. If no functors are provided, + * the texture will be created without images. + * + * If the texture properties or parameters have changed, these changes + * will be applied to the resulting OpenGL texture. + */ + QOpenGLTexture* getOrCreateGLTexture(); + + /** + * @brief Make sure to call this before calling the dtor + */ + void destroyGLTexture(); + +protected: + + template<class APITexture, class APITextureImage> + friend class APITextureManager; + + /* + * These methods are to be accessed from the GLTextureManager. + * The renderer and the texture backend nodes can only modify Textures + * through the GLTextureManager. + * + * The methods should only be called for unique textures, or textures + * that are not shared between multiple nodes. + */ + void setParameters(const TextureParameters ¶ms); + void setProperties(const TextureProperties &props); + void setImages(const QVector<Image> &images); + +private: + + enum DirtyFlag { + TextureData = 0x1, // one or more generators need to be executed + Properties = 0x2, // texture needs to be (re-)created + Parameters = 0x4 // texture parameters need to be (re-)set + }; + Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag) + + QOpenGLTexture *buildGLTexture(); + void uploadGLTextureData(); + void updateGLTextureParameters(); + + bool m_unique; + DirtyFlags m_dirty; + QOpenGLTexture *m_gl; + + TextureDataManager *m_textureDataManager; + TextureImageDataManager *m_textureImageDataManager; + + TextureProperties m_properties; + TextureParameters m_parameters; + + QTextureGeneratorPtr m_dataFunctor; + QVector<Image> m_images; + + // cache actual image data generated by the functors + QTextureDataPtr m_textureData; + QVector<QTextureImageDataPtr> m_imageData; +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_GLTEXTURE_H diff --git a/src/render/texture/gltexturemanager_p.h b/src/render/texture/gltexturemanager_p.h new file mode 100644 index 000000000..1c8b49911 --- /dev/null +++ b/src/render/texture/gltexturemanager_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_GLTEXTUREMANAGER_H +#define QT3DRENDER_RENDER_GLTEXTUREMANAGER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DRender/private/apitexturemanager_p.h> +#include <Qt3DRender/private/gltexture_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +class Q_AUTOTEST_EXPORT GLTextureManager : public APITextureManager<GLTexture, GLTexture::Image> +{ +public: + explicit GLTextureManager(TextureImageManager *textureImageManager, + TextureDataManager *textureDataManager, + TextureImageDataManager *textureImageDataManager) + : APITextureManager<GLTexture, GLTexture::Image>(textureImageManager, + textureDataManager, + textureImageDataManager) + {} +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_GLTEXTUREMANAGER_H diff --git a/src/render/texture/qabstracttexture.cpp b/src/render/texture/qabstracttexture.cpp index d7bb33f44..7703933a4 100644 --- a/src/render/texture/qabstracttexture.cpp +++ b/src/render/texture/qabstracttexture.cpp @@ -65,9 +65,21 @@ QAbstractTexturePrivate::QAbstractTexturePrivate() , m_comparisonFunction(QAbstractTexture::CompareLessEqual) , m_comparisonMode(QAbstractTexture::CompareNone) , m_layers(1) + , m_samples(1) { } +void QAbstractTexturePrivate::setDataFunctor(const QTextureGeneratorPtr &generator) +{ + if (generator != m_dataFunctor) { + m_dataFunctor = generator; + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(m_id); + change->setPropertyName("generator"); + change->setValue(QVariant::fromValue(generator)); + notifyObservers(change); + } +} + /*! \class Qt3DRender::QAbstractTexture \inmodule Qt3DRender @@ -83,6 +95,26 @@ QAbstractTexturePrivate::QAbstractTexturePrivate() */ /*! + \enum Qt3DRender::QAbstractTexture::CubeMapFace + + This enum identifies the faces of a cube map texture + \value CubeMapPositiveX Specify the positive X face of a cube map + \value CubeMapNegativeX Specify the negative X face of a cube map + \value CubeMapPositiveY Specify the positive Y face of a cube map + \value CubeMapNegativeY Specify the negative Y face of a cube map + \value CubeMapPositiveZ Specify the positive Z face of a cube map + \value CubeMapNegativeZ Specify the negative Z face of a cube map + \value AllFaces Specify all the faces of a cube map + + \note AllFaces should only be used when a behavior needs to be applied to + all the faces of a cubemap. This is the case for example when using a cube + map as a texture attachment. Using AllFaces in the attachment specfication + would result in all faces being bound to the attachment point. On the other + hand, if a specific face is specified, the attachment would only be using + the specified face. +*/ + +/*! * The constructor creates a new QAbstractTexture::QAbstractTexture * instance with the specified \a parent. */ @@ -222,6 +254,36 @@ int QAbstractTexture::layers() const } /*! + \property Qt3DRender::QAbstractTexture::samples + + Holds the number of samples per texel for the texture provider. + By default, the number of samples is 1. + + \note this has a meaning only for texture providers that have multisample + formats. + */ +void QAbstractTexture::setSamples(int samples) +{ + Q_D(QAbstractTexture); + if (d->m_samples != samples) { + d->m_samples = samples; + emit samplesChanged(samples); + } +} + +/*! + \return the number of samples per texel for the texture provider. + + \note this has a meaning only for texture providers that have multisample + formats. + */ +int QAbstractTexture::samples() const +{ + Q_D(const QAbstractTexture); + return d->m_samples; +} + +/*! \property Qt3DRender::QAbstractTexture::format Holds the format of the texture provider. @@ -536,6 +598,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QAbstractTexture::createNodeCreationChange() data.comparisonMode = d->m_comparisonMode; data.textureImageIds = qIdsForNodes(d->m_textureImages); data.layers = d->m_layers; + data.samples = d->m_samples; data.dataFunctor = d->m_dataFunctor; return creationChange; } diff --git a/src/render/texture/qabstracttexture.h b/src/render/texture/qabstracttexture.h index eb4ad66f8..53868b319 100644 --- a/src/render/texture/qabstracttexture.h +++ b/src/render/texture/qabstracttexture.h @@ -72,6 +72,7 @@ class QT3DRENDERSHARED_EXPORT QAbstractTexture : public Qt3DCore::QNode Q_PROPERTY(ComparisonFunction comparisonFunction READ comparisonFunction WRITE setComparisonFunction NOTIFY comparisonFunctionChanged) Q_PROPERTY(ComparisonMode comparisonMode READ comparisonMode WRITE setComparisonMode NOTIFY comparisonModeChanged) Q_PROPERTY(int layers READ layers WRITE setLayers NOTIFY layersChanged) + Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged) public: @@ -81,7 +82,7 @@ public: Ready, Error }; - Q_ENUM(Status) + Q_ENUM(Status) // LCOV_EXCL_LINE enum Target { TargetAutomatic = 0, // Target will be determined by the Qt3D engine @@ -97,7 +98,7 @@ public: TargetRectangle = 0x84F5, // GL_TEXTURE_RECTANGLE TargetBuffer = 0x8C2A // GL_TEXTURE_BUFFER }; - Q_ENUM(Target) + Q_ENUM(Target) // LCOV_EXCL_LINE enum TextureFormat { NoFormat = 0, // GL_NONE @@ -226,7 +227,7 @@ public: LuminanceFormat = 0x1909, // GL_LUMINANCE LuminanceAlphaFormat = 0x190A }; - Q_ENUM(TextureFormat) + Q_ENUM(TextureFormat) // LCOV_EXCL_LINE enum Filter { Nearest = 0x2600, // GL_NEAREST @@ -236,7 +237,7 @@ public: LinearMipMapNearest = 0x2701, // GL_LINEAR_MIPMAP_NEAREST LinearMipMapLinear = 0x2703 // GL_LINEAR_MIPMAP_LINEAR }; - Q_ENUM(Filter) + Q_ENUM(Filter) // LCOV_EXCL_LINE enum CubeMapFace { CubeMapPositiveX = 0x8515, // GL_TEXTURE_CUBE_MAP_POSITIVE_X @@ -244,9 +245,10 @@ public: CubeMapPositiveY = 0x8517, // GL_TEXTURE_CUBE_MAP_POSITIVE_Y CubeMapNegativeY = 0x8518, // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y CubeMapPositiveZ = 0x8519, // GL_TEXTURE_CUBE_MAP_POSITIVE_Z - CubeMapNegativeZ = 0x851A // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z + CubeMapNegativeZ = 0x851A, // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z + AllFaces }; - Q_ENUM(CubeMapFace) + Q_ENUM(CubeMapFace) // LCOV_EXCL_LINE enum ComparisonFunction { CompareLessEqual = 0x0203, // GL_LEQUAL @@ -258,13 +260,13 @@ public: CompareAlways = 0x0207, // GL_ALWAYS CompareNever = 0x0200 // GL_NEVER }; - Q_ENUM(ComparisonFunction) + Q_ENUM(ComparisonFunction) // LCOV_EXCL_LINE enum ComparisonMode { CompareRefToTexture = 0x884E, // GL_COMPARE_REF_TO_TEXTURE CompareNone = 0x0000 // GL_NONE }; - Q_ENUM(ComparisonMode) + Q_ENUM(ComparisonMode) // LCOV_EXCL_LINE ~QAbstractTexture(); @@ -294,6 +296,7 @@ public: int height() const; int depth() const; int layers() const; + int samples() const; QTextureGeneratorPtr dataGenerator() const; public Q_SLOTS: @@ -308,6 +311,7 @@ public Q_SLOTS: void setComparisonFunction(ComparisonFunction function); void setComparisonMode(ComparisonMode mode); void setLayers(int layers); + void setSamples(int samples); Q_SIGNALS: void formatChanged(TextureFormat format); @@ -322,6 +326,7 @@ Q_SIGNALS: void comparisonFunctionChanged(ComparisonFunction comparisonFunction); void comparisonModeChanged(ComparisonMode comparisonMode); void layersChanged(int layers); + void samplesChanged(int samples); protected: explicit QAbstractTexture(Qt3DCore::QNode *parent = nullptr); @@ -339,6 +344,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QAbstractTexture *) +Q_DECLARE_METATYPE(Qt3DRender::QAbstractTexture *) // LCOV_EXCL_LINE #endif // QT3DRENDER_QABSTRACTTEXTURE_H diff --git a/src/render/texture/qabstracttexture_p.h b/src/render/texture/qabstracttexture_p.h index dca912611..7f5a32c94 100644 --- a/src/render/texture/qabstracttexture_p.h +++ b/src/render/texture/qabstracttexture_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { -class QAbstractTexturePrivate : public Qt3DCore::QNodePrivate +class Q_AUTOTEST_EXPORT QAbstractTexturePrivate : public Qt3DCore::QNodePrivate { public : QAbstractTexturePrivate(); @@ -84,7 +84,11 @@ public : QAbstractTexture::ComparisonMode m_comparisonMode; QVector<QAbstractTextureImage *> m_textureImages; int m_layers; + int m_samples; + void setDataFunctor(const QTextureGeneratorPtr &generator); + +private: QTextureGeneratorPtr m_dataFunctor; }; @@ -106,6 +110,7 @@ struct QAbstractTextureData QAbstractTexture::ComparisonMode comparisonMode; Qt3DCore::QNodeIdVector textureImageIds; int layers; + int samples; QTextureGeneratorPtr dataFunctor; }; diff --git a/src/render/texture/qabstracttextureimage.cpp b/src/render/texture/qabstracttextureimage.cpp index 42e78ced6..2f91539ff 100644 --- a/src/render/texture/qabstracttextureimage.cpp +++ b/src/render/texture/qabstracttextureimage.cpp @@ -78,7 +78,7 @@ namespace Qt3DRender { \fn bool QTextureImageDataGenerator::operator ==(const QTextureImageDataGenerator &other) const Implement the method to compare this texture data generator to \a other. - The operator is used to check if the \l QAbstractTextureImage needs to reload + Returns a boolean that indicates whether the \l QAbstractTextureImage needs to reload the \l QTextureImageData. */ diff --git a/src/render/texture/qabstracttextureimage.h b/src/render/texture/qabstracttextureimage.h index 698539ab3..7041483b2 100644 --- a/src/render/texture/qabstracttextureimage.h +++ b/src/render/texture/qabstracttextureimage.h @@ -47,10 +47,6 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { -namespace Render { -class TextureImage; -} - class QAbstractTextureImagePrivate; class QT3DRENDERSHARED_EXPORT QAbstractTextureImage : public Qt3DCore::QNode @@ -84,7 +80,6 @@ protected: private: Q_DECLARE_PRIVATE(QAbstractTextureImage) - friend class Render::TextureImage; Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; }; diff --git a/src/render/texture/qpaintedtextureimage.cpp b/src/render/texture/qpaintedtextureimage.cpp new file mode 100644 index 000000000..6de253128 --- /dev/null +++ b/src/render/texture/qpaintedtextureimage.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintedtextureimage.h" +#include "qpaintedtextureimage_p.h" + +#include <QtGui/qpainter.h> +#include <QtGui/qimage.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +QPaintedTextureImagePrivate::QPaintedTextureImagePrivate() + : m_imageSize(256,256) + , m_generation(0) +{ +} + +QPaintedTextureImagePrivate::~QPaintedTextureImagePrivate() +{ +} + +void QPaintedTextureImagePrivate::repaint() +{ + // create or re-allocate QImage with current size + if (m_image.isNull() || (m_image->size() != m_imageSize)) + m_image.reset(new QImage(m_imageSize, QImage::Format_RGBA8888)); + + QPainter painter(m_image.data()); + q_func()->paint(&painter); + painter.end(); + + ++m_generation; + m_currentGenerator.reset(new QPaintedTextureImageDataGenerator(*m_image.data(), m_generation, q_func()->id())); + q_func()->notifyDataGeneratorChanged(); +} + +QPaintedTextureImage::QPaintedTextureImage(Qt3DCore::QNode *parent) + : QAbstractTextureImage(*new QPaintedTextureImagePrivate, parent) +{ +} + +QPaintedTextureImage::~QPaintedTextureImage() +{ +} + +int QPaintedTextureImage::width() const +{ + Q_D(const QPaintedTextureImage); + return d->m_imageSize.width(); +} + +int QPaintedTextureImage::height() const +{ + Q_D(const QPaintedTextureImage); + return d->m_imageSize.height(); +} + +QSize QPaintedTextureImage::size() const +{ + Q_D(const QPaintedTextureImage); + return d->m_imageSize; +} + +void QPaintedTextureImage::setWidth(int w) +{ + if (w < 1) { + qWarning() << "QPaintedTextureImage: Attempting to set invalid width" << w << ". Will be ignored"; + return; + } + setSize(QSize(w, height())); +} + +void QPaintedTextureImage::setHeight(int h) +{ + if (h < 1) { + qWarning() << "QPaintedTextureImage: Attempting to set invalid height" << h << ". Will be ignored"; + return; + } + setSize(QSize(width(), h)); +} + +void QPaintedTextureImage::setSize(QSize size) +{ + Q_D(QPaintedTextureImage); + + if (d->m_imageSize != size) { + if (size.isEmpty()) { + qWarning() << "QPaintedTextureImage: Attempting to set invalid size" << size << ". Will be ignored"; + return; + } + + const bool changeW = d->m_imageSize.width() != size.width(); + const bool changeH = d->m_imageSize.height() != size.height(); + + d->m_imageSize = size; + + if (changeW) + Q_EMIT widthChanged(d->m_imageSize.height()); + if (changeH) + Q_EMIT heightChanged(d->m_imageSize.height()); + + Q_EMIT sizeChanged(d->m_imageSize); + + d->repaint(); + } +} + +void QPaintedTextureImage::update(const QRect &rect) +{ + Q_UNUSED(rect) + Q_D(QPaintedTextureImage); + + d->repaint(); +} + +QTextureImageDataGeneratorPtr QPaintedTextureImage::dataGenerator() const +{ + Q_D(const QPaintedTextureImage); + return d->m_currentGenerator; +} + + +QPaintedTextureImageDataGenerator::QPaintedTextureImageDataGenerator(const QImage &image, int gen, Qt3DCore::QNodeId texId) + : m_image(image) // pixels are implicitly shared, no copying + , m_generation(gen) + , m_paintedTextureImageId(texId) +{ +} + +QPaintedTextureImageDataGenerator::~QPaintedTextureImageDataGenerator() +{ +} + +QTextureImageDataPtr QPaintedTextureImageDataGenerator::operator ()() +{ + QTextureImageDataPtr textureData = QTextureImageDataPtr::create(); + textureData->setImage(m_image); + return textureData; +} + +bool QPaintedTextureImageDataGenerator::operator ==(const QTextureImageDataGenerator &other) const +{ + const QPaintedTextureImageDataGenerator *otherFunctor = functor_cast<QPaintedTextureImageDataGenerator>(&other); + return (otherFunctor != Q_NULLPTR && otherFunctor->m_generation == m_generation && otherFunctor->m_paintedTextureImageId == m_paintedTextureImageId); +} + +} // namespace Qt3DRender + +QT_END_NAMESPACE + diff --git a/src/render/texture/qpaintedtextureimage.h b/src/render/texture/qpaintedtextureimage.h new file mode 100644 index 000000000..ff62da118 --- /dev/null +++ b/src/render/texture/qpaintedtextureimage.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QPAINTEDTEXTURE_H +#define QT3DRENDER_QPAINTEDTEXTURE_H + +#include <Qt3DRender/qabstracttextureimage.h> + +QT_BEGIN_NAMESPACE + +class QPainter; + +namespace Qt3DRender { + +class QPaintedTextureImagePrivate; + +class QT3DRENDERSHARED_EXPORT QPaintedTextureImage : public QAbstractTextureImage +{ + Q_OBJECT + Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged) + Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged) + Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged) + +public: + explicit QPaintedTextureImage(Qt3DCore::QNode *parent = nullptr); + ~QPaintedTextureImage(); + + int width() const; + int height() const; + QSize size() const; + + void update(const QRect &rect = QRect()); + +public Q_SLOTS: + void setWidth(int w); + void setHeight(int h); + void setSize(QSize size); + +Q_SIGNALS: + void widthChanged(int w); + void heightChanged(int w); + void sizeChanged(QSize size); + +protected: + virtual void paint(QPainter *painter) = 0; + +private: + Q_DECLARE_PRIVATE(QPaintedTextureImage) + + QTextureImageDataGeneratorPtr dataGenerator() const Q_DECL_OVERRIDE; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QPAINTEDTEXTURE_H diff --git a/src/render/texture/qpaintedtextureimage_p.h b/src/render/texture/qpaintedtextureimage_p.h new file mode 100644 index 000000000..4fcaa6c93 --- /dev/null +++ b/src/render/texture/qpaintedtextureimage_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QPAINTEDTEXTURE_P_H +#define QT3DRENDER_QPAINTEDTEXTURE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DRender/private/qabstracttextureimage_p.h> +#include <Qt3DRender/qtextureimagedatagenerator.h> +#include <Qt3DRender/qpaintedtextureimage.h> + +QT_BEGIN_NAMESPACE + +class QImage; +class QPainter; + +namespace Qt3DRender { + +class QPaintedTextureImagePrivate : public QAbstractTextureImagePrivate +{ +public: + QPaintedTextureImagePrivate(); + ~QPaintedTextureImagePrivate(); + + Q_DECLARE_PUBLIC(QPaintedTextureImage) + + QSize m_imageSize; + QScopedPointer<QImage> m_image; + QTextureImageDataGeneratorPtr m_currentGenerator; + + // gets increased each time the image is re-painted. + // used to distinguish between different generators + quint64 m_generation; + + void repaint(); +}; + +class QPaintedTextureImageDataGenerator : public QTextureImageDataGenerator +{ +public: + QPaintedTextureImageDataGenerator(const QImage &image, int gen, Qt3DCore::QNodeId texId); + ~QPaintedTextureImageDataGenerator(); + + // Will be executed from within a QAspectJob + QTextureImageDataPtr operator ()() Q_DECL_FINAL; + bool operator ==(const QTextureImageDataGenerator &other) const Q_DECL_FINAL; + + QT3D_FUNCTOR(QPaintedTextureImageDataGenerator) + +private: + QImage m_image; + quint64 m_generation; + Qt3DCore::QNodeId m_paintedTextureImageId; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QPAINTEDTEXTURE_P_H diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp index 13e6a04ab..a566ecc36 100644 --- a/src/render/texture/qtexture.cpp +++ b/src/render/texture/qtexture.cpp @@ -623,7 +623,7 @@ QTextureImageDataPtr setDdsFile(const QString &source) } // anonynous -QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool allow3D) +QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool allow3D, bool mirrored) { QTextureImageDataPtr textureData; if (url.isLocalFile() || url.scheme() == QLatin1String("qrc")) { @@ -640,7 +640,7 @@ QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool QImage img; if (img.load(source)) { textureData = QTextureImageDataPtr::create(); - textureData->setImage(img.mirrored()); + textureData->setImage(mirrored ? img.mirrored() : img); } break; } @@ -656,7 +656,7 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()() QTextureDataPtr generatedData = QTextureDataPtr::create(); m_status = QAbstractTexture::Loading; - const QTextureImageDataPtr textureData = TextureLoadingHelper::loadTextureData(m_url, true); + const QTextureImageDataPtr textureData = TextureLoadingHelper::loadTextureData(m_url, true, m_mirrored); if (textureData && textureData->data().length() > 0) { generatedData->setTarget(static_cast<QAbstractTexture::Target>(textureData->target())); @@ -676,6 +676,7 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()() QTextureLoaderPrivate::QTextureLoaderPrivate() : QAbstractTexturePrivate() + , m_mirrored(true) { } @@ -922,6 +923,12 @@ QUrl QTextureLoader::source() const return d->m_source; } +bool QTextureLoader::isMirrored() const +{ + Q_D(const QTextureLoader); + return d->m_mirrored; +} + /*! * Sets the texture loader source to \a source. * \param source @@ -931,8 +938,58 @@ void QTextureLoader::setSource(const QUrl& source) Q_D(QTextureLoader); if (source != d->m_source) { d->m_source = source; - d->m_dataFunctor.reset(new QTextureFromSourceGenerator(source)); + d->setDataFunctor(QTextureFromSourceGeneratorPtr::create(d->m_source, d->m_mirrored)); + const bool blocked = blockNotifications(true); emit sourceChanged(source); + blockNotifications(blocked); + } +} + +/*! + \property Qt3DRender::QTextureLoader::mirrored + + This property specifies whether the texture should be mirrored when loaded. This + is a convenience to avoid having to manipulate images to match the origin of + the texture coordinates used by the rendering API. By default this property + is set to true. This has no effect when using compressed texture formats. + + \note OpenGL specifies the origin of texture coordinates from the lower left + hand corner whereas DirectX uses the the upper left hand corner. + + \note When using cube map texture you'll probably want mirroring disabled as + the cube map sampler takes a direction rather than regular texture + coordinates. +*/ + +/*! + \qmlproperty bool Qt3DRender::QTextureLoader::mirrored + + This property specifies whether the texture should be mirrored when loaded. This + is a convenience to avoid having to manipulate images to match the origin of + the texture coordinates used by the rendering API. By default this property + is set to true. This has no effect when using compressed texture formats. + + \note OpenGL specifies the origin of texture coordinates from the lower left + hand corner whereas DirectX uses the the upper left hand corner. + + \note When using cube map texture you'll probably want mirroring disabled as + the cube map sampler takes a direction rather than regular texture + coordinates. +*/ + +/*! + Sets mirroring to \a mirrored. + \note This internally triggers a call to update the data generator. + */ +void QTextureLoader::setMirrored(bool mirrored) +{ + Q_D(QTextureLoader); + if (mirrored != d->m_mirrored) { + d->m_mirrored = mirrored; + d->setDataFunctor(QTextureFromSourceGeneratorPtr::create(d->m_source, d->m_mirrored)); + const bool blocked = blockNotifications(true); + emit mirroredChanged(mirrored); + blockNotifications(blocked); } } @@ -943,7 +1000,19 @@ void QTextureLoader::setSource(const QUrl& source) bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) const { const QTextureFromSourceGenerator *otherFunctor = functor_cast<QTextureFromSourceGenerator>(&other); - return (otherFunctor != Q_NULLPTR && otherFunctor->m_url == m_url); + return (otherFunctor != nullptr && + otherFunctor->m_url == m_url && + otherFunctor->m_mirrored == m_mirrored); +} + +QUrl QTextureFromSourceGenerator::url() const +{ + return m_url; +} + +bool QTextureFromSourceGenerator::isMirrored() const +{ + return m_mirrored; } /*! @@ -951,10 +1020,11 @@ bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) co * instance with \a url. * \param url */ -QTextureFromSourceGenerator::QTextureFromSourceGenerator(const QUrl &url) +QTextureFromSourceGenerator::QTextureFromSourceGenerator(const QUrl &url, bool mirrored) : QTextureGenerator() , m_url(url) , m_status(QAbstractTexture::None) + , m_mirrored(mirrored) { } diff --git a/src/render/texture/qtexture.h b/src/render/texture/qtexture.h index 4d687dc6d..24d19fbcf 100644 --- a/src/render/texture/qtexture.h +++ b/src/render/texture/qtexture.h @@ -149,18 +149,21 @@ class QT3DRENDERSHARED_EXPORT QTextureLoader : public QAbstractTexture { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - + Q_PROPERTY(bool mirrored READ isMirrored WRITE setMirrored NOTIFY mirroredChanged) public: explicit QTextureLoader(Qt3DCore::QNode *parent = nullptr); ~QTextureLoader(); QUrl source() const; + bool isMirrored() const; public Q_SLOTS: void setSource(const QUrl &source); + void setMirrored(bool mirrored); Q_SIGNALS: void sourceChanged(const QUrl &source); + void mirroredChanged(bool mirrored); private: Q_DECLARE_PRIVATE(QTextureLoader) diff --git a/src/render/texture/qtexture_p.h b/src/render/texture/qtexture_p.h index d80e048f7..a0ea71a58 100644 --- a/src/render/texture/qtexture_p.h +++ b/src/render/texture/qtexture_p.h @@ -64,27 +64,33 @@ public: QTextureLoaderPrivate(); QUrl m_source; + bool m_mirrored; }; -class QTextureFromSourceGenerator : public QTextureGenerator +class Q_AUTOTEST_EXPORT QTextureFromSourceGenerator : public QTextureGenerator { public: - explicit QTextureFromSourceGenerator(const QUrl &url); + explicit QTextureFromSourceGenerator(const QUrl &url, bool mirrored); QTextureDataPtr operator ()() Q_DECL_OVERRIDE; bool operator ==(const QTextureGenerator &other) const Q_DECL_OVERRIDE; inline QAbstractTexture::Status status() const { return m_status; } QT3D_FUNCTOR(QTextureFromSourceGenerator) + QUrl url() const; + bool isMirrored() const; + private: QUrl m_url; QAbstractTexture::Status m_status; + bool m_mirrored; }; +typedef QSharedPointer<QTextureFromSourceGenerator> QTextureFromSourceGeneratorPtr; class Q_AUTOTEST_EXPORT TextureLoadingHelper { public: - static QTextureImageDataPtr loadTextureData(const QUrl &source, bool allow3D); + static QTextureImageDataPtr loadTextureData(const QUrl &source, bool allow3D, bool mirrored); }; } // namespace Qt3DRender diff --git a/src/render/texture/qtexturegenerator.h b/src/render/texture/qtexturegenerator.h index 59bebde8c..faa9e1c7b 100644 --- a/src/render/texture/qtexturegenerator.h +++ b/src/render/texture/qtexturegenerator.h @@ -66,6 +66,6 @@ typedef QSharedPointer<QTextureGenerator> QTextureGeneratorPtr; QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QTextureGeneratorPtr) +Q_DECLARE_METATYPE(Qt3DRender::QTextureGeneratorPtr) // LCOV_EXCL_LINE #endif // QT3DRENDER_QTEXTUREGENERATOR_H diff --git a/src/render/texture/qtextureimage.cpp b/src/render/texture/qtextureimage.cpp index dbe0ff05c..c373b815f 100644 --- a/src/render/texture/qtextureimage.cpp +++ b/src/render/texture/qtextureimage.cpp @@ -155,22 +155,95 @@ QTextureImage::Status QTextureImage::status() const } /*! + * \return whether mirroring is enabled or not. + */ +bool QTextureImage::isMirrored() const +{ + Q_D(const QTextureImage); + return d->m_mirrored; +} + +/*! + \property Qt3DRender::QTextureImage::source + + This property holds the source url from which data for the texture + image will be loaded. +*/ + +/*! + \qmlproperty url Qt3D.Render::TextureImage::source + + This property holds the source url from which data for the texture + image will be loaded. +*/ + +/*! Sets the source url of the texture image to \a source. - \note This triggers a call to update() + \note This internally triggers a call to update the data generator. */ void QTextureImage::setSource(const QUrl &source) { Q_D(QTextureImage); if (source != d->m_source) { d->m_source = source; + const bool blocked = blockNotifications(true); emit sourceChanged(source); + blockNotifications(blocked); + notifyDataGeneratorChanged(); + } +} + +/*! + \property Qt3DRender::QTextureImage::mirrored + + This property specifies whether the image should be mirrored when loaded. This + is a convenience to avoid having to manipulate images to match the origin of + the texture coordinates used by the rendering API. By default this property + is set to true. This has no effect when using compressed texture formats. + + \note OpenGL specifies the origin of texture coordinates from the lower left + hand corner whereas DirectX uses the the upper left hand corner. + + \note When using cube map texture you'll probably want mirroring disabled as + the cube map sampler takes a direction rather than regular texture + coordinates. +*/ + +/*! + \qmlproperty bool Qt3DRender::QTextureImage::mirrored + + This property specifies whether the image should be mirrored when loaded. This + is a convenience to avoid having to manipulate images to match the origin of + the texture coordinates used by the rendering API. By default this property + is set to true. This has no effect when using compressed texture formats. + + \note OpenGL specifies the origin of texture coordinates from the lower left + hand corner whereas DirectX uses the the upper left hand corner. + + \note When using cube map texture you'll probably want mirroring disabled as + the cube map sampler takes a direction rather than regular texture + coordinates. +*/ + +/*! + Sets mirroring to \a mirrored. + \note This internally triggers a call to update the data generator. + */ +void QTextureImage::setMirrored(bool mirrored) +{ + Q_D(QTextureImage); + if (mirrored != d->m_mirrored) { + d->m_mirrored = mirrored; + const bool blocked = blockNotifications(true); + emit mirroredChanged(mirrored); + blockNotifications(blocked); notifyDataGeneratorChanged(); } } /*! - Sets the status to \a status. - \param status + * Sets the status to \a status. + * \param status */ void QTextureImage::setStatus(Status status) { @@ -187,7 +260,7 @@ void QTextureImage::setStatus(Status status) */ QTextureImageDataGeneratorPtr QTextureImage::dataGenerator() const { - return QTextureImageDataGeneratorPtr(new QImageTextureDataFunctor(source())); + return QTextureImageDataGeneratorPtr(new QImageTextureDataFunctor(source(), isMirrored())); } /*! @@ -206,10 +279,11 @@ void QTextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) The constructor creates a new QImageTextureDataFunctor::QImageTextureDataFunctor instance with the specified \a url. */ -QImageTextureDataFunctor::QImageTextureDataFunctor(const QUrl &url) +QImageTextureDataFunctor::QImageTextureDataFunctor(const QUrl &url, bool mirrored) : QTextureImageDataGenerator() , m_url(url) , m_status(QTextureImage::None) + , m_mirrored(mirrored) { if (url.isLocalFile()) { QFileInfo info(url.toLocalFile()); @@ -222,7 +296,7 @@ QTextureImageDataPtr QImageTextureDataFunctor::operator ()() // We assume that a texture image is going to contain a single image data // For compressed dds or ktx textures a warning should be issued if // there are layers or 3D textures - return TextureLoadingHelper::loadTextureData(m_url, false); + return TextureLoadingHelper::loadTextureData(m_url, false, m_mirrored); } bool QImageTextureDataFunctor::operator ==(const QTextureImageDataGenerator &other) const @@ -230,7 +304,20 @@ bool QImageTextureDataFunctor::operator ==(const QTextureImageDataGenerator &oth const QImageTextureDataFunctor *otherFunctor = functor_cast<QImageTextureDataFunctor>(&other); // if its the same URL, but different modification times, its not the same image. - return (otherFunctor != Q_NULLPTR && otherFunctor->m_url == m_url && otherFunctor->m_lastModified == m_lastModified); + return (otherFunctor != nullptr && + otherFunctor->m_url == m_url && + otherFunctor->m_lastModified == m_lastModified && + otherFunctor->m_mirrored == m_mirrored); +} + +QUrl QImageTextureDataFunctor::url() const +{ + return m_url; +} + +bool QImageTextureDataFunctor::isMirrored() const +{ + return m_mirrored; } } // namespace Qt3DRender diff --git a/src/render/texture/qtextureimage.h b/src/render/texture/qtextureimage.h index f614ebdab..e2ab54a1b 100644 --- a/src/render/texture/qtextureimage.h +++ b/src/render/texture/qtextureimage.h @@ -54,6 +54,7 @@ class QT3DRENDERSHARED_EXPORT QTextureImage : public QAbstractTextureImage Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(bool mirrored READ isMirrored WRITE setMirrored NOTIFY mirroredChanged) public: explicit QTextureImage(Qt3DCore::QNode *parent = nullptr); @@ -65,17 +66,20 @@ public: Ready, Error }; - Q_ENUM(Status) + Q_ENUM(Status) // LCOV_EXCL_LINE QUrl source() const; Status status() const; + bool isMirrored() const; public Q_SLOTS: void setSource(const QUrl &source); + void setMirrored(bool mirrored); Q_SIGNALS: void sourceChanged(const QUrl &source); void statusChanged(Status status); + void mirroredChanged(bool mirrored); protected: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; diff --git a/src/render/texture/qtextureimage_p.h b/src/render/texture/qtextureimage_p.h index 23ab57acb..323742781 100644 --- a/src/render/texture/qtextureimage_p.h +++ b/src/render/texture/qtextureimage_p.h @@ -67,7 +67,8 @@ class QTextureImagePrivate : public QAbstractTextureImagePrivate public: QTextureImagePrivate() : QAbstractTextureImagePrivate() - , m_status(QTextureImage::Loading) + , m_status(QTextureImage::None) + , m_mirrored(true) { } @@ -75,24 +76,31 @@ public: QUrl m_source; QTextureImage::Status m_status; + bool m_mirrored; }; -class QImageTextureDataFunctor : public QTextureImageDataGenerator +class Q_AUTOTEST_EXPORT QImageTextureDataFunctor : public QTextureImageDataGenerator { public: - QImageTextureDataFunctor(const QUrl &url); + explicit QImageTextureDataFunctor(const QUrl &url, bool mirrored); // Will be executed from within a QAspectJob QTextureImageDataPtr operator ()() Q_DECL_FINAL; bool operator ==(const QTextureImageDataGenerator &other) const Q_DECL_FINAL; inline QTextureImage::Status status() const { return m_status; } QT3D_FUNCTOR(QImageTextureDataFunctor) + QUrl url() const; + bool isMirrored() const; + private: QUrl m_url; QDateTime m_lastModified; QTextureImage::Status m_status; + bool m_mirrored; }; +typedef QSharedPointer<QImageTextureDataFunctor> QImageTextureDataFunctorPtr; + } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/render/texture/qtextureimagedatagenerator.h b/src/render/texture/qtextureimagedatagenerator.h index eee7a8149..5213f3929 100644 --- a/src/render/texture/qtextureimagedatagenerator.h +++ b/src/render/texture/qtextureimagedatagenerator.h @@ -69,6 +69,6 @@ typedef QSharedPointer<QTextureImageDataGenerator> QTextureImageDataGeneratorPtr QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QTextureImageDataGeneratorPtr) +Q_DECLARE_METATYPE(Qt3DRender::QTextureImageDataGeneratorPtr) // LCOV_EXCL_LINE #endif // QT3DRENDER_QTEXTUREIMAGEDATAGENERATOR_H diff --git a/src/render/texture/qtexturewrapmode.h b/src/render/texture/qtexturewrapmode.h index bb27acf4a..7349e654c 100644 --- a/src/render/texture/qtexturewrapmode.h +++ b/src/render/texture/qtexturewrapmode.h @@ -63,7 +63,7 @@ public: ClampToEdge = 0x812F, // GL_CLAMP_TO_EDGE ClampToBorder = 0x812D // GL_CLAMP_TO_BORDER }; - Q_ENUM(WrapMode) + Q_ENUM(WrapMode) // LCOV_EXCL_LINE explicit QTextureWrapMode(WrapMode wrapMode = ClampToEdge, QObject *parent = nullptr); explicit QTextureWrapMode(WrapMode x, WrapMode y, WrapMode z, QObject *parent = nullptr); diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp index 387a00b3b..233dc364a 100644 --- a/src/render/texture/texture.cpp +++ b/src/render/texture/texture.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -37,22 +37,20 @@ ** ****************************************************************************/ -#include <QtCore/qhash.h> #include "texture_p.h" #include <QDebug> #include <QOpenGLFunctions> #include <QOpenGLTexture> -#include <QOpenGLPixelTransferOptions> -#include <Qt3DRender/qtexture.h> -#include <Qt3DRender/qtextureimagedata.h> -#include <Qt3DRender/private/managers_p.h> -#include <Qt3DRender/private/texturedatamanager_p.h> -#include <Qt3DRender/private/qabstracttexture_p.h> #include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/qpropertynodeaddedchange.h> #include <Qt3DCore/qpropertynoderemovedchange.h> +#include <Qt3DRender/private/texture_p.h> +#include <Qt3DRender/private/qabstracttexture_p.h> +#include <Qt3DRender/private/gltexturemanager_p.h> +#include <Qt3DRender/private/managers_p.h> + QT_BEGIN_NAMESPACE using namespace Qt3DCore; @@ -60,542 +58,158 @@ using namespace Qt3DCore; namespace Qt3DRender { namespace Render { -/* A Texture can get its data in two complementary ways - * - Usually when a texture is created it is associated with a various number of - * QTextureImages <-> TextureImage which will internally contain a set of QTexImageData - * - A QTexture can also provide a QTextureGenerator functor which might also - * return a vector of QTexImageData - * So internally a Texture has a vector of HTextureImage which allow to retrieve a TextureImage and HTextureData - * but also a vector of HTextureData filled by the QTextureGenerator if present. - * From a memory management point of view, the texture needs to make sure it releases the HTextureData - * that were generated from the QTextureGenerator as these are not shared and belong to the Texture object. - * The HTextureData associated to a HTextureImage are managed by the TextureImage. - */ - Texture::Texture() - : BackendNode() - , m_gl(nullptr) - , m_width(1) - , m_height(1) - , m_depth(1) - , m_layers(1) - , m_mipLevels(1) - , m_generateMipMaps(false) - , m_target(QAbstractTexture::Target2D) - , m_format(QAbstractTexture::RGBA8_UNorm) - , m_magnificationFilter(QAbstractTexture::Nearest) - , m_minificationFilter(QAbstractTexture::Nearest) - , m_wrapModeX(QTextureWrapMode::ClampToEdge) - , m_wrapModeY(QTextureWrapMode::ClampToEdge) - , m_wrapModeZ(QTextureWrapMode::ClampToEdge) - , m_maximumAnisotropy(1.0f) - , m_comparisonFunction(QAbstractTexture::CompareLessEqual) - , m_comparisonMode(QAbstractTexture::CompareNone) - , m_isDirty(false) - , m_filtersAndWrapUpdated(false) - , m_dataUploadRequired(false) - , m_textureDNA(0) - , m_textureManager(nullptr) + // We need backend -> frontend notifications to update the status of the texture + : BackendNode(ReadWrite) + , m_dirty(DirtyGenerators|DirtyProperties|DirtyParameters) , m_textureImageManager(nullptr) - , m_textureDataManager(nullptr) { - // We need backend -> frontend notifications to update the status of the texture } Texture::~Texture() { - // Release the texture data handles that may have been loaded - // by a QTextureGenerator functor - releaseTextureDataHandles(); + // We do not abandon the api texture + // because if the dtor is called that means + // the manager was destroyed otherwise cleanup + // would have been called } -void Texture::cleanup() +void Texture::setTextureImageManager(TextureImageManager *manager) { - // Release the texture data handles that may have been loaded - // by a QTextureGenerator functor - releaseTextureDataHandles(); - - QBackendNode::setEnabled(false); - m_gl = nullptr; - m_width = 1; - m_height = 1; - m_depth = 1; - m_layers = 1; - m_mipLevels = 1; - m_generateMipMaps = false; - m_target = QAbstractTexture::Target2D; - m_format = QAbstractTexture::RGBA8_UNorm; - m_magnificationFilter = QAbstractTexture::Nearest; - m_minificationFilter = QAbstractTexture::Nearest; - m_wrapModeX = QTextureWrapMode::ClampToEdge; - m_wrapModeY = QTextureWrapMode::ClampToEdge; - m_wrapModeZ = QTextureWrapMode::ClampToEdge; - m_maximumAnisotropy = 1.0f; - m_comparisonFunction = QAbstractTexture::CompareLessEqual; - m_comparisonMode = QAbstractTexture::CompareNone; - m_isDirty = false; - m_filtersAndWrapUpdated = false; - m_dataUploadRequired = false; - m_textureDNA = 0; - m_textureImages.clear(); - m_textureManager = nullptr; - m_textureImageManager = nullptr; - m_textureDataManager = nullptr; - m_dataFunctor.clear(); + m_textureImageManager = manager; } -// AspectThread -void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +void Texture::addDirtyFlag(DirtyFlags flags) { - const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAbstractTextureData>>(change); - const auto &data = typedChange->data; - - QMutexLocker lock(&m_lock); - m_target = data.target; - m_format = data.format; - m_width = data.width; - m_height = data.height; - m_depth = data.depth; - m_generateMipMaps = data.autoMipMap; - m_minificationFilter = data.minFilter; - m_magnificationFilter = data.magFilter; - m_wrapModeX = data.wrapModeX; - m_wrapModeY = data.wrapModeY; - m_wrapModeZ = data.wrapModeZ; - m_maximumAnisotropy = data.maximumAnisotropy; - m_comparisonFunction = data.comparisonFunction; - m_comparisonMode = data.comparisonMode; - m_layers = data.layers; - m_dataFunctor = data.dataFunctor; - if (m_dataFunctor) - addToPendingTextureJobs(); - - // TODO: Handle texture image ids better. At the moment we rely upon the assumption - // in the TextureImage that its parent is a Texture. Better to set the ids from here - // I think, and do it consistently with other types that refer to other nodes. - //data.textureImageIds - - m_isDirty = true; + m_dirty |= flags; } -// RenderTread -QOpenGLTexture *Texture::getOrCreateGLTexture() +void Texture::unsetDirty() { - // m_gl HAS to be destroyed in the OpenGL Thread - // Will be recreated with updated values the next time - // buildGLTexture is called - - - // getOrCreateGLTexture is called by the OpenGL Render Thread - // sceneChangeEvent is called by the QAspectThread - // only the OpenGL Render Thread can set isDirty to false - // only a sceneChangeEvent in QAspectThread can set isDirty to true - // We need the lock to make sure there are no races when the OpenGL - // thread tries to read isDirty or one of the texture properties in case - // we are receiving a sceneChangeEvent that modifies isDirty or one of the properties - // at the same time - - QMutexLocker lock(&m_lock); - if (m_isDirty) { - delete m_gl; - m_gl = nullptr; - m_isDirty = false; - } - - // If the texture exists, we just update it and return - if (m_gl != nullptr) { - - bool refreshDNA = m_filtersAndWrapUpdated || m_dataUploadRequired; - - if (m_filtersAndWrapUpdated) { - updateWrapAndFilters(); - m_filtersAndWrapUpdated = false; - } - if (m_dataUploadRequired) - updateAndLoadTextureImage(); - - if (refreshDNA) - updateDNA(); - - return m_gl; - } - - // Builds a new Texture, the texture was never created or it was destroyed - // because it was dirty - m_gl = buildGLTexture(); - - m_gl->allocateStorage(); - if (!m_gl->isStorageAllocated()) { - qWarning() << Q_FUNC_INFO << "texture storage allocation failed"; - return nullptr; - } - - // Filters and WrapMode are set - updateWrapAndFilters(); - m_filtersAndWrapUpdated = false; - - // Upload textures data the first time - updateAndLoadTextureImage(); - - // Update DNA - updateDNA(); - - // Ideally we might want to abstract that and use the GraphicsContext as a wrapper - // around that. -#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) - if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) { - int err = ctx->functions()->glGetError(); - if (err) - qWarning() << Q_FUNC_INFO << "GL error after generating mip-maps" << QString::number(err, 16); - } -#endif - - return m_gl; + m_dirty = Texture::NotDirty; } -// RenderThread -QOpenGLTexture *Texture::buildGLTexture() +void Texture::addTextureImage(Qt3DCore::QNodeId id) { - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (!ctx) { - qWarning() << Q_FUNC_INFO << "requires an OpenGL context"; - return nullptr; - } - - if (m_target == QAbstractTexture::TargetAutomatic) { - qWarning() << Q_FUNC_INFO << "something went wrong, target shouldn't be automatic at this point"; - return nullptr; - } - - QOpenGLTexture* glTex = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(m_target)); - - // m_format may not be ES2 compatible. Now it's time to convert it, if necessary. - QAbstractTexture::TextureFormat format = m_format; - if (ctx->isOpenGLES() && ctx->format().majorVersion() < 3) { - switch (m_format) { - case QOpenGLTexture::RGBA8_UNorm: - case QOpenGLTexture::RGBAFormat: - format = QAbstractTexture::RGBAFormat; - break; - case QOpenGLTexture::RGB8_UNorm: - case QOpenGLTexture::RGBFormat: - format = QAbstractTexture::RGBFormat; - break; - case QOpenGLTexture::DepthFormat: - format = QAbstractTexture::DepthFormat; - break; - default: - qWarning() << Q_FUNC_INFO << "could not find a matching OpenGL ES 2.0 unsized texture format"; - break; - } - } - - // Map ETC1 to ETC2 when supported. This allows using features like - // immutable storage as ETC2 is standard in GLES 3.0, while the ETC1 extension - // is written against GLES 1.0. - if (m_format == QAbstractTexture::RGB8_ETC1) { - if ((ctx->isOpenGLES() && ctx->format().majorVersion() >= 3) - || ctx->hasExtension(QByteArrayLiteral("GL_OES_compressed_ETC2_RGB8_texture")) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_ES3_compatibility"))) - format = m_format = QAbstractTexture::RGB8_ETC2; - } - - glTex->setFormat(format == QAbstractTexture::Automatic ? - QOpenGLTexture::NoFormat : - static_cast<QOpenGLTexture::TextureFormat>(format)); - glTex->setSize(m_width, m_height, m_depth); - // Set layers count if texture array - if (m_target == QAbstractTexture::Target1DArray || - m_target == QAbstractTexture::Target2DArray || - m_target == QAbstractTexture::Target3D || - m_target == QAbstractTexture::Target2DMultisampleArray || - m_target == QAbstractTexture::TargetCubeMapArray) { - glTex->setLayers(m_layers); + if (!m_textureImageManager) { + qWarning() << "[Qt3DRender::TextureNode] addTextureImage: invalid TextureImageManager"; + return; } - if (m_generateMipMaps) { - glTex->setMipLevels(glTex->maximumMipLevels()); - } else { - glTex->setAutoMipMapGenerationEnabled(false); - glTex->setMipBaseLevel(0); - glTex->setMipMaxLevel(m_mipLevels - 1); - glTex->setMipLevels(m_mipLevels); + const HTextureImage handle = m_textureImageManager->lookupHandle(id); + if (handle.isNull()) { + qWarning() << "[Qt3DRender::TextureNode] addTextureImage: image handle is NULL"; + } else if (!m_textureImages.contains(handle)) { + m_textureImages << handle; + addDirtyFlag(DirtyGenerators); } - - if (!glTex->create()) { - qWarning() << Q_FUNC_INFO << "creating QOpenGLTexture failed"; - return nullptr; - } - - // FIXME : make this conditional on Qt version - // work-around issue in QOpenGLTexture DSA emulaation which rasies - // an Invalid Enum error -#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) - int err = ctx->functions()->glGetError(); - if (err) - qWarning() << Q_FUNC_INFO << err; -#endif - - return glTex; } -// RenderThread -void Texture::setToGLTexture(QTextureImageData *imgData) +void Texture::removeTextureImage(Qt3DCore::QNodeId id) { - Q_ASSERT(m_gl && m_gl->isCreated() && m_gl->isStorageAllocated()); - - const int layers = imgData->layers(); - const int faces = imgData->faces(); - const int mipLevels = m_generateMipMaps ? 1 : imgData->mipLevels(); - - for (int layer = 0; layer < layers; layer++) { - for (int face = 0; face < faces; face++) { - for (int level = 0; level < mipLevels; level++) { - // ensure we don't accidently cause a detach / copy of the raw bytes - const QByteArray &bytes(imgData->data(layer, face, level)); - - if (imgData->isCompressed()) { - m_gl->setCompressedData(level, - layer, - static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face), - bytes.size(), - bytes.constData()); - } else { - QOpenGLPixelTransferOptions uploadOptions; - uploadOptions.setAlignment(1); - m_gl->setData(level, - layer, - static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face), - imgData->pixelFormat(), - imgData->pixelType(), - bytes.constData(), - &uploadOptions); - } - } - } + if (!m_textureImageManager) { + qWarning() << "[Qt3DRender::TextureNode] removeTextureImage: invalid TextureImageManager"; + return; } - // FIXME : make this conditional on Qt version - // work-around issue in QOpenGLTexture DSA emulation which rasies - // an Invalid Enum error -#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) - if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) { - int err = ctx->functions()->glGetError(); - if (err) - qWarning() << Q_FUNC_INFO << err; - } -#endif -} - -// RenderThread -void Texture::setToGLTexture(TextureImage *rImg, QTextureImageData *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(rImg->mipLevel(), - rImg->layer(), - static_cast<QOpenGLTexture::CubeMapFace>(rImg->face()), - bytes.size(), - bytes.constData()); + const HTextureImage handle = m_textureImageManager->lookupHandle(id); + if (handle.isNull()) { + qWarning() << "[Qt3DRender::TextureNode] removeTextureImage: image handle is NULL"; } else { - QOpenGLPixelTransferOptions uploadOptions; - uploadOptions.setAlignment(1); - m_gl->setData(rImg->mipLevel(), - rImg->layer(), - static_cast<QOpenGLTexture::CubeMapFace>(rImg->face()), - imgData->pixelFormat(), - imgData->pixelType(), - bytes.constData(), - &uploadOptions); - } - - // FIXME : make this conditional on Qt version - // work-around issue in QOpenGLTexture DSA emulaation which rasies - // an Invalid Enum error -#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) - if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) { - int err = ctx->functions()->glGetError(); - if (err) - qWarning() << Q_FUNC_INFO << err; - } -#endif -} - -// RenderThread -void Texture::updateWrapAndFilters() -{ - m_gl->setWrapMode(QOpenGLTexture::DirectionS, static_cast<QOpenGLTexture::WrapMode>(m_wrapModeX)); - if (m_target != QAbstractTexture::Target1D && - m_target != QAbstractTexture::Target1DArray && - m_target != QAbstractTexture::TargetBuffer) - m_gl->setWrapMode(QOpenGLTexture::DirectionT, static_cast<QOpenGLTexture::WrapMode>(m_wrapModeY)); - if (m_target == QAbstractTexture::Target3D) - m_gl->setWrapMode(QOpenGLTexture::DirectionR, static_cast<QOpenGLTexture::WrapMode>(m_wrapModeZ)); - m_gl->setMinMagFilters(static_cast<QOpenGLTexture::Filter>(m_minificationFilter), - static_cast<QOpenGLTexture::Filter>(m_magnificationFilter)); - if (m_gl->hasFeature(QOpenGLTexture::AnisotropicFiltering)) - m_gl->setMaximumAnisotropy(m_maximumAnisotropy); - if (m_gl->hasFeature(QOpenGLTexture::TextureComparisonOperators)) { - m_gl->setComparisonFunction(static_cast<QOpenGLTexture::ComparisonFunction>(m_comparisonFunction)); - m_gl->setComparisonMode(static_cast<QOpenGLTexture::ComparisonMode>(m_comparisonMode)); - } -} - -void Texture::updateDNA() -{ - const int key = m_width + m_height + m_depth + m_layers + m_mipLevels + - (m_generateMipMaps ? 1 : 0) + - static_cast<int>(m_target) + - static_cast<int>(m_format) + - static_cast<int>(m_magnificationFilter) + - static_cast<int>(m_minificationFilter) + - static_cast<int>(m_wrapModeX) + - static_cast<int>(m_wrapModeY) + - static_cast<int>(m_wrapModeZ) + - static_cast<int>(m_comparisonFunction) + - static_cast<int>(m_comparisonMode); - m_textureDNA = ::qHash(key) + ::qHash(m_maximumAnisotropy); - - // apply non-unique hashes from texture images or texture data - for (HTextureImage imgHandle : qAsConst(m_textureImages)) { - TextureImage *img = m_textureImageManager->data(imgHandle); - if (img) - m_textureDNA += img->dna(); - } - for (const HTextureData textureDataHandle : qAsConst(m_textureDataHandles)) - m_textureDNA += ::qHash(textureDataHandle.index()); - - // if texture contains no potentially shared image data: texture is unique - if (m_textureImages.empty() && m_textureDataHandles.isEmpty()) // Ensures uniqueness by adding unique QNode id to the dna - m_textureDNA += qHash(peerId()); -} - -// RenderThread -GLint Texture::textureId() -{ - return getOrCreateGLTexture()->textureId(); -} - -// Any Thread -bool Texture::isTextureReset() const -{ - QMutexLocker lock(&m_lock); - return m_isDirty; -} - -void Texture::setTarget(QAbstractTexture::Target target) -{ - if (target != m_target) { - m_target = target; - m_isDirty = true; - } -} - -void Texture::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; + m_textureImages.removeAll(handle); + addDirtyFlag(DirtyGenerators); } } -void Texture::setFormat(QAbstractTexture::TextureFormat format) -{ - if (format != m_format) { - m_format = format; - m_isDirty |= true; - } -} - -void Texture::setMipLevels(int mipLevels) +void Texture::cleanup() { - if (mipLevels != m_mipLevels) { - m_mipLevels = mipLevels; - m_isDirty = true; - } -} + // Whoever calls this must make sure to also check if this + // texture is being referenced by a shared API specific texture (GLTexture) + m_dataFunctor.reset(); + m_textureImages.clear(); -void Texture::setLayers(int layers) -{ - if (layers != m_layers) { - m_layers = layers; - m_isDirty = true; - } + // set default values + m_properties.width = 1; + m_properties.height = 1; + m_properties.depth = 1; + m_properties.layers = 1; + m_properties.mipLevels = 1; + m_properties.samples = 1; + m_properties.generateMipMaps = false; + m_properties.format = QAbstractTexture::RGBA8_UNorm; + m_properties.target = QAbstractTexture::Target2D; + + m_parameters.magnificationFilter = QAbstractTexture::Nearest; + m_parameters.minificationFilter = QAbstractTexture::Nearest; + m_parameters.wrapModeX = QTextureWrapMode::ClampToEdge; + m_parameters.wrapModeY = QTextureWrapMode::ClampToEdge; + m_parameters.wrapModeZ = QTextureWrapMode::ClampToEdge; + m_parameters.maximumAnisotropy = 1.0f; + m_parameters.comparisonFunction = QAbstractTexture::CompareLessEqual; + m_parameters.comparisonMode = QAbstractTexture::CompareNone; } // ChangeArbiter/Aspect Thread void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { - // The QOpenGLTexture has to be manipulated from the RenderThread only - QMutexLocker lock(&m_lock); - // We lock here so that we're sure the texture cannot be rebuilt while we are - // modifying one of its properties + DirtyFlags dirty; + switch (e->type()) { case PropertyUpdated: { QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e); if (propertyChange->propertyName() == QByteArrayLiteral("width")) { - setSize(propertyChange->value().toInt(), m_height, m_depth); + m_properties.width = propertyChange->value().toInt(); + dirty = DirtyProperties; } else if (propertyChange->propertyName() == QByteArrayLiteral("height")) { - setSize(m_width, propertyChange->value().toInt(), m_depth); + m_properties.height = propertyChange->value().toInt(); + dirty = DirtyProperties; } else if (propertyChange->propertyName() == QByteArrayLiteral("depth")) { - setSize(m_width, m_height, propertyChange->value().toInt()); + m_properties.depth = propertyChange->value().toInt(); + dirty = DirtyProperties; + } else if (propertyChange->propertyName() == QByteArrayLiteral("maximumLayers")) { + m_properties.layers = propertyChange->value().toInt(); + dirty = DirtyProperties; + } else if (propertyChange->propertyName() == QByteArrayLiteral("format")) { + m_properties.format = static_cast<QAbstractTexture::TextureFormat>(propertyChange->value().toInt()); + dirty = DirtyProperties; + } else if (propertyChange->propertyName() == QByteArrayLiteral("target")) { + m_properties.target = static_cast<QAbstractTexture::Target>(propertyChange->value().toInt()); + dirty = DirtyProperties; } else if (propertyChange->propertyName() == QByteArrayLiteral("mipmaps")) { - const bool oldMipMaps = m_generateMipMaps; - m_generateMipMaps = propertyChange->value().toBool(); - m_isDirty |= (oldMipMaps != m_generateMipMaps); + m_properties.generateMipMaps = propertyChange->value().toBool(); + dirty = DirtyProperties; } else if (propertyChange->propertyName() == QByteArrayLiteral("minificationFilter")) { - QAbstractTexture::Filter oldMinFilter = m_minificationFilter; - m_minificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt()); - m_filtersAndWrapUpdated |= (oldMinFilter != m_minificationFilter); + m_parameters.minificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt()); + dirty = DirtyParameters; } else if (propertyChange->propertyName() == QByteArrayLiteral("magnificationFilter")) { - QAbstractTexture::Filter oldMagFilter = m_magnificationFilter; - m_magnificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt()); - m_filtersAndWrapUpdated |= (oldMagFilter != m_magnificationFilter); + m_parameters.magnificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt()); + dirty = DirtyParameters; } else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeX")) { - QTextureWrapMode::WrapMode oldWrapModeX = m_wrapModeX; - m_wrapModeX = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt()); - m_filtersAndWrapUpdated |= (oldWrapModeX != m_wrapModeX); + m_parameters.wrapModeX = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt()); + dirty = DirtyParameters; } else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeY")) { - QTextureWrapMode::WrapMode oldWrapModeY = m_wrapModeY; - m_wrapModeY = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt()); - m_filtersAndWrapUpdated |= (oldWrapModeY != m_wrapModeY); + m_parameters.wrapModeY = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt()); + dirty = DirtyParameters; } else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeZ")) { - QTextureWrapMode::WrapMode oldWrapModeZ = m_wrapModeZ; - m_wrapModeZ =static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt()); - m_filtersAndWrapUpdated |= (oldWrapModeZ != m_wrapModeZ); - } else if (propertyChange->propertyName() == QByteArrayLiteral("format")) { - setFormat(static_cast<QAbstractTexture::TextureFormat>(propertyChange->value().toInt())); - } else if (propertyChange->propertyName() == QByteArrayLiteral("target")) { - QAbstractTexture::Target oldTarget = m_target; - m_target = static_cast<QAbstractTexture::Target>(propertyChange->value().toInt()); - m_isDirty |= (oldTarget != m_target); + m_parameters.wrapModeZ =static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt()); + dirty = DirtyParameters; } else if (propertyChange->propertyName() == QByteArrayLiteral("maximumAnisotropy")) { - float oldMaximumAnisotropy = m_maximumAnisotropy; - m_maximumAnisotropy = propertyChange->value().toFloat(); - m_filtersAndWrapUpdated |= !qFuzzyCompare(oldMaximumAnisotropy, m_maximumAnisotropy); + m_parameters.maximumAnisotropy = propertyChange->value().toFloat(); + dirty = DirtyParameters; } else if (propertyChange->propertyName() == QByteArrayLiteral("comparisonFunction")) { - QAbstractTexture::ComparisonFunction oldComparisonFunction = m_comparisonFunction; - m_comparisonFunction = propertyChange->value().value<QAbstractTexture::ComparisonFunction>(); - m_filtersAndWrapUpdated |= (oldComparisonFunction != m_comparisonFunction); + m_parameters.comparisonFunction = propertyChange->value().value<QAbstractTexture::ComparisonFunction>(); + dirty = DirtyParameters; } else if (propertyChange->propertyName() == QByteArrayLiteral("comparisonMode")) { - QAbstractTexture::ComparisonMode oldComparisonMode = m_comparisonMode; - m_comparisonMode = propertyChange->value().value<QAbstractTexture::ComparisonMode>(); - m_filtersAndWrapUpdated |= (oldComparisonMode != m_comparisonMode); - } else if (propertyChange->propertyName() == QByteArrayLiteral("maximumLayers")) { - const int oldLayers = m_layers; - m_layers = propertyChange->value().toInt(); - m_isDirty |= (oldLayers != m_layers); + m_parameters.comparisonMode = propertyChange->value().value<QAbstractTexture::ComparisonMode>(); + dirty = DirtyParameters; + } else if (propertyChange->propertyName() == QByteArrayLiteral("layers")) { + m_properties.layers = propertyChange->value().toInt(); + dirty = DirtyProperties; + } else if (propertyChange->propertyName() == QByteArrayLiteral("samples")) { + m_properties.samples = propertyChange->value().toInt(); + dirty = DirtyProperties; } + // TO DO: Handle the textureGenerator change } break; @@ -603,7 +217,7 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) case PropertyValueAdded: { const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e); if (change->propertyName() == QByteArrayLiteral("textureImage")) { - m_textureImages.append(m_textureImageManager->lookupHandle(change->addedNodeId())); + addTextureImage(change->addedNodeId()); } } break; @@ -611,8 +225,7 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) case PropertyValueRemoved: { const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e); if (change->propertyName() == QByteArrayLiteral("textureImage")) { - m_textureImages.removeOne(m_textureImageManager->lookupHandle(change->removedNodeId())); - // If a TextureImage is removed from a Texture, the texture image data remains on GPU + removeTextureImage(change->removedNodeId()); } } break; @@ -621,136 +234,67 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) break; } - markDirty(AbstractRenderer::AllDirty); - BackendNode::sceneChangeEvent(e); -} - -TextureDNA Texture::dna() const -{ - return m_textureDNA; -} - -// AspectThread -void Texture::setTextureManager(TextureManager *manager) -{ - m_textureManager = manager; -} - -// AspectThread -void Texture::setTextureImageManager(TextureImageManager *manager) -{ - m_textureImageManager = manager; -} - -void Texture::setTextureDataManager(TextureDataManager *manager) -{ - m_textureDataManager = manager; -} - -// RenderThread -void Texture::updateAndLoadTextureImage() -{ - // Upload all QTexImageData set by the QTextureGenerator - for (const HTextureData textureDataHandle : qAsConst(m_textureDataHandles)) { - QTextureImageData *data = m_textureDataManager->data(textureDataHandle); - if (data != Q_NULLPTR) - setToGLTexture(data); - } - // Upload all QTexImageData references by the TextureImages - QVector<TextureImageDNA> dnas; - for (const HTextureImage t : qAsConst(m_textureImages)) { - TextureImage *img = m_textureImageManager->data(t); - if (img != nullptr && img->isDirty()) { - if (dnas.contains(img->dna())) { - img->unsetDirty(); - continue; - } - QTextureImageData *data = m_textureDataManager->data(img->textureDataHandle()); - if (data != nullptr) { - setToGLTexture(img, data); - dnas.append(img->dna()); - img->unsetDirty(); - } - } - } + addDirtyFlag(dirty); - m_dataUploadRequired = false; + markDirty(AbstractRenderer::AllDirty); + BackendNode::sceneChangeEvent(e); } -void Texture::addTextureImageData(HTextureImage handle) +void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) { - m_textureImages.append(handle); -} + const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAbstractTextureData>>(change); + const auto &data = typedChange->data; -void Texture::removeTextureImageData(HTextureImage handle) -{ - m_textureImages.removeOne(handle); -} + m_properties.target = data.target; + m_properties.format = data.format; + m_properties.width = data.width; + m_properties.height = data.height; + m_properties.depth = data.depth; + m_properties.generateMipMaps = data.autoMipMap; + m_properties.layers = data.layers; + m_properties.samples = data.samples; + m_parameters.minificationFilter = data.minFilter; + m_parameters.magnificationFilter = data.magFilter; + m_parameters.wrapModeX = data.wrapModeX; + m_parameters.wrapModeY = data.wrapModeY; + m_parameters.wrapModeZ = data.wrapModeZ; + m_parameters.maximumAnisotropy = data.maximumAnisotropy; + m_parameters.comparisonFunction = data.comparisonFunction; + m_parameters.comparisonMode = data.comparisonMode; + m_dataFunctor = data.dataFunctor; -void Texture::requestTextureDataUpdate() -{ - m_dataUploadRequired = true; + addDirtyFlag(DirtyFlags(DirtyGenerators|DirtyProperties|DirtyParameters)); } -// 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 Texture::addToPendingTextureJobs() -{ - m_textureDataManager->addToPendingTextures(peerId()); -} TextureFunctor::TextureFunctor(AbstractRenderer *renderer, - TextureManager *textureManager, - TextureImageManager *textureImageManager, - TextureDataManager *textureDataManager) + TextureManager *textureNodeManager, + TextureImageManager *textureImageManager) : m_renderer(renderer) - , m_textureManager(textureManager) + , m_textureNodeManager(textureNodeManager) , m_textureImageManager(textureImageManager) - , m_textureDataManager(textureDataManager) { } Qt3DCore::QBackendNode *TextureFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const { - Texture *backend = m_textureManager->getOrCreateResource(change->subjectId()); - backend->setTextureManager(m_textureManager); + Texture *backend = m_textureNodeManager->getOrCreateResource(change->subjectId()); backend->setTextureImageManager(m_textureImageManager); - backend->setTextureDataManager(m_textureDataManager); backend->setRenderer(m_renderer); return backend; } Qt3DCore::QBackendNode *TextureFunctor::get(Qt3DCore::QNodeId id) const { - return m_textureManager->lookupResource(id); + return m_textureNodeManager->lookupResource(id); } void TextureFunctor::destroy(Qt3DCore::QNodeId id) const { - m_textureManager->releaseResource(id); -} - -void Texture::addTextureDataHandle(HTextureData handle) -{ - m_textureDataHandles.push_back(handle); - // Request a new upload to the GPU - requestTextureDataUpdate(); + m_textureNodeManager->releaseResource(id); } -void Texture::releaseTextureDataHandles() -{ - if (m_textureDataHandles.size() > 0) { - m_isDirty = true; - Q_ASSERT(m_textureDataManager); - for (HTextureData textureData : qAsConst(m_textureDataHandles)) - m_textureDataManager->release(textureData); - m_textureDataHandles.clear(); - // Request a new upload to the GPU - requestTextureDataUpdate(); - } -} } // namespace Render } // namespace Qt3DRender diff --git a/src/render/texture/texture.pri b/src/render/texture/texture.pri index a4d419f07..bd5c34e72 100644 --- a/src/render/texture/texture.pri +++ b/src/render/texture/texture.pri @@ -18,17 +18,23 @@ HEADERS += \ $$PWD/qtexturedata.h \ $$PWD/qtextureimagedatagenerator.h \ $$PWD/qtexturegenerator.h \ - $$PWD/qtexture_p.h + $$PWD/qtexture_p.h \ + $$PWD/qpaintedtextureimage.h \ + $$PWD/qpaintedtextureimage_p.h \ + $$PWD/gltexture_p.h \ + $$PWD/gltexturemanager_p.h \ + $$PWD/apitexturemanager_p.h SOURCES += \ $$PWD/qabstracttextureimage.cpp \ $$PWD/qtextureimage.cpp \ $$PWD/qtexturewrapmode.cpp \ $$PWD/texture.cpp \ - $$PWD/texturedatamanager.cpp \ $$PWD/textureimage.cpp \ $$PWD/qabstracttexture.cpp \ $$PWD/qtexture.cpp \ $$PWD/qtextureimagedata.cpp \ $$PWD/qtexturedata.cpp \ - $$PWD/qtexturegenerator.cpp + $$PWD/qtexturegenerator.cpp \ + $$PWD/qpaintedtextureimage.cpp \ + $$PWD/gltexture.cpp diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h index f578cfd29..07e3791e9 100644 --- a/src/render/texture/texture_p.h +++ b/src/render/texture/texture_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -71,115 +71,118 @@ namespace Render { class TextureManager; class TextureImageManager; -class TextureDataManager; -typedef quint64 TextureDNA; +/** + * General, constant properties of a texture + */ +struct TextureProperties +{ + int width = 1; + int height = 1; + int depth = 1; + int layers = 1; + int mipLevels = 1; + int samples = 1; + QAbstractTexture::Target target = QAbstractTexture::Target2D; + QAbstractTexture::TextureFormat format = QAbstractTexture::RGBA8_UNorm; + bool generateMipMaps = false; + + bool operator==(const TextureProperties &o) const { + return (width == o.width) && (height == o.height) && (depth == o.depth) + && (layers == o.layers) && (mipLevels == o.mipLevels) && (target == o.target) + && (format == o.format) && (generateMipMaps == o.generateMipMaps) + && (samples == o.samples); + } + inline bool operator!=(const TextureProperties &o) const { return !(*this == o); } +}; + +/** + * Texture parameters that are independent of texture data and that may + * change without the re-uploading the texture + */ +struct TextureParameters +{ + QAbstractTexture::Filter magnificationFilter = QAbstractTexture::Nearest; + QAbstractTexture::Filter minificationFilter = QAbstractTexture::Nearest; + QTextureWrapMode::WrapMode wrapModeX = QTextureWrapMode::ClampToEdge; + QTextureWrapMode::WrapMode wrapModeY = QTextureWrapMode::ClampToEdge; + QTextureWrapMode::WrapMode wrapModeZ = QTextureWrapMode::ClampToEdge; + float maximumAnisotropy = 1.0f; + QAbstractTexture::ComparisonFunction comparisonFunction = QAbstractTexture::CompareLessEqual; + QAbstractTexture::ComparisonMode comparisonMode = QAbstractTexture::CompareNone; + + bool operator==(const TextureParameters &o) const { + return (magnificationFilter == o.magnificationFilter) && (minificationFilter == o.minificationFilter) + && (wrapModeX == o.wrapModeX) && (wrapModeY == o.wrapModeY) && (wrapModeZ == o.wrapModeZ) + && (maximumAnisotropy == o.maximumAnisotropy) + && (comparisonFunction == o.comparisonFunction) && (comparisonMode == o.comparisonMode); + } + inline bool operator!=(const TextureParameters &o) const { return !(*this == o); } +}; -class Texture : public BackendNode +/** + * Backend object for QAbstractTexture. Just holds texture properties and parameters. + * Will query the TextureImplManager for an instance of TextureImpl that matches it's + * properties. + */ +class Q_AUTOTEST_EXPORT Texture : public BackendNode { public: Texture(); ~Texture(); - void cleanup(); - - QOpenGLTexture* getOrCreateGLTexture() ; - - GLint textureId(); - bool isTextureReset() const; + enum DirtyFlag { + NotDirty = 0, + DirtyProperties = 0x1, + DirtyParameters = 0x2, + DirtyGenerators = 0x4 + }; + Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag) - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - TextureDNA dna() const; - - void setTextureManager(TextureManager *manager); void setTextureImageManager(TextureImageManager *manager); - void setTextureDataManager(TextureDataManager *manager); - void updateAndLoadTextureImage(); - void addTextureImageData(HTextureImage handle); - void removeTextureImageData(HTextureImage handle); + void addDirtyFlag(DirtyFlags flags); + inline DirtyFlags dirtyFlags() const { return m_dirty; } + void unsetDirty(); - void requestTextureDataUpdate(); - void addToPendingTextureJobs(); - void setTarget(QAbstractTexture::Target target); - void setSize(int width, int height, int depth); - void setFormat(QAbstractTexture::TextureFormat format); - void setMipLevels(int mipmapLevels); - void setLayers(int layers); - - inline QVector<HTextureImage> textureImages() const { return m_textureImages; } - inline QAbstractTexture::TextureFormat format() const { return m_format; } - inline QAbstractTexture::Target target() const { return m_target; } - inline bool isAutoMipMapGenerationEnabled() const { return m_generateMipMaps; } + void addTextureImage(Qt3DCore::QNodeId id); + void removeTextureImage(Qt3DCore::QNodeId id); + void cleanup(); - inline QTextureGeneratorPtr dataGenerator() const { return m_dataFunctor; } - void addTextureDataHandle(HTextureData handle); - inline QVector<HTextureData> textureDataHandles() const { return m_textureDataHandles; } - void releaseTextureDataHandles(); + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - inline bool dataUploadRequired() const { return m_dataUploadRequired; } - inline bool isDirty() const { return m_isDirty; } + inline const TextureProperties& properties() const { return m_properties; } + inline const TextureParameters& parameters() const { return m_parameters; } + inline const QVector<HTextureImage>& textureImages() const { return m_textureImages; } + inline const QTextureGeneratorPtr& dataGenerator() const { return m_dataFunctor; } private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - QOpenGLTexture *m_gl; - - QOpenGLTexture *buildGLTexture(); - void setToGLTexture(QTextureImageData *imgData); - void setToGLTexture(TextureImage *rImg, QTextureImageData *imgData); - void updateWrapAndFilters(); - - int m_width; - int m_height; - int m_depth; - int m_layers; - int m_mipLevels; - bool m_generateMipMaps; - QAbstractTexture::Target m_target; - QAbstractTexture::TextureFormat m_format; - QAbstractTexture::Filter m_magnificationFilter; - QAbstractTexture::Filter m_minificationFilter; - QTextureWrapMode::WrapMode m_wrapModeX; - QTextureWrapMode::WrapMode m_wrapModeY; - QTextureWrapMode::WrapMode m_wrapModeZ; - float m_maximumAnisotropy; - QAbstractTexture::ComparisonFunction m_comparisonFunction; - QAbstractTexture::ComparisonMode m_comparisonMode; + DirtyFlags m_dirty; + TextureProperties m_properties; + TextureParameters m_parameters; QTextureGeneratorPtr m_dataFunctor; - QVector<HTextureData> m_textureDataHandles; QVector<HTextureImage> m_textureImages; - bool m_isDirty; - bool m_filtersAndWrapUpdated; - bool m_dataUploadRequired; - - mutable QMutex m_lock; - TextureDNA m_textureDNA; - TextureManager *m_textureManager; TextureImageManager *m_textureImageManager; - TextureDataManager *m_textureDataManager; - - void updateDNA(); }; class TextureFunctor : public Qt3DCore::QBackendNodeMapper { public: explicit TextureFunctor(AbstractRenderer *renderer, - TextureManager *textureManager, - TextureImageManager *textureImageManager, - TextureDataManager *textureDataManager); + TextureManager *textureNodeManager, + TextureImageManager *textureImageManager); Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_FINAL; Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_FINAL; void destroy(Qt3DCore::QNodeId id) const Q_DECL_FINAL; private: AbstractRenderer *m_renderer; - TextureManager *m_textureManager; + TextureManager *m_textureNodeManager; TextureImageManager *m_textureImageManager; - TextureDataManager *m_textureDataManager; }; } // namespace Render @@ -187,6 +190,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::Render::Texture*) +Q_DECLARE_METATYPE(Qt3DRender::Render::Texture*) // LCOV_EXCL_LINE #endif // QT3DRENDER_RENDER_TEXTURE_H diff --git a/src/render/texture/texturedatamanager.cpp b/src/render/texture/texturedatamanager.cpp deleted file mode 100644 index abd536116..000000000 --- a/src/render/texture/texturedatamanager.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "texturedatamanager_p.h" -#include <Qt3DRender/qtextureimagedatagenerator.h> -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Render { - - -TextureDataManager::TextureDataManager() - : m_mutex(QMutex::Recursive) -{} - -// Called from AspectThread sync -void TextureDataManager::addToPendingTextures(Qt3DCore::QNodeId textureId) -{ - // This simple check ensures that we won't be having n jobs - // for one mesh, in case n Materials are referencing the said - // texture - if (!m_texturesPending.contains(textureId)) - m_texturesPending.append(textureId); -} - -// Called from AspectThread prepare jobs -// Caller will often use std::move on this to clear it -QVector<Qt3DCore::QNodeId> &TextureDataManager::texturesPending() -{ - return m_texturesPending; -} - -// Called from LoadTextureDataJob threads -HTextureData TextureDataManager::textureDataFromFunctor(const QTextureImageDataGeneratorPtr &functor) const -{ - QMutexLocker lock(&m_mutex); - for (int i = 0, m = m_textureDataFunctors.size(); i < m; ++i) { - if (*functor == *(m_textureDataFunctors[i].first)) - return m_textureDataFunctors[i].second; - } - return HTextureData(); -} - -// Called from LoadTextureDataJob threads -void TextureDataManager::addTextureDataForFunctor(HTextureData textureDataHandle, const QTextureImageDataGeneratorPtr &functor) -{ - QMutexLocker lock(&m_mutex); - m_textureDataFunctors.push_back(qMakePair(functor, textureDataHandle)); -} - -// Called from LoadTextureDataJob threads -void TextureDataManager::removeTextureDataFunctor(const QTextureImageDataGeneratorPtr &functor) -{ - QMutexLocker lock(&m_mutex); - for (int i = 0, m = m_textureDataFunctors.size(); i < m; ++i) { - if (*functor == *(m_textureDataFunctors[i].first)) { - m_textureDataFunctors.remove(i); - break; - } - } -} - -// Called from LoadTextureDataJob threads -void TextureDataManager::assignFunctorToTextureImage(const QTextureImageDataGeneratorPtr &newFunctor, HTextureImage imageHandle) -{ - QMutexLocker lock(&m_mutex); - QVector<QPair<QTextureImageDataGeneratorPtr, QVector<HTextureImage> > >::iterator it = m_texturesImagesPerFunctor.begin(); - - bool newFunctorAlreadyExists = false; - bool oldFunctorWasRemoved = false; - while (it != m_texturesImagesPerFunctor.end()) { - QPair<QTextureImageDataGeneratorPtr, QVector<HTextureImage> > &entry = *it; - QTextureImageDataGeneratorPtr functor = entry.first; - QVector<HTextureImage> &imageHandles = entry.second; - const bool functorMatchesNewFunctor = (*functor == *newFunctor); - bool removed = false; - - if (functorMatchesNewFunctor) { - // New Functor already exist, just need to append - imageHandles.push_back(imageHandle); - newFunctorAlreadyExists = true; - } else if (imageHandles.contains(imageHandle)) { - // functor in array != New Functor and contains - // <=> functor was the previous functor of imageHandle - // the image handle, we need to remove the handle - imageHandles.removeAll(imageHandle); - - // If no texture image is referencing the functor anymore - // get rid of the functor - if (imageHandles.isEmpty()) { - // We need to release the texture image data - HTextureData textureDataHandle = textureDataFromFunctor(functor); - if (!m_textureHandlesToRelease.contains(textureDataHandle)) - m_textureHandlesToRelease.push_back(textureDataHandle); - // Remove functor - removeTextureDataFunctor(functor); - // Remove the entry - it = m_texturesImagesPerFunctor.erase(it); - removed = true; - oldFunctorWasRemoved = true; - } - } - - // Early exit if we can - if (oldFunctorWasRemoved && newFunctorAlreadyExists) - break; - - if (!removed) - ++it; - } - - // Insert new imageHandle with new functor - if (!newFunctorAlreadyExists) - m_texturesImagesPerFunctor.push_back(qMakePair(newFunctor, QVector<HTextureImage>() << imageHandle)); -} - -QMutex *TextureDataManager::mutex() const -{ - return &m_mutex; -} - -// Called by cleanup job -// No need to lock -void TextureDataManager::cleanup() -{ - for (int i = 0, m = m_textureHandlesToRelease.size(); i < m; ++i) - release(m_textureHandlesToRelease[i]); - m_textureHandlesToRelease.clear(); -} - -} // namespace Render - -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/render/texture/texturedatamanager_p.h b/src/render/texture/texturedatamanager_p.h index a420460e9..a93bace52 100644 --- a/src/render/texture/texturedatamanager_p.h +++ b/src/render/texture/texturedatamanager_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -51,57 +51,168 @@ // We mean it. // -#include <Qt3DCore/private/qresourcemanager_p.h> +#include <QMutex> +#include <QMutexLocker> #include <Qt3DRender/qtexture.h> #include <Qt3DRender/qtextureimagedata.h> -#include <Qt3DRender/private/handle_types_p.h> - -#include <QPair> -#include <Qt3DCore/qnodeid.h> +#include <Qt3DRender/qtexturegenerator.h> +#include <Qt3DRender/qtextureimagedatagenerator.h> QT_BEGIN_NAMESPACE namespace Qt3DRender { - namespace Render { -typedef QPair<QTextureImageDataGeneratorPtr, QVector<HTextureImage> > FunctorImageHandlesPair; -typedef QPair<QTextureImageDataGeneratorPtr, HTextureData> FunctorTextureDataPair; - -class TextureDataManager : public Qt3DCore::QResourceManager<QTextureImageData, - Qt3DCore::QNodeId, - 16, - Qt3DCore::ArrayAllocatingPolicy, - Qt3DCore::ObjectLevelLockingPolicy> +/** + * The texture data managers associates each texture data generator + * with the data objects generated by them. That is, either + * + * QTextureImageDataGenerator -> QTextureImageData, or + * QTextureGenerator -> QTextureData + * + * This way, texture classes only need to refer to the texture functors used. + * Aspect jobs will make sure that at the start of each frame, all generators + * registered with the GeneratorDataManagers have been executed. + * + * This guarantees that no texture data generator is executed twice. + * + * Each Generator is associated with a number of textures that reference it. + * If the last texture disassociates from a generator, the QTextureData will + * be deleted. + */ +template <class GeneratorPtr, class DataPtr, class APITexture> +class GeneratorDataManager { public: - TextureDataManager(); - void addToPendingTextures(Qt3DCore::QNodeId textureId); + GeneratorDataManager() {} + + /*! + * If no data for the given generator exists, make sure that the + * generators are executed the next frame. Reference generator by + * given texture + */ + void requestData(const GeneratorPtr &generator, const APITexture *tex) + { + QMutexLocker lock(&m_mutex); + + Entry *entry = findEntry(generator); + if (entry == nullptr) + entry = createEntry(generator); + Q_ASSERT(entry); + if (!entry->referencingTextures.contains(tex)) + entry->referencingTextures.push_back(tex); + } + + /*! + * Dereference given generator from texture. If no other textures still reference + * the generator, the associated data will be deleted + */ + void releaseData(const GeneratorPtr &generator, const APITexture *tex) + { + QMutexLocker lock(&m_mutex); + + const auto end = m_data.end(); + for (auto it = m_data.begin(); it != end; ++it) { + Entry &entry = *it; + if (*entry.generator == *generator) { + entry.referencingTextures.removeAll(tex); + // delete, if that was the last reference + if (entry.referencingTextures.empty()) { + m_data.erase(it); + return; + } + } + } + } + + /*! + * Return data associated with given generator, if existent + */ + DataPtr getData(const GeneratorPtr &generator) + { + QMutexLocker lock(&m_mutex); + + const Entry *entry = findEntry(generator); + return entry ? entry->data : DataPtr(); + } + + /*! + * Returns all generators that were not yet executed + */ + QVector<GeneratorPtr> pendingGenerators() + { + QMutexLocker lock(&m_mutex); + + QVector<GeneratorPtr> ret; + for (const Entry &entry : m_data) + if (!entry.data && !ret.contains(entry.generator)) + ret.push_back(entry.generator); + return ret; + } + + /*! + * Assigns a piece of data to the generator that was used to + * create it. + */ + void assignData(const GeneratorPtr &generator, const DataPtr &data) + { + QMutexLocker lock(&m_mutex); + + Entry *entry = findEntry(generator); + if (!entry) + qWarning() << "[TextureDataManager] assignData() called with non-existent generator"; + else + entry->data = data; + } - QVector<Qt3DCore::QNodeId> &texturesPending(); +private: - HTextureData textureDataFromFunctor(const QTextureImageDataGeneratorPtr &functor) const; - void addTextureDataForFunctor(HTextureData textureDataHandle, const QTextureImageDataGeneratorPtr &functor); - void removeTextureDataFunctor(const QTextureImageDataGeneratorPtr &functor); + struct Entry { + GeneratorPtr generator; + QVector<const APITexture*> referencingTextures; + DataPtr data; + }; + + /*! + * Helper function: return entry for given generator if it exists, nullptr + * otherwise. + */ + Entry* findEntry(const GeneratorPtr &generator) + { + for (int i = 0, sz = m_data.size(); i < sz; ++i) + if (*m_data[i].generator == *generator) + return &m_data[i]; + return nullptr; + } + + Entry *createEntry(const GeneratorPtr &generator) + { + Entry newEntry; + newEntry.generator = generator; + + m_data.push_back(newEntry); + return &m_data.back(); + } + + QMutex m_mutex; + QVector<Entry> m_data; +}; - void assignFunctorToTextureImage(const QTextureImageDataGeneratorPtr &functor, HTextureImage imageHandle); +class GLTexture; - QMutex *mutex() const; - void cleanup(); +class Q_AUTOTEST_EXPORT TextureDataManager + : public GeneratorDataManager<QTextureGeneratorPtr, QTextureDataPtr, GLTexture> +{ +}; -private: - QVector<Qt3DCore::QNodeId> m_texturesPending; - QVector<FunctorTextureDataPair> m_textureDataFunctors; - QVector<FunctorImageHandlesPair> m_texturesImagesPerFunctor; - mutable QMutex m_mutex; - QVector<HTextureData> m_textureHandlesToRelease; +class Q_AUTOTEST_EXPORT TextureImageDataManager + : public GeneratorDataManager<QTextureImageDataGeneratorPtr, QTextureImageDataPtr, GLTexture> +{ }; } // namespace Render } // namespace Qt3DRender -Q_DECLARE_RESOURCE_INFO(Qt3DRender::QTextureImageData, Q_REQUIRES_CLEANUP) - QT_END_NAMESPACE #endif // TEXTUREDATAMANAGER_H diff --git a/src/render/texture/textureimage.cpp b/src/render/texture/textureimage.cpp index 7e2ac6277..f44a82649 100644 --- a/src/render/texture/textureimage.cpp +++ b/src/render/texture/textureimage.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -39,9 +39,8 @@ #include "textureimage_p.h" #include <Qt3DCore/qpropertyupdatedchange.h> -#include <Qt3DRender/qtextureimagedatagenerator.h> +#include <Qt3DRender/qtextureimage.h> #include <Qt3DRender/private/managers_p.h> -#include <Qt3DRender/private/texturedatamanager_p.h> #include <Qt3DRender/private/qabstracttextureimage_p.h> QT_BEGIN_NAMESPACE @@ -56,27 +55,16 @@ TextureImage::TextureImage() , m_layer(0) , m_mipLevel(0) , m_face(QAbstractTexture::CubeMapPositiveX) - , m_dirty(true) , m_textureManager(nullptr) - , m_textureImageManager(nullptr) - , m_textureDataManager(nullptr) - , m_dna(0) +{ +} + +TextureImage::~TextureImage() { } void TextureImage::cleanup() { - QBackendNode::setEnabled(false); - m_layer = 0; - m_mipLevel = 0; - m_dirty = true; - m_face = QAbstractTexture::CubeMapPositiveX; - m_generator.reset(); - m_textureManager = nullptr; - m_textureImageManager = nullptr; - m_textureDataManager = nullptr; - m_referencedTextures.clear(); - m_dna = 0; } void TextureImage::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) @@ -89,15 +77,14 @@ void TextureImage::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr m_generator = data.generator; if (!change->parentId()) { - qWarning() << "No QAbstractTextureProvider parent found"; + qWarning() << "No QAbstractTexture parent found"; } else { - m_textureProviderId = change->parentId(); - m_textureProvider = m_textureManager->lookupHandle(m_textureProviderId); + const QNodeId id = change->parentId(); + m_textureProvider = m_textureManager->lookupHandle(id); Texture *texture = m_textureManager->data(m_textureProvider); Q_ASSERT(texture); // Notify the Texture that it has a new TextureImage and needs an update - texture->addTextureImageData(m_textureImageManager->lookupHandle(peerId())); - texture->addToPendingTextureJobs(); + texture->addTextureImage(peerId()); } } @@ -105,27 +92,23 @@ void TextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e); - const bool wasDirty = m_dirty; if (e->type() == PropertyUpdated) { if (propertyChange->propertyName() == QByteArrayLiteral("layer")) { m_layer = propertyChange->value().toInt(); - m_dirty = true; } else if (propertyChange->propertyName() == QByteArrayLiteral("mipLevel")) { m_mipLevel = propertyChange->value().toInt(); - m_dirty = true; } else if (propertyChange->propertyName() == QByteArrayLiteral("face")) { m_face = static_cast<QAbstractTexture::CubeMapFace>(propertyChange->value().toInt()); - m_dirty = true; } else if (propertyChange->propertyName() == QByteArrayLiteral("dataGenerator")) { m_generator = propertyChange->value().value<QTextureImageDataGeneratorPtr>(); - m_dirty = true; } - } - if (!wasDirty && wasDirty != m_dirty) { // Notify the Texture that we were updated and request it to schedule an update job + + // Notify the Texture that we were updated and request it to schedule an update job Texture *txt = m_textureManager->data(m_textureProvider); if (txt != nullptr) - txt->addToPendingTextureJobs(); + txt->addDirtyFlag(Texture::DirtyGenerators); } + markDirty(AbstractRenderer::AllDirty); BackendNode::sceneChangeEvent(e); } @@ -135,64 +118,12 @@ void TextureImage::setTextureManager(TextureManager *manager) m_textureManager = manager; } -void TextureImage::setTextureImageManager(TextureImageManager *manager) -{ - m_textureImageManager = manager; -} - -void TextureImage::setTextureDataManager(TextureDataManager *manager) -{ - m_textureDataManager = manager; -} - -void TextureImage::unsetDirty() -{ - m_dirty = false; -} - -// Called by LoadDataTextureJob when the texture data has been successfully load -void TextureImage::setTextureDataHandle(HTextureData handle) -{ - m_textureDataHandle = handle; -} - -void TextureImage::setStatus(QTextureImage::Status status) -{ - // Notify the frontend - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); - e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); - e->setPropertyName("status"); - e->setValue(status); - notifyObservers(e); -} - -union DNABuilder { - quint64 dna; - quint32 dataHash; - quint16 layer; - quint8 face; - quint8 mipLevel; -}; - -void TextureImage::updateDNA(quint32 dataHash) -{ - // 64 bits [ 32 bits data ] [ 16 bits layer ] [ 8 bits mip level ] [ 8 bits face ] - DNABuilder builder; - builder.dataHash = dataHash; - builder.layer = m_layer; - builder.face = m_face; - builder.mipLevel = m_mipLevel; - - m_dna = builder.dna; -} - -TextureImageFunctor::TextureImageFunctor(AbstractRenderer *renderer, TextureManager *textureManager, - TextureImageManager *textureImageManager, - TextureDataManager *textureDataManager) - : m_textureManager(textureManager) +TextureImageFunctor::TextureImageFunctor(AbstractRenderer *renderer, + TextureManager *textureManager, + TextureImageManager *textureImageManager) + : m_renderer(renderer) + , m_textureManager(textureManager) , m_textureImageManager(textureImageManager) - , m_textureDataManager(textureDataManager) - , m_renderer(renderer) { } @@ -200,8 +131,6 @@ Qt3DCore::QBackendNode *TextureImageFunctor::create(const Qt3DCore::QNodeCreated { TextureImage *backend = m_textureImageManager->getOrCreateResource(change->subjectId()); backend->setTextureManager(m_textureManager); - backend->setTextureImageManager(m_textureImageManager); - backend->setTextureDataManager(m_textureDataManager); backend->setRenderer(m_renderer); return backend; } diff --git a/src/render/texture/textureimage_p.h b/src/render/texture/textureimage_p.h index 8a5f7d0ba..131114f7e 100644 --- a/src/render/texture/textureimage_p.h +++ b/src/render/texture/textureimage_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -54,9 +54,7 @@ #include <Qt3DRender/private/backendnode_p.h> #include <Qt3DRender/private/handle_types_p.h> #include <Qt3DRender/qabstracttexture.h> -#include <Qt3DRender/qtextureimage.h> -#include <Qt3DRender/qabstracttextureimage.h> -#include <qglobal.h> +#include <Qt3DRender/qtextureimagedatagenerator.h> QT_BEGIN_NAMESPACE @@ -68,51 +66,37 @@ class TextureManager; class TextureImageManager; class TextureDataManager; -typedef quint64 TextureImageDNA; - -class TextureImage : public BackendNode +/** + * Backend class for QAbstractTextureImage. + * Will only hold the generator and some info values. + */ +class Q_AUTOTEST_EXPORT TextureImage : public BackendNode { public: TextureImage(); + ~TextureImage(); + void cleanup(); - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - int m_layer; - int m_mipLevel; - QAbstractTexture::CubeMapFace m_face; - bool m_dirty; - inline TextureImageDNA dna() const { return m_dna; } + void setTextureManager(TextureManager *manager); + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; inline int layer() const { return m_layer; } inline int mipLevel() const { return m_mipLevel; } inline QAbstractTexture::CubeMapFace face() const { return m_face; } - - void setTextureManager(TextureManager *manager); - void setTextureImageManager(TextureImageManager *manager); - void setTextureDataManager(TextureDataManager *manager); - void setStatus(QTextureImage::Status status); - void unsetDirty(); - - inline bool isDirty() const { return m_dirty; } - void setTextureDataHandle(HTextureData handle); - - inline HTextureData textureDataHandle() const { return m_textureDataHandle; } inline QTextureImageDataGeneratorPtr dataGenerator() const { return m_generator; } - void updateDNA(quint32 dataHash); private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - + int m_layer; + int m_mipLevel; + QAbstractTexture::CubeMapFace m_face; QTextureImageDataGeneratorPtr m_generator; - HTextureData m_textureDataHandle; + TextureManager *m_textureManager; - TextureImageManager *m_textureImageManager; - TextureDataManager *m_textureDataManager; - QVector<Qt3DCore::QNodeId> m_referencedTextures; HTexture m_textureProvider; - Qt3DCore::QNodeId m_textureProviderId; - TextureImageDNA m_dna; }; class TextureImageFunctor : public Qt3DCore::QBackendNodeMapper @@ -120,18 +104,16 @@ class TextureImageFunctor : public Qt3DCore::QBackendNodeMapper public: explicit TextureImageFunctor(AbstractRenderer *renderer, TextureManager *textureManager, - TextureImageManager *textureImageManager, - TextureDataManager *textureDataManager); + TextureImageManager *textureImageManager); Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_FINAL; Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_FINAL; void destroy(Qt3DCore::QNodeId id) const Q_DECL_FINAL; private: + AbstractRenderer *m_renderer; TextureManager *m_textureManager; TextureImageManager *m_textureImageManager; - TextureDataManager *m_textureDataManager; - AbstractRenderer *m_renderer; }; |