summaryrefslogtreecommitdiffstats
path: root/src/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/render')
-rw-r--r--src/render/backend/commandexecuter.cpp8
-rw-r--r--src/render/backend/managers_p.h62
-rw-r--r--src/render/backend/nodemanagers.cpp7
-rw-r--r--src/render/backend/nodemanagers_p.h8
-rw-r--r--src/render/backend/platformsurfacefilter_p.h1
-rw-r--r--src/render/backend/render-backend.pri12
-rw-r--r--src/render/backend/rendercommand_p.h2
-rw-r--r--src/render/backend/renderer.cpp330
-rw-r--r--src/render/backend/renderer_p.h37
-rw-r--r--src/render/backend/rendersettings.cpp4
-rw-r--r--src/render/backend/rendersettings_p.h4
-rw-r--r--src/render/backend/rendertarget_p.h2
-rw-r--r--src/render/backend/renderview.cpp174
-rw-r--r--src/render/backend/renderview_p.h51
-rw-r--r--src/render/backend/renderviewbuilder.cpp510
-rw-r--r--src/render/backend/renderviewbuilder_p.h133
-rw-r--r--src/render/backend/shaderparameterpack.cpp (renamed from src/render/backend/quniformvalue.cpp)34
-rw-r--r--src/render/backend/shaderparameterpack_p.h (renamed from src/render/backend/quniformvalue_p.h)125
-rw-r--r--src/render/backend/transform.cpp24
-rw-r--r--src/render/backend/transform_p.h7
-rw-r--r--src/render/backend/triangleboundingvolume_p.h2
-rw-r--r--src/render/backend/uniform.cpp236
-rw-r--r--src/render/backend/uniform_p.h211
-rw-r--r--src/render/framegraph/framegraph.pri9
-rw-r--r--src/render/framegraph/framegraphnode.cpp5
-rw-r--r--src/render/framegraph/framegraphnode_p.h5
-rw-r--r--src/render/framegraph/framegraphvisitor.cpp277
-rw-r--r--src/render/framegraph/qclearbuffers.h2
-rw-r--r--src/render/framegraph/qnodraw.cpp83
-rw-r--r--src/render/framegraph/qrendercapture.cpp290
-rw-r--r--src/render/framegraph/qrendercapture.h96
-rw-r--r--src/render/framegraph/qrendercapture_p.h104
-rw-r--r--src/render/framegraph/qrendersurfaceselector.cpp15
-rw-r--r--src/render/framegraph/qrendersurfaceselector.h4
-rw-r--r--src/render/framegraph/qrendertargetselector.h2
-rw-r--r--src/render/framegraph/qsortcriterion.h2
-rw-r--r--src/render/framegraph/qsortpolicy.h2
-rw-r--r--src/render/framegraph/rendercapture.cpp110
-rw-r--r--src/render/framegraph/rendercapture_p.h88
-rw-r--r--src/render/frontend/qcamera.h2
-rw-r--r--src/render/frontend/qcameralens.h2
-rw-r--r--src/render/frontend/qpickingsettings.cpp26
-rw-r--r--src/render/frontend/qpickingsettings.h17
-rw-r--r--src/render/frontend/qpickingsettings_p.h1
-rw-r--r--src/render/frontend/qrenderaspect.cpp24
-rw-r--r--src/render/frontend/qrendersettings.cpp17
-rw-r--r--src/render/frontend/qrendersettings.h3
-rw-r--r--src/render/frontend/qrendersettings_p.h2
-rw-r--r--src/render/frontend/qrendertargetoutput.h6
-rw-r--r--src/render/frontend/sphere_p.h2
-rw-r--r--src/render/geometry/attribute.cpp10
-rw-r--r--src/render/geometry/attribute_p.h4
-rw-r--r--src/render/geometry/buffer.cpp5
-rw-r--r--src/render/geometry/buffer_p.h6
-rw-r--r--src/render/geometry/geometryrenderer.cpp2
-rw-r--r--src/render/geometry/qattribute.cpp46
-rw-r--r--src/render/geometry/qattribute.h21
-rw-r--r--src/render/geometry/qattribute_p.h8
-rw-r--r--src/render/geometry/qbuffer.cpp111
-rw-r--r--src/render/geometry/qbuffer.h7
-rw-r--r--src/render/geometry/qbuffer_p.h7
-rw-r--r--src/render/geometry/qbufferdatagenerator.h2
-rw-r--r--src/render/geometry/qgeometryfactory.h2
-rw-r--r--src/render/geometry/qgeometryrenderer.h2
-rw-r--r--src/render/geometry/qmesh.cpp18
-rw-r--r--src/render/geometry/qmesh_p.h15
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp516
-rw-r--r--src/render/graphicshelpers/graphicscontext_p.h87
-rw-r--r--src/render/graphicshelpers/graphicshelperes2.cpp273
-rw-r--r--src/render/graphicshelpers/graphicshelperes2_p.h30
-rw-r--r--src/render/graphicshelpers/graphicshelperes3.cpp25
-rw-r--r--src/render/graphicshelpers/graphicshelperes3_p.h5
-rw-r--r--src/render/graphicshelpers/graphicshelpergl2.cpp297
-rw-r--r--src/render/graphicshelpers/graphicshelpergl2_p.h31
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2.cpp (renamed from src/render/graphicshelpers/graphicshelpergl3.cpp)498
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2_p.h (renamed from src/render/graphicshelpers/graphicshelpergl3_p.h)34
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_3.cpp388
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_3_p.h32
-rw-r--r--src/render/graphicshelpers/graphicshelpergl4.cpp390
-rw-r--r--src/render/graphicshelpers/graphicshelpergl4_p.h31
-rw-r--r--src/render/graphicshelpers/graphicshelperinterface_p.h33
-rw-r--r--src/render/graphicshelpers/graphicshelpers.pri8
-rw-r--r--src/render/io/qsceneiohandler_p.h2
-rw-r--r--src/render/io/qsceneloader.h2
-rw-r--r--src/render/jobs/calcboundingvolumejob_p.h2
-rw-r--r--src/render/jobs/calcgeometrytrianglevolumes_p.h2
-rw-r--r--src/render/jobs/expandboundingvolumejob_p.h2
-rw-r--r--src/render/jobs/filterlayerentityjob.cpp4
-rw-r--r--src/render/jobs/filterlayerentityjob_p.h6
-rw-r--r--src/render/jobs/framecleanupjob.cpp4
-rw-r--r--src/render/jobs/frustumcullingjob_p.h2
-rw-r--r--src/render/jobs/genericlambdajob_p.h4
-rw-r--r--src/render/jobs/job_common_p.h15
-rw-r--r--src/render/jobs/jobs.pri14
-rw-r--r--src/render/jobs/loadbufferjob_p.h4
-rw-r--r--src/render/jobs/loadgeometryjob_p.h2
-rw-r--r--src/render/jobs/loadtexturedatajob.cpp163
-rw-r--r--src/render/jobs/loadtexturedatajob_p.h11
-rw-r--r--src/render/jobs/materialparametergathererjob.cpp3
-rw-r--r--src/render/jobs/materialparametergathererjob_p.h3
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp657
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h24
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp268
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h166
-rw-r--r--src/render/jobs/renderviewbuilderjob.cpp2
-rw-r--r--src/render/jobs/renderviewinitializerjob.cpp3
-rw-r--r--src/render/jobs/renderviewinitializerjob_p.h6
-rw-r--r--src/render/jobs/renderviewjobutils.cpp18
-rw-r--r--src/render/jobs/renderviewjobutils_p.h6
-rw-r--r--src/render/jobs/sendrendercapturejob.cpp81
-rw-r--r--src/render/jobs/sendrendercapturejob_p.h89
-rw-r--r--src/render/jobs/updatemeshtrianglelistjob.cpp126
-rw-r--r--src/render/jobs/updatemeshtrianglelistjob_p.h88
-rw-r--r--src/render/jobs/updateshaderdatatransformjob.cpp (renamed from src/render/jobs/framepreparationjob.cpp)67
-rw-r--r--src/render/jobs/updateshaderdatatransformjob_p.h (renamed from src/render/jobs/framepreparationjob_p.h)21
-rw-r--r--src/render/jobs/updateworldboundingvolumejob_p.h2
-rw-r--r--src/render/jobs/updateworldtransformjob_p.h2
-rw-r--r--src/render/lights/light_p.h2
-rw-r--r--src/render/lights/qabstractlight.h2
-rw-r--r--src/render/materialsystem/effect.cpp2
-rw-r--r--src/render/materialsystem/effect_p.h2
-rw-r--r--src/render/materialsystem/filterkey.cpp11
-rw-r--r--src/render/materialsystem/filterkey_p.h6
-rw-r--r--src/render/materialsystem/material_p.h2
-rw-r--r--src/render/materialsystem/parameter.cpp20
-rw-r--r--src/render/materialsystem/parameter_p.h10
-rw-r--r--src/render/materialsystem/qgraphicsapifilter.h4
-rw-r--r--src/render/materialsystem/qgraphicsapifilter_p.h6
-rw-r--r--src/render/materialsystem/qshaderdata.h4
-rw-r--r--src/render/materialsystem/qshaderprogram.h2
-rw-r--r--src/render/materialsystem/renderpass.cpp1
-rw-r--r--src/render/materialsystem/shader_p.h2
-rw-r--r--src/render/materialsystem/shaderdata_p.h2
-rw-r--r--src/render/materialsystem/technique.cpp82
-rw-r--r--src/render/materialsystem/technique_p.h24
-rw-r--r--src/render/picking/qpickevent.cpp97
-rw-r--r--src/render/picking/qpickevent.h28
-rw-r--r--src/render/picking/qpickevent_p.h6
-rw-r--r--src/render/picking/qpicktriangleevent.cpp32
-rw-r--r--src/render/picking/qpicktriangleevent.h2
-rw-r--r--src/render/raycasting/qabstractcollisionqueryservice_p.h2
-rw-r--r--src/render/raycasting/qboundingvolume_p.h2
-rw-r--r--src/render/raycasting/qray3d_p.h2
-rw-r--r--src/render/render.pro3
-rw-r--r--src/render/renderstates/qalphatest.h2
-rw-r--r--src/render/renderstates/qblendequation.h2
-rw-r--r--src/render/renderstates/qblendequationarguments.cpp3
-rw-r--r--src/render/renderstates/qblendequationarguments.h5
-rw-r--r--src/render/renderstates/qcullface.h2
-rw-r--r--src/render/renderstates/qdepthtest.h2
-rw-r--r--src/render/renderstates/qfrontface.h2
-rw-r--r--src/render/renderstates/qpointsize.h2
-rw-r--r--src/render/renderstates/qrenderstatecreatedchange.cpp1
-rw-r--r--src/render/renderstates/qstenciloperationarguments.h4
-rw-r--r--src/render/renderstates/qstenciltestarguments.h4
-rw-r--r--src/render/texture/apitexturemanager_p.h376
-rw-r--r--src/render/texture/gltexture.cpp413
-rw-r--r--src/render/texture/gltexture_p.h196
-rw-r--r--src/render/texture/gltexturemanager_p.h79
-rw-r--r--src/render/texture/qabstracttexture.cpp63
-rw-r--r--src/render/texture/qabstracttexture.h23
-rw-r--r--src/render/texture/qabstracttexture_p.h7
-rw-r--r--src/render/texture/qabstracttextureimage.cpp2
-rw-r--r--src/render/texture/qabstracttextureimage.h5
-rw-r--r--src/render/texture/qpaintedtextureimage.cpp188
-rw-r--r--src/render/texture/qpaintedtextureimage.h93
-rw-r--r--src/render/texture/qpaintedtextureimage_p.h106
-rw-r--r--src/render/texture/qtexture.cpp82
-rw-r--r--src/render/texture/qtexture.h5
-rw-r--r--src/render/texture/qtexture_p.h12
-rw-r--r--src/render/texture/qtexturegenerator.h2
-rw-r--r--src/render/texture/qtextureimage.cpp101
-rw-r--r--src/render/texture/qtextureimage.h6
-rw-r--r--src/render/texture/qtextureimage_p.h14
-rw-r--r--src/render/texture/qtextureimagedatagenerator.h2
-rw-r--r--src/render/texture/qtexturewrapmode.h2
-rw-r--r--src/render/texture/texture.cpp728
-rw-r--r--src/render/texture/texture.pri12
-rw-r--r--src/render/texture/texture_p.h155
-rw-r--r--src/render/texture/texturedatamanager.cpp172
-rw-r--r--src/render/texture/texturedatamanager_p.h175
-rw-r--r--src/render/texture/textureimage.cpp109
-rw-r--r--src/render/texture/textureimage_p.h54
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 &parameterPack)
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 &parameterPack)
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 &params)
+ {
+ 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 &params)
+{
+ 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 &params);
+ 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;
};