summaryrefslogtreecommitdiffstats
path: root/src/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/render')
-rw-r--r--src/render/backend/abstractrenderer_p.h8
-rw-r--r--src/render/backend/backendnode.cpp14
-rw-r--r--src/render/backend/backendnode_p.h9
-rw-r--r--src/render/backend/cameralens.cpp89
-rw-r--r--src/render/backend/cameralens_p.h6
-rw-r--r--src/render/backend/commandexecuter.cpp4
-rw-r--r--src/render/backend/computecommand.cpp54
-rw-r--r--src/render/backend/computecommand_p.h3
-rw-r--r--src/render/backend/entity.cpp200
-rw-r--r--src/render/backend/entity_p.h16
-rw-r--r--src/render/backend/entity_p_p.h87
-rw-r--r--src/render/backend/handle_types_p.h4
-rw-r--r--src/render/backend/layer.cpp33
-rw-r--r--src/render/backend/layer_p.h4
-rw-r--r--src/render/backend/levelofdetail.cpp75
-rw-r--r--src/render/backend/levelofdetail_p.h3
-rw-r--r--src/render/backend/managers_p.h11
-rw-r--r--src/render/backend/nodemanagers.cpp95
-rw-r--r--src/render/backend/nodemanagers_p.h168
-rw-r--r--src/render/backend/render-backend.pri1
-rw-r--r--src/render/backend/rendersettings.cpp71
-rw-r--r--src/render/backend/rendersettings_p.h4
-rw-r--r--src/render/backend/rendertarget.cpp48
-rw-r--r--src/render/backend/rendertarget_p.h4
-rw-r--r--src/render/backend/rendertargetoutput.cpp66
-rw-r--r--src/render/backend/rendertargetoutput_p.h3
-rw-r--r--src/render/backend/resourceaccessor.cpp1
-rw-r--r--src/render/backend/transform.cpp44
-rw-r--r--src/render/backend/transform_p.h7
-rw-r--r--src/render/backend/uniform_p.h4
-rw-r--r--src/render/framegraph/blitframebuffer.cpp77
-rw-r--r--src/render/framegraph/blitframebuffer_p.h4
-rw-r--r--src/render/framegraph/buffercapture.cpp1
-rw-r--r--src/render/framegraph/cameraselectornode.cpp28
-rw-r--r--src/render/framegraph/cameraselectornode_p.h5
-rw-r--r--src/render/framegraph/clearbuffers.cpp71
-rw-r--r--src/render/framegraph/clearbuffers_p.h5
-rw-r--r--src/render/framegraph/dispatchcompute.cpp41
-rw-r--r--src/render/framegraph/dispatchcompute_p.h4
-rw-r--r--src/render/framegraph/framegraph.pri13
-rw-r--r--src/render/framegraph/framegraphnode.cpp49
-rw-r--r--src/render/framegraph/framegraphnode_p.h8
-rw-r--r--src/render/framegraph/framegraphvisitor.cpp21
-rw-r--r--src/render/framegraph/framegraphvisitor_p.h2
-rw-r--r--src/render/framegraph/frustumculling.cpp1
-rw-r--r--src/render/framegraph/layerfilternode.cpp51
-rw-r--r--src/render/framegraph/layerfilternode_p.h6
-rw-r--r--src/render/framegraph/memorybarrier.cpp27
-rw-r--r--src/render/framegraph/memorybarrier_p.h3
-rw-r--r--src/render/framegraph/nodraw.cpp1
-rw-r--r--src/render/framegraph/nopicking.cpp (renamed from src/render/renderers/opengl/renderer/glcommands.cpp)20
-rw-r--r--src/render/framegraph/nopicking_p.h (renamed from src/render/renderers/opengl/renderer/glcommands_p.h)31
-rw-r--r--src/render/framegraph/proximityfilter.cpp36
-rw-r--r--src/render/framegraph/proximityfilter_p.h4
-rw-r--r--src/render/framegraph/qblitframebuffer.cpp2
-rw-r--r--src/render/framegraph/qbuffercapture.cpp1
-rw-r--r--src/render/framegraph/qcameraselector.cpp1
-rw-r--r--src/render/framegraph/qclearbuffers.cpp1
-rw-r--r--src/render/framegraph/qframegraphnode.cpp11
-rw-r--r--src/render/framegraph/qlayerfilter.cpp15
-rw-r--r--src/render/framegraph/qmemorybarrier.cpp2
-rw-r--r--src/render/framegraph/qnopicking.cpp139
-rw-r--r--src/render/framegraph/qnopicking.h61
-rw-r--r--src/render/framegraph/qrendercapture.cpp12
-rw-r--r--src/render/framegraph/qrendercapture_p.h14
-rw-r--r--src/render/framegraph/qrenderpassfilter.cpp27
-rw-r--r--src/render/framegraph/qrenderstateset.cpp15
-rw-r--r--src/render/framegraph/qrendersurfaceselector.cpp31
-rw-r--r--src/render/framegraph/qrendertargetselector.cpp9
-rw-r--r--src/render/framegraph/qsortpolicy.cpp6
-rw-r--r--src/render/framegraph/qsortpolicy.h3
-rw-r--r--src/render/framegraph/qsubtreeenabler.cpp185
-rw-r--r--src/render/framegraph/qsubtreeenabler.h83
-rw-r--r--src/render/framegraph/qsubtreeenabler_p.h80
-rw-r--r--src/render/framegraph/qtechniquefilter.cpp27
-rw-r--r--src/render/framegraph/qviewport.cpp1
-rw-r--r--src/render/framegraph/rendercapture.cpp23
-rw-r--r--src/render/framegraph/rendercapture_p.h3
-rw-r--r--src/render/framegraph/renderpassfilternode.cpp68
-rw-r--r--src/render/framegraph/renderpassfilternode_p.h4
-rw-r--r--src/render/framegraph/rendersurfaceselector.cpp67
-rw-r--r--src/render/framegraph/rendersurfaceselector_p.h5
-rw-r--r--src/render/framegraph/rendertargetselectornode.cpp36
-rw-r--r--src/render/framegraph/rendertargetselectornode_p.h4
-rw-r--r--src/render/framegraph/sortpolicy.cpp30
-rw-r--r--src/render/framegraph/sortpolicy_p.h4
-rw-r--r--src/render/framegraph/statesetnode.cpp43
-rw-r--r--src/render/framegraph/statesetnode_p.h4
-rw-r--r--src/render/framegraph/subtreeenabler.cpp (renamed from src/render/jobs/loadtexturedatajob.cpp)63
-rw-r--r--src/render/framegraph/subtreeenabler_p.h82
-rw-r--r--src/render/framegraph/techniquefilternode.cpp65
-rw-r--r--src/render/framegraph/techniquefilternode_p.h4
-rw-r--r--src/render/framegraph/viewportnode.cpp50
-rw-r--r--src/render/framegraph/viewportnode_p.h4
-rw-r--r--src/render/framegraph/waitfence.cpp48
-rw-r--r--src/render/framegraph/waitfence_p.h4
-rw-r--r--src/render/frontend/qcamera.cpp24
-rw-r--r--src/render/frontend/qcamera.h3
-rw-r--r--src/render/frontend/qcameralens.cpp17
-rw-r--r--src/render/frontend/qcameralens_p.h23
-rw-r--r--src/render/frontend/qcomputecommand.cpp6
-rw-r--r--src/render/frontend/qlevelofdetail.cpp29
-rw-r--r--src/render/frontend/qlevelofdetail.h1
-rw-r--r--src/render/frontend/qlevelofdetail_p.h2
-rw-r--r--src/render/frontend/qlevelofdetailswitch.cpp65
-rw-r--r--src/render/frontend/qlevelofdetailswitch.h4
-rw-r--r--src/render/frontend/qlevelofdetailswitch_p.h77
-rw-r--r--src/render/frontend/qpickingsettings.cpp2
-rw-r--r--src/render/frontend/qrenderaspect.cpp168
-rw-r--r--src/render/frontend/qrenderaspect_p.h4
-rw-r--r--src/render/frontend/qrenderplugin_p.h4
-rw-r--r--src/render/frontend/qrendersettings.cpp19
-rw-r--r--src/render/frontend/qrendersettings.h1
-rw-r--r--src/render/frontend/qrendersettings_p.h2
-rw-r--r--src/render/frontend/qrendertarget.cpp15
-rw-r--r--src/render/frontend/qrendertargetoutput.cpp1
-rw-r--r--src/render/frontend/render-frontend.pri1
-rw-r--r--src/render/geometry/armature.cpp33
-rw-r--r--src/render/geometry/armature_p.h4
-rw-r--r--src/render/geometry/attribute.cpp115
-rw-r--r--src/render/geometry/attribute_p.h4
-rw-r--r--src/render/geometry/buffer.cpp86
-rw-r--r--src/render/geometry/buffer_p.h3
-rw-r--r--src/render/geometry/buffermanager.cpp8
-rw-r--r--src/render/geometry/geometry.cpp58
-rw-r--r--src/render/geometry/geometry_p.h4
-rw-r--r--src/render/geometry/geometryrenderer.cpp144
-rw-r--r--src/render/geometry/geometryrenderer_p.h13
-rw-r--r--src/render/geometry/joint.cpp100
-rw-r--r--src/render/geometry/joint_p.h4
-rw-r--r--src/render/geometry/qattribute.cpp15
-rw-r--r--src/render/geometry/qbuffer.cpp16
-rw-r--r--src/render/geometry/qgeometry.cpp14
-rw-r--r--src/render/geometry/qgeometryrenderer.cpp23
-rw-r--r--src/render/geometry/qgeometryrenderer.h1
-rw-r--r--src/render/geometry/qmesh.cpp12
-rw-r--r--src/render/geometry/qmesh.h1
-rw-r--r--src/render/geometry/skeleton.cpp313
-rw-r--r--src/render/geometry/skeleton_p.h38
-rw-r--r--src/render/io/qsceneloader.cpp53
-rw-r--r--src/render/io/qsceneloader.h1
-rw-r--r--src/render/io/qsceneloader_p.h1
-rw-r--r--src/render/io/scene.cpp68
-rw-r--r--src/render/io/scene_p.h5
-rw-r--r--src/render/jobs/abstractpickingjob.cpp13
-rw-r--r--src/render/jobs/abstractpickingjob_p.h2
-rw-r--r--src/render/jobs/framecleanupjob.cpp1
-rw-r--r--src/render/jobs/genericlambdajob_p.h43
-rw-r--r--src/render/jobs/job_common_p.h4
-rw-r--r--src/render/jobs/jobs.pri4
-rw-r--r--src/render/jobs/loadgeometryjob.cpp35
-rw-r--r--src/render/jobs/loadgeometryjob_p.h4
-rw-r--r--src/render/jobs/loadscenejob.cpp58
-rw-r--r--src/render/jobs/loadscenejob_p.h23
-rw-r--r--src/render/jobs/loadskeletonjob.cpp247
-rw-r--r--src/render/jobs/loadskeletonjob_p.h22
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp127
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h9
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp14
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h1
-rw-r--r--src/render/jobs/raycastingjob.cpp41
-rw-r--r--src/render/jobs/raycastingjob_p.h4
-rw-r--r--src/render/jobs/updatelevelofdetailjob.cpp46
-rw-r--r--src/render/jobs/updatelevelofdetailjob_p.h3
-rw-r--r--src/render/jobs/updateworldtransformjob.cpp54
-rw-r--r--src/render/jobs/updateworldtransformjob_p.h2
-rw-r--r--src/render/lights/environmentlight.cpp14
-rw-r--r--src/render/lights/environmentlight_p.h3
-rw-r--r--src/render/lights/light.cpp17
-rw-r--r--src/render/lights/light_p.h4
-rw-r--r--src/render/lights/qdirectionallight.cpp1
-rw-r--r--src/render/lights/qspotlight.cpp1
-rw-r--r--src/render/materialsystem/effect.cpp57
-rw-r--r--src/render/materialsystem/effect_p.h4
-rw-r--r--src/render/materialsystem/filterkey.cpp29
-rw-r--r--src/render/materialsystem/filterkey_p.h4
-rw-r--r--src/render/materialsystem/material.cpp61
-rw-r--r--src/render/materialsystem/material_p.h4
-rw-r--r--src/render/materialsystem/materialsystem.pri5
-rw-r--r--src/render/materialsystem/parameter.cpp48
-rw-r--r--src/render/materialsystem/parameter_p.h6
-rw-r--r--src/render/materialsystem/qeffect.cpp33
-rw-r--r--src/render/materialsystem/qfilterkey.cpp1
-rw-r--r--src/render/materialsystem/qgraphicsapifilter.cpp5
-rw-r--r--src/render/materialsystem/qgraphicsapifilter_p.h1
-rw-r--r--src/render/materialsystem/qmaterial.cpp15
-rw-r--r--src/render/materialsystem/qparameter.cpp1
-rw-r--r--src/render/materialsystem/qrenderpass.cpp45
-rw-r--r--src/render/materialsystem/qshaderimage.cpp984
-rw-r--r--src/render/materialsystem/qshaderimage.h170
-rw-r--r--src/render/materialsystem/qshaderimage_p.h93
-rw-r--r--src/render/materialsystem/qshaderprogrambuilder.cpp108
-rw-r--r--src/render/materialsystem/qshaderprogrambuilder.h1
-rw-r--r--src/render/materialsystem/qshaderprogrambuilder_p.h6
-rw-r--r--src/render/materialsystem/qtechnique.cpp52
-rw-r--r--src/render/materialsystem/qtechnique.h1
-rw-r--r--src/render/materialsystem/renderpass.cpp71
-rw-r--r--src/render/materialsystem/renderpass_p.h4
-rw-r--r--src/render/materialsystem/shader.cpp94
-rw-r--r--src/render/materialsystem/shader_p.h11
-rw-r--r--src/render/materialsystem/shaderbuilder.cpp122
-rw-r--r--src/render/materialsystem/shaderbuilder_p.h40
-rw-r--r--src/render/materialsystem/shaderdata.cpp241
-rw-r--r--src/render/materialsystem/shaderdata_p.h31
-rw-r--r--src/render/materialsystem/shaderimage.cpp118
-rw-r--r--src/render/materialsystem/shaderimage_p.h (renamed from src/render/renderers/opengl/renderer/commandthread_p.h)84
-rw-r--r--src/render/materialsystem/technique.cpp92
-rw-r--r--src/render/materialsystem/technique_p.h4
-rw-r--r--src/render/picking/objectpicker.cpp101
-rw-r--r--src/render/picking/objectpicker_p.h10
-rw-r--r--src/render/picking/picking.pri1
-rw-r--r--src/render/picking/qabstractraycaster.cpp6
-rw-r--r--src/render/picking/qobjectpicker.cpp39
-rw-r--r--src/render/picking/qobjectpicker.h3
-rw-r--r--src/render/picking/qobjectpicker_p.h10
-rw-r--r--src/render/picking/qpickevent.cpp51
-rw-r--r--src/render/picking/qpickevent.h14
-rw-r--r--src/render/picking/qpickevent_p.h9
-rw-r--r--src/render/picking/qpicktriangleevent.cpp51
-rw-r--r--src/render/picking/qpicktriangleevent_p.h (renamed from src/render/jobs/updateentityhierarchyjob.cpp)47
-rw-r--r--src/render/picking/qraycaster.cpp5
-rw-r--r--src/render/picking/qscreenraycaster.cpp5
-rw-r--r--src/render/picking/raycaster.cpp112
-rw-r--r--src/render/picking/raycaster_p.h5
-rw-r--r--src/render/raycasting/qraycastingservice.cpp1
-rw-r--r--src/render/render.pro3
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp44
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h7
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp27
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h3
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp75
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h1
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp57
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h3
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp25
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h3
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp25
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h3
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp24
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h3
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp167
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h3
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h6
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri2
-rw-r--r--src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp306
-rw-r--r--src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h (renamed from src/render/jobs/loadtexturedatajob_p.h)51
-rw-r--r--src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp73
-rw-r--r--src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h2
-rw-r--r--src/render/renderers/opengl/jobs/renderviewjobutils.cpp25
-rw-r--r--src/render/renderers/opengl/opengl.pri3
-rw-r--r--src/render/renderers/opengl/renderer/commandthread.cpp205
-rw-r--r--src/render/renderers/opengl/renderer/rendercommand_p.h4
-rw-r--r--src/render/renderers/opengl/renderer/renderer.cpp483
-rw-r--r--src/render/renderers/opengl/renderer/renderer.pri4
-rw-r--r--src/render/renderers/opengl/renderer/renderer_p.h45
-rw-r--r--src/render/renderers/opengl/renderer/renderview.cpp184
-rw-r--r--src/render/renderers/opengl/renderer/shaderparameterpack.cpp17
-rw-r--r--src/render/renderers/opengl/renderer/shaderparameterpack_p.h42
-rw-r--r--src/render/renderers/opengl/textures/gltexture.cpp328
-rw-r--r--src/render/renderers/opengl/textures/gltexture_p.h90
-rw-r--r--src/render/renderers/opengl/textures/gltexturemanager_p.h17
-rw-r--r--src/render/renderstates/genericstate_p.h2
-rw-r--r--src/render/renderstates/qdepthrange.cpp156
-rw-r--r--src/render/renderstates/qdepthrange.h81
-rw-r--r--src/render/renderstates/qdepthrange_p.h (renamed from src/render/jobs/updateentityhierarchyjob_p.h)46
-rw-r--r--src/render/renderstates/qdithering.cpp1
-rw-r--r--src/render/renderstates/qmultisampleantialiasing.cpp1
-rw-r--r--src/render/renderstates/qnodepthmask.cpp1
-rw-r--r--src/render/renderstates/qrastermode.cpp195
-rw-r--r--src/render/renderstates/qrastermode.h96
-rw-r--r--src/render/renderstates/qrastermode_p.h84
-rw-r--r--src/render/renderstates/qseamlesscubemap.cpp1
-rw-r--r--src/render/renderstates/qstenciloperation.cpp14
-rw-r--r--src/render/renderstates/qstenciloperation_p.h1
-rw-r--r--src/render/renderstates/qstenciltest.cpp14
-rw-r--r--src/render/renderstates/qstenciltest_p.h1
-rw-r--r--src/render/renderstates/renderstatenode.cpp161
-rw-r--r--src/render/renderstates/renderstatenode_p.h4
-rw-r--r--src/render/renderstates/renderstates.cpp194
-rw-r--r--src/render/renderstates/renderstates.pri10
-rw-r--r--src/render/renderstates/renderstates_p.h46
-rw-r--r--src/render/renderstates/statemask_p.h2
-rw-r--r--src/render/renderstates/statevariant.cpp4
-rw-r--r--src/render/renderstates/statevariant_p.h1
-rw-r--r--src/render/services/vsyncframeadvanceservice.cpp11
-rw-r--r--src/render/texture/apitexturemanager_p.h411
-rw-r--r--src/render/texture/qabstracttexture.cpp103
-rw-r--r--src/render/texture/qabstracttexture.h9
-rw-r--r--src/render/texture/qabstracttexture_p.h8
-rw-r--r--src/render/texture/qabstracttextureimage.cpp14
-rw-r--r--src/render/texture/qabstracttextureimage_p.h2
-rw-r--r--src/render/texture/qtexture.cpp203
-rw-r--r--src/render/texture/qtexture_p.h4
-rw-r--r--src/render/texture/qtexturedataupdate.cpp186
-rw-r--r--src/render/texture/qtexturedataupdate.h105
-rw-r--r--src/render/texture/qtexturedataupdate_p.h79
-rw-r--r--src/render/texture/qtextureimage.cpp4
-rw-r--r--src/render/texture/qtextureimagedata.cpp27
-rw-r--r--src/render/texture/qtextureimagedata_p.h13
-rw-r--r--src/render/texture/texture.cpp244
-rw-r--r--src/render/texture/texture.pri7
-rw-r--r--src/render/texture/texture_p.h25
-rw-r--r--src/render/texture/texturedatamanager_p.h238
-rw-r--r--src/render/texture/textureimage.cpp76
-rw-r--r--src/render/texture/textureimage_p.h15
305 files changed, 8293 insertions, 5467 deletions
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index 273ab359a..b618eda55 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -68,7 +68,6 @@ class QScreen;
namespace Qt3DCore {
class QAbstractFrameAdvanceService;
-class QBackendNodeFactory;
class QEventFilterService;
class QAbstractAspectJobManager;
class QServiceLocator;
@@ -115,7 +114,6 @@ public:
JointDirty = 1 << 11,
LayersDirty = 1 << 12,
TechniquesDirty = 1 << 13,
- EntityHierarchyDirty= 1 << 14,
LightsDirty = 1 << 15,
AllDirty = 0xffffff
};
@@ -142,7 +140,7 @@ public:
// Threaded renderer
virtual void render() = 0;
// Synchronous renderer
- virtual void doRender(bool scene3dBlocking = false) = 0;
+ virtual void doRender(bool swapBuffers) = 0;
virtual void cleanGraphicsResources() = 0;
@@ -160,10 +158,10 @@ public:
virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0;
virtual Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() = 0;
virtual Qt3DCore::QAspectJobPtr rayCastingJob() = 0;
- virtual Qt3DCore::QAspectJobPtr syncTextureLoadingJob() = 0;
+ virtual Qt3DCore::QAspectJobPtr syncLoadingJobs() = 0;
virtual Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() = 0;
- virtual void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Entity *root) = 0;
+ virtual void setSceneRoot(Entity *root) = 0;
virtual Entity *sceneRoot() const = 0;
virtual FrameGraphNode *frameGraphRoot() const = 0;
diff --git a/src/render/backend/backendnode.cpp b/src/render/backend/backendnode.cpp
index 0dc8da237..642f6e44d 100644
--- a/src/render/backend/backendnode.cpp
+++ b/src/render/backend/backendnode.cpp
@@ -41,6 +41,7 @@
#include <private/renderer_p.h>
#include <private/resourceaccessor_p.h>
#include <private/nodemanagers_p.h>
+#include <Qt3DCore/private/qbackendnode_p.h>
QT_BEGIN_NAMESPACE
@@ -55,6 +56,12 @@ BackendNode::BackendNode(Mode mode)
{
}
+BackendNode::BackendNode(Qt3DCore::QBackendNodePrivate &dd)
+ : QBackendNode(dd)
+ , m_renderer(nullptr)
+{
+}
+
BackendNode::~BackendNode()
{
}
@@ -81,6 +88,13 @@ QSharedPointer<RenderBackendResourceAccessor> BackendNode::resourceAccessor()
return r->nodeManagers()->resourceAccessor();
}
+void BackendNode::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
+{
+ Q_UNUSED(firstTime);
+
+ d_ptr->setEnabled(frontEnd->isEnabled());
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/backendnode_p.h b/src/render/backend/backendnode_p.h
index f94033c1a..37f8305af 100644
--- a/src/render/backend/backendnode_p.h
+++ b/src/render/backend/backendnode_p.h
@@ -58,6 +58,12 @@
QT_BEGIN_NAMESPACE
+namespace Qt3DCore {
+
+class QBackendNodePrivate;
+
+}
+
namespace Qt3DRender {
namespace Render {
@@ -70,12 +76,15 @@ public:
BackendNode(Qt3DCore::QBackendNode::Mode mode = ReadOnly);
~BackendNode();
+ virtual void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime);
+
void setRenderer(AbstractRenderer *renderer);
AbstractRenderer *renderer() const;
QSharedPointer<RenderBackendResourceAccessor> resourceAccessor();
protected:
+ explicit BackendNode(Qt3DCore::QBackendNodePrivate &dd);
void markDirty(AbstractRenderer::BackendNodeDirtySet changes);
AbstractRenderer *m_renderer;
};
diff --git a/src/render/backend/cameralens.cpp b/src/render/backend/cameralens.cpp
index 42635bad7..85c5e9656 100644
--- a/src/render/backend/cameralens.cpp
+++ b/src/render/backend/cameralens.cpp
@@ -41,14 +41,12 @@
#include <Qt3DRender/qcameralens.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/managers_p.h>
-#include <Qt3DRender/private/qcameralens_p.h>
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DRender/private/computefilteredboundingvolumejob_p.h>
#include <Qt3DCore/qentity.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/qtransform.h>
QT_BEGIN_NAMESPACE
@@ -119,12 +117,43 @@ Matrix4x4 CameraLens::viewMatrix(const Matrix4x4 &worldTransform)
return Matrix4x4(m);
}
-void CameraLens::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void CameraLens::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QCameraLensData>>(change);
- const auto &data = typedChange->data;
- m_projection = Matrix4x4(data.projectionMatrix);
- m_exposure = data.exposure;
+ const QCameraLens *node = qobject_cast<const QCameraLens *>(frontEnd);
+ if (!node)
+ return;
+
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const Matrix4x4 projectionMatrix(node->projectionMatrix());
+ if (projectionMatrix != m_projection) {
+ m_projection = projectionMatrix;
+ markDirty(AbstractRenderer::AllDirty);
+ }
+
+ if (node->exposure() != m_exposure) {
+ m_exposure = node->exposure();
+ markDirty(AbstractRenderer::AllDirty);
+ }
+
+ const QCameraLensPrivate *d = static_cast<const QCameraLensPrivate *>(QNodePrivate::get(node));
+ if (d->m_pendingViewAllCommand != m_pendingViewAllCommand) {
+ m_pendingViewAllCommand = d->m_pendingViewAllCommand;
+
+ if (m_pendingViewAllCommand) {
+ const QVariant v = m_pendingViewAllCommand.data;
+ const QNodeCommand::CommandId commandId = m_pendingViewAllCommand.commandId;
+
+ if (m_pendingViewAllCommand.name == QLatin1String("QueryRootBoundingVolume")) {
+ const QNodeId id = v.value<QNodeId>();
+ computeSceneBoundingVolume({}, id, commandId);
+ } else if (m_pendingViewAllCommand.name == QLatin1String("QueryEntityBoundingVolume")) {
+ const QVector<QNodeId> ids = v.value<QVector<QNodeId>>();
+ if (ids.size() == 2)
+ computeSceneBoundingVolume(ids[0], ids[1], commandId);
+ }
+ }
+ }
}
void CameraLens::computeSceneBoundingVolume(QNodeId entityId,
@@ -152,15 +181,16 @@ void CameraLens::computeSceneBoundingVolume(QNodeId entityId,
void CameraLens::notifySceneBoundingVolume(const Sphere &sphere, QNodeCommand::CommandId commandId)
{
- if (m_pendingViewAllCommand != commandId)
+ if (!m_pendingViewAllCommand || m_pendingViewAllCommand.commandId != commandId)
return;
if (sphere.radius() > 0.f) {
QVector<float> data = { sphere.center().x(), sphere.center().y(), sphere.center().z(),
sphere.radius() };
QVariant v;
v.setValue(data);
- sendCommand(QLatin1Literal("ViewAll"), v, m_pendingViewAllCommand);
+ sendCommand(QLatin1String("ViewAll"), v, m_pendingViewAllCommand.commandId);
}
+ m_pendingViewAllCommand = {};
}
void CameraLens::setProjection(const Matrix4x4 &projection)
@@ -173,47 +203,6 @@ void CameraLens::setExposure(float exposure)
m_exposure = exposure;
}
-void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyUpdated: {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
-
- if (propertyChange->propertyName() == QByteArrayLiteral("projectionMatrix")) {
- QMatrix4x4 projectionMatrix = propertyChange->value().value<QMatrix4x4>();
- m_projection = Matrix4x4(projectionMatrix);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("exposure")) {
- setExposure(propertyChange->value().toFloat());
- }
-
- markDirty(AbstractRenderer::AllDirty);
- }
- break;
-
- case CommandRequested: {
- QNodeCommandPtr command = qSharedPointerCast<QNodeCommand>(e);
-
- if (command->name() == QLatin1Literal("QueryRootBoundingVolume")) {
- m_pendingViewAllCommand = command->commandId();
- QVariant v = command->data();
- QNodeId id = v.value<QNodeId>();
- computeSceneBoundingVolume({}, id, command->commandId());
- } else if (command->name() == QLatin1Literal("QueryEntityBoundingVolume")) {
- m_pendingViewAllCommand = command->commandId();
- QVariant v = command->data();
- QVector<QNodeId> ids = v.value<QVector<QNodeId>>();
- if (ids.size() == 2)
- computeSceneBoundingVolume(ids[0], ids[1], command->commandId());
- }
- }
- break;
-
- default:
- break;
- }
- BackendNode::sceneChangeEvent(e);
-}
-
bool CameraLens::viewMatrixForCamera(EntityManager* manager, Qt3DCore::QNodeId cameraId,
Matrix4x4 &viewMatrix, Matrix4x4 &projectionMatrix)
{
diff --git a/src/render/backend/cameralens_p.h b/src/render/backend/cameralens_p.h
index 80a1715cf..bd721d5e9 100644
--- a/src/render/backend/cameralens_p.h
+++ b/src/render/backend/cameralens_p.h
@@ -54,6 +54,7 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DCore/private/qnodecommand_p.h>
#include <Qt3DCore/private/matrix4x4_p.h>
+#include <Qt3DRender/private/qcameralens_p.h>
#include <QRectF>
QT_BEGIN_NAMESPACE
@@ -96,21 +97,20 @@ public:
void setExposure(float exposure);
inline float exposure() const { return m_exposure; }
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
void notifySceneBoundingVolume(const Sphere &sphere, Qt3DCore::QNodeCommand::CommandId commandId);
static bool viewMatrixForCamera(EntityManager *manager, Qt3DCore::QNodeId cameraId,
Matrix4x4 &viewMatrix, Matrix4x4 &projectionMatrix);
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
void computeSceneBoundingVolume(Qt3DCore::QNodeId entityId,
Qt3DCore::QNodeId cameraId,
Qt3DCore::QNodeCommand::CommandId commandId);
QRenderAspect *m_renderAspect;
- Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand;
+ CameraLensCommand m_pendingViewAllCommand;
Matrix4x4 m_projection;
float m_exposure;
};
diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp
index 182ba89d1..8bccb1437 100644
--- a/src/render/backend/commandexecuter.cpp
+++ b/src/render/backend/commandexecuter.cpp
@@ -261,11 +261,11 @@ QJsonObject parameterPackToJson(const Render::ShaderParameterPack &pack)
obj.insert(QLatin1String("uniforms"), uniformsArray);
QJsonArray texturesArray;
- const QVector<Render::ShaderParameterPack::NamedTexture> &textures = pack.textures();
+ const QVector<Render::ShaderParameterPack::NamedResource> &textures = pack.textures();
for (const auto & texture : textures) {
QJsonObject textureObj;
textureObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(texture.glslNameId));
- textureObj.insert(QLatin1String("id"), qint64(texture.texId.id()));
+ textureObj.insert(QLatin1String("id"), qint64(texture.nodeId.id()));
texturesArray.push_back(textureObj);
}
obj.insert(QLatin1String("textures"), texturesArray);
diff --git a/src/render/backend/computecommand.cpp b/src/render/backend/computecommand.cpp
index 349941965..df79dcbe8 100644
--- a/src/render/backend/computecommand.cpp
+++ b/src/render/backend/computecommand.cpp
@@ -73,36 +73,38 @@ void ComputeCommand::cleanup()
m_runType = QComputeCommand::Continuous;
}
-void ComputeCommand::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void ComputeCommand::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QComputeCommandData>>(change);
- const auto &data = typedChange->data;
- m_workGroups[0] = data.workGroupX;
- m_workGroups[1] = data.workGroupY;
- m_workGroups[2] = data.workGroupZ;
- m_runType = data.runType;
- m_frameCount = data.frameCount;
- if (m_renderer != nullptr)
- BackendNode::markDirty(AbstractRenderer::ComputeDirty);
-}
+ const QComputeCommand *node = qobject_cast<const QComputeCommand *>(frontEnd);
+ if (!node)
+ return;
-void ComputeCommand::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (e->type() == Qt3DCore::PropertyUpdated) {
- if (propertyChange->propertyName() == QByteArrayLiteral("workGroupX"))
- m_workGroups[0] = propertyChange->value().toInt();
- else if (propertyChange->propertyName() == QByteArrayLiteral("workGroupY"))
- m_workGroups[1] = propertyChange->value().toInt();
- else if (propertyChange->propertyName() == QByteArrayLiteral("workGroupZ"))
- m_workGroups[2] = propertyChange->value().toInt();
- else if (propertyChange->propertyName() == QByteArrayLiteral("frameCount"))
- m_frameCount = propertyChange->value().toInt();
- else if (propertyChange->propertyName() == QByteArrayLiteral("runType"))
- m_runType = static_cast<QComputeCommand::RunType>(propertyChange->value().toInt());
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (m_workGroups[0] != node->workGroupX()) {
+ m_workGroups[0] = node->workGroupX();
+ markDirty(AbstractRenderer::ComputeDirty);
+ }
+ if (m_workGroups[1] != node->workGroupY()) {
+ m_workGroups[1] = node->workGroupY();
+ markDirty(AbstractRenderer::ComputeDirty);
+ }
+ if (m_workGroups[2] != node->workGroupZ()) {
+ m_workGroups[2] = node->workGroupZ();
markDirty(AbstractRenderer::ComputeDirty);
}
- BackendNode::sceneChangeEvent(e);
+ if (node->runType() != m_runType) {
+ m_runType = node->runType();
+ markDirty(AbstractRenderer::ComputeDirty);
+ }
+ const QComputeCommandPrivate *d = static_cast<const QComputeCommandPrivate *>(Qt3DCore::QNodePrivate::get(node));
+ if (d->m_frameCount != m_frameCount) {
+ m_frameCount = d->m_frameCount;
+ markDirty(AbstractRenderer::ComputeDirty);
+ }
+
+ if (firstTime)
+ markDirty(AbstractRenderer::ComputeDirty);
}
// Called from buildComputeRenderCommands in a job
diff --git a/src/render/backend/computecommand_p.h b/src/render/backend/computecommand_p.h
index 10e10fd25..dc2069928 100644
--- a/src/render/backend/computecommand_p.h
+++ b/src/render/backend/computecommand_p.h
@@ -69,7 +69,7 @@ public:
~ComputeCommand();
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
inline int x() const Q_DECL_NOTHROW { return m_workGroups[0]; }
inline int y() const Q_DECL_NOTHROW { return m_workGroups[1]; }
@@ -81,7 +81,6 @@ public:
void updateFrameCount();
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) override;
int m_workGroups[3];
int m_frameCount;
QComputeCommand::RunType m_runType;
diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp
index bf128b508..682dc000e 100644
--- a/src/render/backend/entity.cpp
+++ b/src/render/backend/entity.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "entity_p.h"
+#include "entity_p_p.h"
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/qabstractlight.h>
@@ -59,10 +60,7 @@
#include <Qt3DRender/qcameralens.h>
#include <Qt3DCore/qarmature.h>
-#include <Qt3DCore/qcomponentaddedchange.h>
-#include <Qt3DCore/qcomponentremovedchange.h>
#include <Qt3DCore/qentity.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/private/qentity_p.h>
#include <Qt3DCore/qnodecreatedchange.h>
@@ -77,8 +75,33 @@ using namespace Qt3DCore;
namespace Qt3DRender {
namespace Render {
+
+EntityPrivate::EntityPrivate()
+ : Qt3DCore::QBackendNodePrivate(Entity::ReadOnly)
+{
+}
+
+EntityPrivate *EntityPrivate::get(Entity *node)
+{
+ return node->d_func();
+}
+
+void EntityPrivate::componentAdded(Qt3DCore::QNode *frontend)
+{
+ Q_Q(Entity);
+ const auto componentIdAndType = QNodeIdTypePair(frontend->id(), QNodePrivate::findStaticMetaObject(frontend->metaObject()));
+ q->addComponent(componentIdAndType);
+}
+
+void EntityPrivate::componentRemoved(Qt3DCore::QNode *frontend)
+{
+ Q_Q(Entity);
+ q->removeComponent(frontend->id());
+}
+
+
Entity::Entity()
- : BackendNode()
+ : BackendNode(*new EntityPrivate)
, m_nodeManagers(nullptr)
, m_boundingDirty(false)
, m_treeEnabled(true)
@@ -95,11 +118,19 @@ void Entity::cleanup()
if (m_nodeManagers != nullptr) {
m_nodeManagers->worldMatrixManager()->releaseResource(peerId());
qCDebug(Render::RenderNodes) << Q_FUNC_INFO;
+
+ removeFromParentChildHandles();
+
+ for (auto &childHandle : qAsConst(m_childrenHandles)) {
+ auto child = m_nodeManagers->renderNodesManager()->data(childHandle);
+ // children should always exist and have this as parent
+ // if they were destroyed, they would have removed themselves from our m_childrenHandles
+ Q_ASSERT(child);
+ Q_ASSERT(child->m_parentHandle == m_handle);
+ child->m_parentHandle = {};
+ }
}
- if (!m_parentEntityId.isNull())
- markDirty(AbstractRenderer::EntityHierarchyDirty);
- m_parentEntityId = Qt3DCore::QNodeId();
m_worldTransform = HMatrix();
// Release all component will have to perform their own release when they receive the
// NodeDeleted notification
@@ -122,6 +153,7 @@ void Entity::cleanup()
m_localBoundingVolume.reset();
m_worldBoundingVolume.reset();
m_worldBoundingVolumeWithChildren.reset();
+ m_parentHandle = {};
m_boundingDirty = false;
QBackendNode::setEnabled(false);
}
@@ -129,6 +161,12 @@ void Entity::cleanup()
void Entity::setParentHandle(HEntity parentHandle)
{
Q_ASSERT(m_nodeManagers);
+
+ if (parentHandle == m_parentHandle)
+ return;
+
+ removeFromParentChildHandles();
+
m_parentHandle = parentHandle;
auto parent = m_nodeManagers->renderNodesManager()->data(parentHandle);
if (parent != nullptr && !parent->m_childrenHandles.contains(m_handle))
@@ -145,89 +183,60 @@ void Entity::setHandle(HEntity handle)
m_handle = handle;
}
-void Entity::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
+void Entity::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<QNodeCreatedChange<Qt3DCore::QEntityData>>(change);
- const auto &data = typedChange->data;
-
- // Note this is *not* the parentId as that is the ID of the parent QNode, which is not
- // necessarily the same as the parent QEntity (which may be further up the tree).
- m_parentEntityId = data.parentEntityId;
- qCDebug(Render::RenderNodes) << "Creating Entity id =" << peerId() << "parentId =" << m_parentEntityId;
-
- // TODO: Store string id instead and only in debug mode
- //m_objectName = peer->objectName();
- m_worldTransform = m_nodeManagers->worldMatrixManager()->getOrAcquireHandle(peerId());
-
- // TODO: Suboptimal -> Maybe have a Hash<QComponent, QEntityList> instead
- m_transformComponent = QNodeId();
- m_materialComponent = QNodeId();
- m_cameraComponent = QNodeId();
- m_geometryRendererComponent = QNodeId();
- m_objectPickerComponent = QNodeId();
- m_boundingVolumeDebugComponent = QNodeId();
- m_computeComponent = QNodeId();
- m_layerComponents.clear();
- m_levelOfDetailComponents.clear();
- m_rayCasterComponents.clear();
- m_shaderDataComponents.clear();
- m_lightComponents.clear();
- m_environmentLightComponents.clear();
- m_localBoundingVolume = QSharedPointer<Sphere>::create(peerId());
- m_worldBoundingVolume = QSharedPointer<Sphere>::create(peerId());
- m_worldBoundingVolumeWithChildren = QSharedPointer<Sphere>::create(peerId());
+ const Qt3DCore::QEntity *node = qobject_cast<const Qt3DCore::QEntity *>(frontEnd);
+ if (!node)
+ return;
- for (const auto &idAndType : qAsConst(data.componentIdsAndTypes))
- addComponent(idAndType);
+ if (this->isEnabled() != node->isEnabled()) {
+ markDirty(AbstractRenderer::EntityEnabledDirty);
+ // We let QBackendNode::syncFromFrontEnd change the enabled property
+ }
- markDirty(AbstractRenderer::EntityHierarchyDirty);
-}
+ const auto parentID = node->parentEntity() ? node->parentEntity()->id() : Qt3DCore::QNodeId();
+ auto parentHandle = m_nodeManagers->renderNodesManager()->lookupHandle(parentID);
-void Entity::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
+ // All entity creation is done from top-down and always during the same frame, so
+ // we if we have a valid parent node, we should always be able to resolve the
+ // backend parent at this time
+ Q_ASSERT(!node->parentEntity() || (!parentHandle.isNull() && m_nodeManagers->renderNodesManager()->data(parentHandle)));
- case ComponentAdded: {
- QComponentAddedChangePtr change = qSharedPointerCast<QComponentAddedChange>(e);
- const auto componentIdAndType = QNodeIdTypePair(change->componentId(), change->componentMetaObject());
- addComponent(componentIdAndType);
- qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "Component Added. Id =" << change->componentId();
+ if (parentHandle != m_parentHandle) {
markDirty(AbstractRenderer::AllDirty);
- break;
}
- case ComponentRemoved: {
- QComponentRemovedChangePtr change = qSharedPointerCast<QComponentRemovedChange>(e);
- removeComponent(change->componentId());
- qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "Component Removed. Id =" << change->componentId();
- markDirty(AbstractRenderer::AllDirty);
- break;
- }
+ setParentHandle(parentHandle);
- case PropertyUpdated: {
- QPropertyUpdatedChangePtr change = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("enabled")) {
- // We only mark as dirty the renderer
- markDirty(AbstractRenderer::EntityEnabledDirty);
- // We let QBackendNode::sceneChangeEvent change the enabled property
- } else if (change->propertyName() == QByteArrayLiteral("parentEntityUpdated")) {
- auto newParent = change->value().value<Qt3DCore::QNodeId>();
- qCDebug(Render::RenderNodes) << "Setting parent for " << peerId() << ", new parentId =" << newParent;
- if (m_parentEntityId != newParent) {
- m_parentEntityId = newParent;
- // TODO: change to EventHierarchyDirty and update renderer to
- // ensure all jobs are run that depend on Entity hierarchy.
- markDirty(AbstractRenderer::AllDirty);
- }
- }
+ if (firstTime) {
+ m_worldTransform = m_nodeManagers->worldMatrixManager()->getOrAcquireHandle(peerId());
- break;
+ // TODO: Suboptimal -> Maybe have a Hash<QComponent, QEntityList> instead
+ m_transformComponent = QNodeId();
+ m_materialComponent = QNodeId();
+ m_cameraComponent = QNodeId();
+ m_geometryRendererComponent = QNodeId();
+ m_objectPickerComponent = QNodeId();
+ m_boundingVolumeDebugComponent = QNodeId();
+ m_computeComponent = QNodeId();
+ m_layerComponents.clear();
+ m_levelOfDetailComponents.clear();
+ m_rayCasterComponents.clear();
+ m_shaderDataComponents.clear();
+ m_lightComponents.clear();
+ m_environmentLightComponents.clear();
+ m_localBoundingVolume = QSharedPointer<Sphere>::create(peerId());
+ m_worldBoundingVolume = QSharedPointer<Sphere>::create(peerId());
+ m_worldBoundingVolumeWithChildren = QSharedPointer<Sphere>::create(peerId());
+
+ const QComponentVector &components = node->components();
+ for (QComponent *c : components) {
+ const auto idAndType = QNodeIdTypePair(c->id(), QNodePrivate::findStaticMetaObject(c->metaObject()));
+ addComponent(idAndType);
+ }
}
- default:
- break;
- }
- BackendNode::sceneChangeEvent(e);
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
}
void Entity::dump() const
@@ -246,35 +255,12 @@ Entity *Entity::parent() const
return m_nodeManagers->renderNodesManager()->data(m_parentHandle);
}
-
-// clearEntityHierarchy and rebuildEntityHierarchy should only be called
-// from UpdateEntityHierarchyJob to update the entity hierarchy for the
-// entire scene at once
-void Entity::clearEntityHierarchy()
+void Entity::removeFromParentChildHandles()
{
- m_childrenHandles.clear();
- m_parentHandle = HEntity();
-}
-
-// clearEntityHierarchy and rebuildEntityHierarchy should only be called
-// from UpdateEntityHierarchyJob to update the entity hierarchy for the
-// entire scene at once
-void Entity::rebuildEntityHierarchy()
-{
- if (!m_parentEntityId.isNull())
- setParentHandle(m_nodeManagers->renderNodesManager()->lookupHandle(m_parentEntityId));
- else
- qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "No parent entity found for Entity" << peerId();
-}
-
-void Entity::appendChildHandle(HEntity childHandle)
-{
- if (!m_childrenHandles.contains(childHandle)) {
- m_childrenHandles.append(childHandle);
- Entity *child = m_nodeManagers->renderNodesManager()->data(childHandle);
- if (child != nullptr)
- child->m_parentHandle = m_handle;
- }
+ // remove ourself from our parent's list of children.
+ auto p = parent();
+ if (p)
+ p->removeChildHandle(m_handle);
}
QVector<Entity *> Entity::children() const
@@ -358,6 +344,7 @@ void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
} else if (type->inherits(&QArmature::staticMetaObject)) {
m_armatureComponent = id;
}
+ markDirty(AbstractRenderer::AllDirty);
}
void Entity::removeComponent(Qt3DCore::QNodeId nodeId)
@@ -392,6 +379,7 @@ void Entity::removeComponent(Qt3DCore::QNodeId nodeId)
} else if (m_armatureComponent == nodeId) {
m_armatureComponent = QNodeId();
}
+ markDirty(AbstractRenderer::AllDirty);
}
bool Entity::isBoundingVolumeDirty() const
diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h
index b4c9541f2..d13d96784 100644
--- a/src/render/backend/entity_p.h
+++ b/src/render/backend/entity_p.h
@@ -79,6 +79,7 @@ namespace Render {
class Sphere;
class Renderer;
class NodeManagers;
+class EntityPrivate;
class Q_AUTOTEST_EXPORT Entity : public BackendNode
{
@@ -89,7 +90,7 @@ public:
void setParentHandle(HEntity parentHandle);
void setNodeManagers(NodeManagers *manager);
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
void dump() const;
@@ -97,11 +98,8 @@ public:
HEntity handle() const { return m_handle; }
Entity *parent() const;
HEntity parentHandle() const { return m_parentHandle; }
- Qt3DCore::QNodeId parentEntityId() const { return m_parentEntityId; }
-
- void clearEntityHierarchy();
- void rebuildEntityHierarchy();
+ void removeFromParentChildHandles();
void appendChildHandle(HEntity childHandle);
void removeChildHandle(HEntity childHandle) { m_childrenHandles.removeOne(childHandle); }
QVector<HEntity> childrenHandles() const { return m_childrenHandles; }
@@ -178,17 +176,15 @@ public:
return containsComponentsOfType<T>() && containsComponentsOfType<Ts, Ts2...>();
}
+protected:
+ Q_DECLARE_PRIVATE(Entity)
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
NodeManagers *m_nodeManagers;
HEntity m_handle;
HEntity m_parentHandle;
QVector<HEntity > m_childrenHandles;
- Qt3DCore::QNodeId m_parentEntityId;
-
HMatrix m_worldTransform;
QSharedPointer<Sphere> m_localBoundingVolume;
QSharedPointer<Sphere> m_worldBoundingVolume;
@@ -306,7 +302,7 @@ ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(ShaderData, HShaderData)
ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(Light, HLight)
ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(EnvironmentLight, HEnvironmentLight)
-class RenderEntityFunctor : public Qt3DCore::QBackendNodeMapper
+class Q_AUTOTEST_EXPORT RenderEntityFunctor : public Qt3DCore::QBackendNodeMapper
{
public:
explicit RenderEntityFunctor(AbstractRenderer *renderer, NodeManagers *manager);
diff --git a/src/render/backend/entity_p_p.h b/src/render/backend/entity_p_p.h
new file mode 100644
index 000000000..4ac6ab978
--- /dev/null
+++ b/src/render/backend/entity_p_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+** 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_ENTITY_P_P_H
+#define QT3DRENDER_RENDER_ENTITY_P_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/entity_p.h>
+#include <Qt3DCore/private/qbackendnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QNode;
+}
+
+namespace Qt3DRender {
+
+class QRenderAspect;
+
+namespace Render {
+
+class Q_AUTOTEST_EXPORT EntityPrivate : public Qt3DCore::QBackendNodePrivate {
+public:
+ EntityPrivate();
+
+ Q_DECLARE_PUBLIC(Entity)
+
+ static EntityPrivate *get(Entity *node);
+
+ void componentAdded(Qt3DCore::QNode *frontend) override;
+ void componentRemoved(Qt3DCore::QNode *frontend) override;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_ENTITY_P_P_H
diff --git a/src/render/backend/handle_types_p.h b/src/render/backend/handle_types_p.h
index 035bbfc91..195fc2cc6 100644
--- a/src/render/backend/handle_types_p.h
+++ b/src/render/backend/handle_types_p.h
@@ -94,10 +94,12 @@ class Light;
class EnvironmentLight;
class ComputeCommand;
class GLBuffer;
+class GLTexture;
class RenderStateNode;
class Armature;
class Skeleton;
class Joint;
+class ShaderImage;
typedef Qt3DCore::QHandle<RenderTargetOutput> HAttachment;
typedef Qt3DCore::QHandle<CameraLens> HCamera;
@@ -132,10 +134,12 @@ typedef Qt3DCore::QHandle<Light> HLight;
typedef Qt3DCore::QHandle<EnvironmentLight> HEnvironmentLight;
typedef Qt3DCore::QHandle<ComputeCommand> HComputeCommand;
typedef Qt3DCore::QHandle<GLBuffer> HGLBuffer;
+typedef Qt3DCore::QHandle<GLTexture> HGLTexture;
typedef Qt3DCore::QHandle<RenderStateNode> HRenderState;
typedef Qt3DCore::QHandle<Armature> HArmature;
typedef Qt3DCore::QHandle<Skeleton> HSkeleton;
typedef Qt3DCore::QHandle<Joint> HJoint;
+typedef Qt3DCore::QHandle<ShaderImage> HShaderImage;
} // namespace Render
diff --git a/src/render/backend/layer.cpp b/src/render/backend/layer.cpp
index 976c35fd5..f1b6d2fc6 100644
--- a/src/render/backend/layer.cpp
+++ b/src/render/backend/layer.cpp
@@ -41,7 +41,6 @@
#include <Qt3DRender/qlayer.h>
#include <Qt3DRender/private/qlayer_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <QVariant>
QT_BEGIN_NAMESPACE
@@ -67,26 +66,22 @@ void Layer::cleanup()
QBackendNode::setEnabled(false);
}
-void Layer::sceneChangeEvent(const QSceneChangePtr &e)
+void Layer::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- QByteArray propertyName = propertyChange->propertyName();
- if (propertyName == QByteArrayLiteral("recursive")) {
- m_recursive = propertyChange->value().toBool();
- markDirty(AbstractRenderer::LayersDirty);
- }
- if (propertyName == QByteArrayLiteral("enabled"))
- markDirty(AbstractRenderer::LayersDirty);
- }
- BackendNode::sceneChangeEvent(e);
-}
+ const QLayer *node = qobject_cast<const QLayer *>(frontEnd);
+ if (!node)
+ return;
-void Layer::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
-{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QLayerData>>(change);
- const auto &data = typedChange->data;
- m_recursive = data.m_recursive;
+ const bool oldEnabled = isEnabled();
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (isEnabled() != oldEnabled || firstTime)
+ markDirty(AbstractRenderer::LayersDirty);
+
+ if (node->recursive() != m_recursive) {
+ m_recursive = node->recursive();
+ markDirty(AbstractRenderer::LayersDirty);
+ }
}
bool Layer::recursive() const
diff --git a/src/render/backend/layer_p.h b/src/render/backend/layer_p.h
index 1513157f9..8631e2d92 100644
--- a/src/render/backend/layer_p.h
+++ b/src/render/backend/layer_p.h
@@ -76,11 +76,9 @@ public:
bool recursive() const;
void setRecursive(bool recursive);
-protected:
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) override;
bool m_recursive;
};
diff --git a/src/render/backend/levelofdetail.cpp b/src/render/backend/levelofdetail.cpp
index 157bfc004..7f528a9d5 100644
--- a/src/render/backend/levelofdetail.cpp
+++ b/src/render/backend/levelofdetail.cpp
@@ -41,7 +41,7 @@
#include <Qt3DRender/QLevelOfDetail>
#include <Qt3DRender/private/qlevelofdetail_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DRender/QCamera>
#include <QVariant>
QT_BEGIN_NAMESPACE
@@ -64,53 +64,54 @@ LevelOfDetail::~LevelOfDetail()
cleanup();
}
-void LevelOfDetail::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
+void LevelOfDetail::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QLevelOfDetailData>>(change);
- const auto &data = typedChange->data;
- m_camera = data.camera;
- m_currentIndex = data.currentIndex;
- m_thresholdType = data.thresholdType;
- m_thresholds = data.thresholds;
- m_volumeOverride = data.volumeOverride;
-}
+ const QLevelOfDetail *node = qobject_cast<const QLevelOfDetail *>(frontEnd);
+ if (!node)
+ return;
-void LevelOfDetail::cleanup()
-{
- QBackendNode::setEnabled(false);
-}
+ const bool oldEnabled = isEnabled();
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
-void LevelOfDetail::sceneChangeEvent(const QSceneChangePtr &e)
-{
- if (e->type() == PropertyUpdated) {
- const QPropertyUpdatedChangePtr &propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("currentIndex"))
- m_currentIndex = propertyChange->value().value<int>();
- else if (propertyChange->propertyName() == QByteArrayLiteral("camera"))
- m_camera = propertyChange->value().value<Qt3DCore::QNodeId>();
- else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType"))
- m_thresholdType = propertyChange->value().value<QLevelOfDetail::ThresholdType>();
- else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds"))
- m_thresholds = propertyChange->value().value<QVector<qreal>>();
- else if (propertyChange->propertyName() == QByteArrayLiteral("volumeOverride"))
- m_volumeOverride = propertyChange->value().value<Qt3DRender::QLevelOfDetailBoundingSphere>();
+ const Qt3DCore::QNodeId cameraId = Qt3DCore::qIdForNode(node->camera());
+ if (cameraId != m_camera) {
+ m_camera = cameraId;
+ markDirty(AbstractRenderer::GeometryDirty);
}
- markDirty(AbstractRenderer::GeometryDirty);
+ if (node->currentIndex() != m_currentIndex) {
+ m_currentIndex = node->currentIndex();
+ markDirty(AbstractRenderer::GeometryDirty);
+ }
- BackendNode::sceneChangeEvent(e);
+ if (node->thresholdType() != m_thresholdType) {
+ m_thresholdType = node->thresholdType();
+ markDirty(AbstractRenderer::GeometryDirty);
+ }
+
+ if (node->thresholds() != m_thresholds) {
+ m_thresholds = node->thresholds();
+ markDirty(AbstractRenderer::GeometryDirty);
+ }
+
+ if (node->volumeOverride() != m_volumeOverride) {
+ m_volumeOverride = node->volumeOverride();
+ markDirty(AbstractRenderer::GeometryDirty);
+ }
+
+ if (isEnabled() != oldEnabled || firstTime)
+ markDirty(AbstractRenderer::LayersDirty);
+}
+
+void LevelOfDetail::cleanup()
+{
+ QBackendNode::setEnabled(false);
}
void LevelOfDetail::setCurrentIndex(int currentIndex)
{
- if (m_currentIndex != currentIndex) {
+ if (m_currentIndex != currentIndex)
m_currentIndex = currentIndex;
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("currentIndex");
- e->setValue(m_currentIndex);
- notifyObservers(e);
- }
}
} // namespace Render
diff --git a/src/render/backend/levelofdetail_p.h b/src/render/backend/levelofdetail_p.h
index 4cf835d9b..8399e19b7 100644
--- a/src/render/backend/levelofdetail_p.h
+++ b/src/render/backend/levelofdetail_p.h
@@ -73,7 +73,7 @@ public:
LevelOfDetail();
~LevelOfDetail();
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) final;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
Qt3DCore::QNodeId camera() const { return m_camera; }
int currentIndex() const { return m_currentIndex; }
@@ -86,7 +86,6 @@ public:
void setCurrentIndex(int currentIndex);
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
Qt3DCore::QNodeId m_camera;
int m_currentIndex;
QLevelOfDetail::ThresholdType m_thresholdType;
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index f28dbe768..759c16f64 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -86,6 +86,7 @@
#include <Qt3DRender/private/armature_p.h>
#include <Qt3DRender/private/skeleton_p.h>
#include <Qt3DRender/private/joint_p.h>
+#include <Qt3DRender/private/shaderimage_p.h>
QT_BEGIN_NAMESPACE
@@ -302,6 +303,15 @@ public:
ParameterManager() {}
};
+class ShaderImageManager : public Qt3DCore::QResourceManager<
+ ShaderImage,
+ Qt3DCore::QNodeId,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ ShaderImageManager() {}
+};
+
class ShaderDataManager : public Qt3DCore::QResourceManager<
ShaderData,
Qt3DCore::QNodeId,
@@ -466,6 +476,7 @@ Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Armature, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Skeleton, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Joint, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::ShaderBuilder, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::ShaderImage, Q_REQUIRES_CLEANUP)
QT_END_NAMESPACE
diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp
index 584ddd65c..5e452f886 100644
--- a/src/render/backend/nodemanagers.cpp
+++ b/src/render/backend/nodemanagers.cpp
@@ -43,7 +43,6 @@
#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>
#include <Qt3DRender/private/techniquemanager_p.h>
#include <Qt3DRender/private/armature_p.h>
@@ -71,9 +70,7 @@ NodeManagers::NodeManagers()
, 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_glTextureManager(new GLTextureManager())
, m_layerManager(new LayerManager())
, m_levelOfDetailManager(new LevelOfDetailManager())
, m_filterKeyManager(new FilterKeyManager())
@@ -100,6 +97,7 @@ NodeManagers::NodeManagers()
, m_armatureManager(new ArmatureManager())
, m_skeletonManager(new SkeletonManager())
, m_jointManager(new JointManager())
+ , m_shaderImageManager(new ShaderImageManager())
, m_resourceAccessor(new ResourceAccessor(this))
{
}
@@ -117,8 +115,6 @@ NodeManagers::~NodeManagers()
delete m_renderPassManager;
delete m_glTextureManager;
delete m_textureManager;
- delete m_textureDataManager;
- delete m_textureImageDataManager;
delete m_layerManager;
delete m_levelOfDetailManager;
delete m_filterKeyManager;
@@ -150,6 +146,7 @@ NodeManagers::~NodeManagers()
delete m_armatureManager;
delete m_skeletonManager;
delete m_jointManager;
+ delete m_shaderImageManager;
}
QSharedPointer<ResourceAccessor> NodeManagers::resourceAccessor()
@@ -158,233 +155,233 @@ QSharedPointer<ResourceAccessor> NodeManagers::resourceAccessor()
}
template<>
-CameraManager *NodeManagers::manager<CameraLens>() const Q_DECL_NOTHROW
+CameraManager *NodeManagers::manager<CameraLens>() const noexcept
{
return m_cameraManager;
}
template<>
-EntityManager *NodeManagers::manager<Entity>() const Q_DECL_NOTHROW
+EntityManager *NodeManagers::manager<Entity>() const noexcept
{
return m_renderNodesManager;
}
template<>
-MaterialManager *NodeManagers::manager<Material>() const Q_DECL_NOTHROW
+MaterialManager *NodeManagers::manager<Material>() const noexcept
{
return m_materialManager;
}
template<>
-MatrixManager *NodeManagers::manager<Matrix4x4>() const Q_DECL_NOTHROW
+MatrixManager *NodeManagers::manager<Matrix4x4>() const noexcept
{
return m_worldMatrixManager;
}
template<>
-VAOManager *NodeManagers::manager<OpenGLVertexArrayObject>() const Q_DECL_NOTHROW
+VAOManager *NodeManagers::manager<OpenGLVertexArrayObject>() const noexcept
{
return m_vaoManager;
}
template<>
-ShaderManager *NodeManagers::manager<Shader>() const Q_DECL_NOTHROW
+ShaderManager *NodeManagers::manager<Shader>() const noexcept
{
return m_shaderManager;
}
template<>
-ShaderBuilderManager *NodeManagers::manager<ShaderBuilder>() const Q_DECL_NOTHROW
+ShaderBuilderManager *NodeManagers::manager<ShaderBuilder>() const noexcept
{
return m_shaderBuilderManager;
}
template<>
-TechniqueManager *NodeManagers::manager<Technique>() const Q_DECL_NOTHROW
+TechniqueManager *NodeManagers::manager<Technique>() const noexcept
{
return m_techniqueManager;
}
template<>
-EffectManager *NodeManagers::manager<Effect>() const Q_DECL_NOTHROW
+EffectManager *NodeManagers::manager<Effect>() const noexcept
{
return m_effectManager;
}
template<>
-RenderPassManager *NodeManagers::manager<RenderPass>() const Q_DECL_NOTHROW
+RenderPassManager *NodeManagers::manager<RenderPass>() const noexcept
{
return m_renderPassManager;
}
template<>
-TextureManager *NodeManagers::manager<Texture>() const Q_DECL_NOTHROW
+TextureManager *NodeManagers::manager<Texture>() const noexcept
{
return m_textureManager;
}
template<>
-TextureDataManager *NodeManagers::manager<QTextureImageData>() const Q_DECL_NOTHROW
-{
- return m_textureDataManager;
-}
-
-template<>
-LayerManager *NodeManagers::manager<Layer>() const Q_DECL_NOTHROW
+LayerManager *NodeManagers::manager<Layer>() const noexcept
{
return m_layerManager;
}
template<>
-LevelOfDetailManager *NodeManagers::manager<LevelOfDetail>() const Q_DECL_NOTHROW
+LevelOfDetailManager *NodeManagers::manager<LevelOfDetail>() const noexcept
{
return m_levelOfDetailManager;
}
template<>
-FilterKeyManager *NodeManagers::manager<FilterKey>() const Q_DECL_NOTHROW
+FilterKeyManager *NodeManagers::manager<FilterKey>() const noexcept
{
return m_filterKeyManager;
}
template<>
-FrameGraphManager *NodeManagers::manager<FrameGraphNode*>() const Q_DECL_NOTHROW
+FrameGraphManager *NodeManagers::manager<FrameGraphNode*>() const noexcept
{
return m_frameGraphManager;
}
template<>
-TransformManager *NodeManagers::manager<Transform>() const Q_DECL_NOTHROW
+TransformManager *NodeManagers::manager<Transform>() const noexcept
{
return m_transformManager;
}
template<>
-RenderTargetManager *NodeManagers::manager<RenderTarget>() const Q_DECL_NOTHROW
+RenderTargetManager *NodeManagers::manager<RenderTarget>() const noexcept
{
return m_renderTargetManager;
}
template<>
-SceneManager *NodeManagers::manager<Scene>() const Q_DECL_NOTHROW
+SceneManager *NodeManagers::manager<Scene>() const noexcept
{
return m_sceneManager;
}
template<>
-AttachmentManager *NodeManagers::manager<RenderTargetOutput>() const Q_DECL_NOTHROW
+AttachmentManager *NodeManagers::manager<RenderTargetOutput>() const noexcept
{
return m_attachmentManager;
}
template<>
-ParameterManager *NodeManagers::manager<Parameter>() const Q_DECL_NOTHROW
+ParameterManager *NodeManagers::manager<Parameter>() const noexcept
{
return m_parameterManager;
}
template<>
-ShaderDataManager *NodeManagers::manager<ShaderData>() const Q_DECL_NOTHROW
+ShaderDataManager *NodeManagers::manager<ShaderData>() const noexcept
{
return m_shaderDataManager;
}
template<>
-GLBufferManager *NodeManagers::manager<GLBuffer>() const Q_DECL_NOTHROW
+GLBufferManager *NodeManagers::manager<GLBuffer>() const noexcept
{
return m_glBufferManager;
}
template<>
-TextureImageManager *NodeManagers::manager<TextureImage>() const Q_DECL_NOTHROW
+TextureImageManager *NodeManagers::manager<TextureImage>() const noexcept
{
return m_textureImageManager;
}
template<>
-BufferManager *NodeManagers::manager<Buffer>() const Q_DECL_NOTHROW
+BufferManager *NodeManagers::manager<Buffer>() const noexcept
{
return m_bufferManager;
}
template<>
-AttributeManager *NodeManagers::manager<Attribute>() const Q_DECL_NOTHROW
+AttributeManager *NodeManagers::manager<Attribute>() const noexcept
{
return m_attributeManager;
}
template<>
-GeometryManager *NodeManagers::manager<Geometry>() const Q_DECL_NOTHROW
+GeometryManager *NodeManagers::manager<Geometry>() const noexcept
{
return m_geometryManager;
}
template<>
-GeometryRendererManager *NodeManagers::manager<GeometryRenderer>() const Q_DECL_NOTHROW
+GeometryRendererManager *NodeManagers::manager<GeometryRenderer>() const noexcept
{
return m_geometryRendererManager;
}
template<>
-ObjectPickerManager *NodeManagers::manager<ObjectPicker>() const Q_DECL_NOTHROW
+ObjectPickerManager *NodeManagers::manager<ObjectPicker>() const noexcept
{
return m_objectPickerManager;
}
template<>
-RayCasterManager *NodeManagers::manager<RayCaster>() const Q_DECL_NOTHROW
+RayCasterManager *NodeManagers::manager<RayCaster>() const noexcept
{
return m_rayCasterManager;
}
//template<>
-//BoundingVolumeDebugManager *NodeManagers::manager<BoundingVolumeDebug>() const Q_DECL_NOTHROW
+//BoundingVolumeDebugManager *NodeManagers::manager<BoundingVolumeDebug>() const noexcept
//{
// return m_boundingVolumeDebugManager;
//}
template<>
-LightManager *NodeManagers::manager<Light>() const Q_DECL_NOTHROW
+LightManager *NodeManagers::manager<Light>() const noexcept
{
return m_lightManager;
}
template<>
-EnvironmentLightManager *NodeManagers::manager<EnvironmentLight>() const Q_DECL_NOTHROW
+EnvironmentLightManager *NodeManagers::manager<EnvironmentLight>() const noexcept
{
return m_environmentLightManager;
}
template<>
-ComputeCommandManager *NodeManagers::manager<ComputeCommand>() const Q_DECL_NOTHROW
+ComputeCommandManager *NodeManagers::manager<ComputeCommand>() const noexcept
{
return m_computeJobManager;
}
template<>
-RenderStateManager *NodeManagers::manager<RenderStateNode>() const Q_DECL_NOTHROW
+RenderStateManager *NodeManagers::manager<RenderStateNode>() const noexcept
{
return m_renderStateManager;
}
template<>
-ArmatureManager *NodeManagers::manager<Armature>() const Q_DECL_NOTHROW
+ArmatureManager *NodeManagers::manager<Armature>() const noexcept
{
return m_armatureManager;
}
template<>
-SkeletonManager *NodeManagers::manager<Skeleton>() const Q_DECL_NOTHROW
+SkeletonManager *NodeManagers::manager<Skeleton>() const noexcept
{
return m_skeletonManager;
}
template<>
-JointManager *NodeManagers::manager<Joint>() const Q_DECL_NOTHROW
+JointManager *NodeManagers::manager<Joint>() const noexcept
{
return m_jointManager;
}
+template<>
+ShaderImageManager *NodeManagers::manager<ShaderImage>() const noexcept
+{
+ return m_shaderImageManager;
+}
+
} // Render
} // Qt3DRender
diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h
index 4ef1f4927..8dda4e8ad 100644
--- a/src/render/backend/nodemanagers_p.h
+++ b/src/render/backend/nodemanagers_p.h
@@ -105,6 +105,7 @@ class RenderStateManager;
class ArmatureManager;
class SkeletonManager;
class JointManager;
+class ShaderImageManager;
class FrameGraphNode;
class Entity;
@@ -143,6 +144,7 @@ class Armature;
class Skeleton;
class Joint;
class OpenGLVertexArrayObject;
+class ShaderImage;
class ResourceAccessor;
@@ -153,7 +155,7 @@ public:
~NodeManagers();
template<class Backend, typename Manager>
- Manager *manager() const Q_DECL_NOEXCEPT
+ Manager *manager() const noexcept
{
return nullptr;
}
@@ -186,47 +188,46 @@ public:
}
- inline CameraManager *cameraManager() const Q_DECL_NOEXCEPT { return m_cameraManager; }
- inline EntityManager *renderNodesManager() const Q_DECL_NOEXCEPT { return m_renderNodesManager; }
- inline MaterialManager *materialManager() const Q_DECL_NOEXCEPT { return m_materialManager; }
- inline MatrixManager *worldMatrixManager() const Q_DECL_NOEXCEPT { return m_worldMatrixManager; }
- inline VAOManager *vaoManager() const Q_DECL_NOEXCEPT { return m_vaoManager; }
- inline ShaderManager *shaderManager() const Q_DECL_NOEXCEPT { return m_shaderManager; }
- inline ShaderBuilderManager *shaderBuilderManager() const Q_DECL_NOEXCEPT { return m_shaderBuilderManager; }
- 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 LevelOfDetailManager *levelOfDetailManager() const Q_DECL_NOEXCEPT { return m_levelOfDetailManager; }
- inline FilterKeyManager *filterKeyManager() const Q_DECL_NOEXCEPT { return m_filterKeyManager; }
- inline FrameGraphManager *frameGraphManager() const Q_DECL_NOEXCEPT { return m_frameGraphManager; }
- inline TransformManager *transformManager() const Q_DECL_NOEXCEPT { return m_transformManager; }
- inline RenderTargetManager *renderTargetManager() const Q_DECL_NOEXCEPT { return m_renderTargetManager; }
- inline SceneManager *sceneManager() const Q_DECL_NOEXCEPT { return m_sceneManager; }
- inline AttachmentManager *attachmentManager() const Q_DECL_NOEXCEPT { return m_attachmentManager; }
- inline ParameterManager *parameterManager() const Q_DECL_NOEXCEPT { return m_parameterManager; }
- inline ShaderDataManager *shaderDataManager() const Q_DECL_NOEXCEPT { return m_shaderDataManager; }
- inline GLBufferManager *glBufferManager() const Q_DECL_NOEXCEPT { return m_glBufferManager; }
- inline GLFenceManager *glFenceManager() const Q_DECL_NOEXCEPT { return m_glFenceManager; }
- inline TextureImageManager *textureImageManager() const Q_DECL_NOEXCEPT { return m_textureImageManager; }
- inline BufferManager *bufferManager() const Q_DECL_NOEXCEPT { return m_bufferManager; }
- inline AttributeManager *attributeManager() const Q_DECL_NOEXCEPT { return m_attributeManager; }
- inline GeometryManager *geometryManager() const Q_DECL_NOEXCEPT { return m_geometryManager; }
- inline GeometryRendererManager *geometryRendererManager() const Q_DECL_NOEXCEPT { return m_geometryRendererManager; }
- inline ObjectPickerManager *objectPickerManager() const Q_DECL_NOEXCEPT { return m_objectPickerManager; }
- inline RayCasterManager *rayCasterManager() const Q_DECL_NOEXCEPT { return m_rayCasterManager; }
- // inline BoundingVolumeDebugManager *boundingVolumeDebugManager() const Q_DECL_NOEXCEPT { return m_boundingVolumeDebugManager; }
- inline LightManager *lightManager() const Q_DECL_NOEXCEPT { return m_lightManager; }
- inline EnvironmentLightManager *environmentLightManager() const Q_DECL_NOEXCEPT { return m_environmentLightManager; }
- inline ComputeCommandManager *computeJobManager() const Q_DECL_NOEXCEPT { return m_computeJobManager; }
- inline RenderStateManager *renderStateManager() const Q_DECL_NOEXCEPT { return m_renderStateManager; }
- inline ArmatureManager *armatureManager() const Q_DECL_NOEXCEPT { return m_armatureManager; }
- inline SkeletonManager *skeletonManager() const Q_DECL_NOEXCEPT { return m_skeletonManager; }
- inline JointManager *jointManager() const Q_DECL_NOEXCEPT { return m_jointManager; }
+ inline CameraManager *cameraManager() const noexcept { return m_cameraManager; }
+ inline EntityManager *renderNodesManager() const noexcept { return m_renderNodesManager; }
+ inline MaterialManager *materialManager() const noexcept { return m_materialManager; }
+ inline MatrixManager *worldMatrixManager() const noexcept { return m_worldMatrixManager; }
+ inline VAOManager *vaoManager() const noexcept { return m_vaoManager; }
+ inline ShaderManager *shaderManager() const noexcept { return m_shaderManager; }
+ inline ShaderBuilderManager *shaderBuilderManager() const noexcept { return m_shaderBuilderManager; }
+ inline TechniqueManager *techniqueManager() const noexcept { return m_techniqueManager; }
+ inline EffectManager *effectManager() const noexcept { return m_effectManager; }
+ inline RenderPassManager *renderPassManager() const noexcept { return m_renderPassManager; }
+ inline GLTextureManager *glTextureManager() const noexcept { return m_glTextureManager; }
+ inline TextureManager *textureManager() const noexcept { return m_textureManager; }
+ inline LayerManager *layerManager() const noexcept { return m_layerManager; }
+ inline LevelOfDetailManager *levelOfDetailManager() const noexcept { return m_levelOfDetailManager; }
+ inline FilterKeyManager *filterKeyManager() const noexcept { return m_filterKeyManager; }
+ inline FrameGraphManager *frameGraphManager() const noexcept { return m_frameGraphManager; }
+ inline TransformManager *transformManager() const noexcept { return m_transformManager; }
+ inline RenderTargetManager *renderTargetManager() const noexcept { return m_renderTargetManager; }
+ inline SceneManager *sceneManager() const noexcept { return m_sceneManager; }
+ inline AttachmentManager *attachmentManager() const noexcept { return m_attachmentManager; }
+ inline ParameterManager *parameterManager() const noexcept { return m_parameterManager; }
+ inline ShaderDataManager *shaderDataManager() const noexcept { return m_shaderDataManager; }
+ inline GLBufferManager *glBufferManager() const noexcept { return m_glBufferManager; }
+ inline GLFenceManager *glFenceManager() const noexcept { return m_glFenceManager; }
+ inline TextureImageManager *textureImageManager() const noexcept { return m_textureImageManager; }
+ inline BufferManager *bufferManager() const noexcept { return m_bufferManager; }
+ inline AttributeManager *attributeManager() const noexcept { return m_attributeManager; }
+ inline GeometryManager *geometryManager() const noexcept { return m_geometryManager; }
+ inline GeometryRendererManager *geometryRendererManager() const noexcept { return m_geometryRendererManager; }
+ inline ObjectPickerManager *objectPickerManager() const noexcept { return m_objectPickerManager; }
+ inline RayCasterManager *rayCasterManager() const noexcept { return m_rayCasterManager; }
+ // inline BoundingVolumeDebugManager *boundingVolumeDebugManager() const noexcept { return m_boundingVolumeDebugManager; }
+ inline LightManager *lightManager() const noexcept { return m_lightManager; }
+ inline EnvironmentLightManager *environmentLightManager() const noexcept { return m_environmentLightManager; }
+ inline ComputeCommandManager *computeJobManager() const noexcept { return m_computeJobManager; }
+ inline RenderStateManager *renderStateManager() const noexcept { return m_renderStateManager; }
+ inline ArmatureManager *armatureManager() const noexcept { return m_armatureManager; }
+ inline SkeletonManager *skeletonManager() const noexcept { return m_skeletonManager; }
+ inline JointManager *jointManager() const noexcept { return m_jointManager; }
+ inline ShaderImageManager *shaderImageManager() const noexcept { return m_shaderImageManager; }
QSharedPointer<ResourceAccessor> resourceAccessor();
@@ -243,8 +244,6 @@ private:
RenderPassManager *m_renderPassManager;
TextureManager *m_textureManager;
TextureImageManager *m_textureImageManager;
- TextureDataManager *m_textureDataManager;
- TextureImageDataManager *m_textureImageDataManager;
GLTextureManager *m_glTextureManager;
LayerManager *m_layerManager;
LevelOfDetailManager *m_levelOfDetailManager;
@@ -272,6 +271,7 @@ private:
ArmatureManager *m_armatureManager;
SkeletonManager *m_skeletonManager;
JointManager *m_jointManager;
+ ShaderImageManager *m_shaderImageManager;
QSharedPointer<ResourceAccessor> m_resourceAccessor;
};
@@ -279,118 +279,118 @@ private:
// Specializations
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT CameraManager *NodeManagers::manager<CameraLens>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT CameraManager *NodeManagers::manager<CameraLens>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT EntityManager *NodeManagers::manager<Entity>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT EntityManager *NodeManagers::manager<Entity>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT MaterialManager *NodeManagers::manager<Material>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT MaterialManager *NodeManagers::manager<Material>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT MatrixManager *NodeManagers::manager<QMatrix4x4*>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT MatrixManager *NodeManagers::manager<QMatrix4x4*>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT VAOManager *NodeManagers::manager<OpenGLVertexArrayObject>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT VAOManager *NodeManagers::manager<OpenGLVertexArrayObject>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT ShaderManager *NodeManagers::manager<Shader>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT ShaderManager *NodeManagers::manager<Shader>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT ShaderBuilderManager *NodeManagers::manager<ShaderBuilder>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT ShaderBuilderManager *NodeManagers::manager<ShaderBuilder>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT TechniqueManager *NodeManagers::manager<Technique>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT TechniqueManager *NodeManagers::manager<Technique>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT EffectManager *NodeManagers::manager<Effect>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT EffectManager *NodeManagers::manager<Effect>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT RenderPassManager *NodeManagers::manager<RenderPass>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT RenderPassManager *NodeManagers::manager<RenderPass>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT TextureManager *NodeManagers::manager<Texture>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT TextureManager *NodeManagers::manager<Texture>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT TextureDataManager *NodeManagers::manager<QTextureImageData>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT LayerManager *NodeManagers::manager<Layer>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT LayerManager *NodeManagers::manager<Layer>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT LevelOfDetailManager *NodeManagers::manager<LevelOfDetail>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT LevelOfDetailManager *NodeManagers::manager<LevelOfDetail>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT FilterKeyManager *NodeManagers::manager<FilterKey>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT FilterKeyManager *NodeManagers::manager<FilterKey>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT FrameGraphManager *NodeManagers::manager<FrameGraphNode*>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT FrameGraphManager *NodeManagers::manager<FrameGraphNode*>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT TransformManager *NodeManagers::manager<Transform>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT TransformManager *NodeManagers::manager<Transform>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT RenderTargetManager *NodeManagers::manager<RenderTarget>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT RenderTargetManager *NodeManagers::manager<RenderTarget>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT SceneManager *NodeManagers::manager<Scene>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT SceneManager *NodeManagers::manager<Scene>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT AttachmentManager *NodeManagers::manager<RenderTargetOutput>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT AttachmentManager *NodeManagers::manager<RenderTargetOutput>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT ParameterManager *NodeManagers::manager<Parameter>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT ParameterManager *NodeManagers::manager<Parameter>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT ShaderDataManager *NodeManagers::manager<ShaderData>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT ShaderDataManager *NodeManagers::manager<ShaderData>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT GLBufferManager *NodeManagers::manager<GLBuffer>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT GLBufferManager *NodeManagers::manager<GLBuffer>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT TextureImageManager *NodeManagers::manager<TextureImage>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT TextureImageManager *NodeManagers::manager<TextureImage>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT BufferManager *NodeManagers::manager<Buffer>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT BufferManager *NodeManagers::manager<Buffer>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT AttributeManager *NodeManagers::manager<Attribute>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT AttributeManager *NodeManagers::manager<Attribute>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT GeometryManager *NodeManagers::manager<Geometry>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT GeometryManager *NodeManagers::manager<Geometry>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT GeometryRendererManager *NodeManagers::manager<GeometryRenderer>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT GeometryRendererManager *NodeManagers::manager<GeometryRenderer>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT ObjectPickerManager *NodeManagers::manager<ObjectPicker>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT ObjectPickerManager *NodeManagers::manager<ObjectPicker>() const Q_DECL_NOEXCEPT;
-
-template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT RayCasterManager *NodeManagers::manager<RayCaster>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT RayCasterManager *NodeManagers::manager<RayCaster>() const noexcept;
//template<>
-//Q_3DRENDERSHARED_PRIVATE_EXPORT BoundingVolumeDebugManager *NodeManagers::manager<BoundingVolumeDebug>() const Q_DECL_NOEXCEPT;
+//Q_3DRENDERSHARED_PRIVATE_EXPORT BoundingVolumeDebugManager *NodeManagers::manager<BoundingVolumeDebug>() const noexcept;
+
+template<>
+LightManager *NodeManagers::manager<Light>() const noexcept;
template<>
-LightManager *NodeManagers::manager<Light>() const Q_DECL_NOEXCEPT;
+EnvironmentLightManager *NodeManagers::manager<EnvironmentLight>() const noexcept;
template<>
-EnvironmentLightManager *NodeManagers::manager<EnvironmentLight>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT ComputeCommandManager *NodeManagers::manager<ComputeCommand>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT ComputeCommandManager *NodeManagers::manager<ComputeCommand>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT RenderStateManager *NodeManagers::manager<RenderStateNode>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT RenderStateManager *NodeManagers::manager<RenderStateNode>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT ArmatureManager *NodeManagers::manager<Armature>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT ArmatureManager *NodeManagers::manager<Armature>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT SkeletonManager *NodeManagers::manager<Skeleton>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT SkeletonManager *NodeManagers::manager<Skeleton>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT JointManager *NodeManagers::manager<Joint>() const noexcept;
template<>
-Q_3DRENDERSHARED_PRIVATE_EXPORT JointManager *NodeManagers::manager<Joint>() const Q_DECL_NOEXCEPT;
+Q_3DRENDERSHARED_PRIVATE_EXPORT ShaderImageManager *NodeManagers::manager<ShaderImage>() const noexcept;
} // Render
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index 6b60dfcda..9510b9530 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -11,6 +11,7 @@ HEADERS += \
$$PWD/platformsurfacefilter_p.h \
$$PWD/cameralens_p.h \
$$PWD/entity_p.h \
+ $$PWD/entity_p_p.h \
$$PWD/entityvisitor_p.h \
$$PWD/entityaccumulator_p.h \
$$PWD/layer_p.h \
diff --git a/src/render/backend/rendersettings.cpp b/src/render/backend/rendersettings.cpp
index 5734f96a6..487f6e11a 100644
--- a/src/render/backend/rendersettings.cpp
+++ b/src/render/backend/rendersettings.cpp
@@ -43,7 +43,6 @@
#include <Qt3DRender/private/abstractrenderer_p.h>
#include <Qt3DRender/private/qrendersettings_p.h>
#include <Qt3DCore/qnodecommand.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -63,42 +62,42 @@ RenderSettings::RenderSettings()
{
}
-void RenderSettings::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void RenderSettings::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QRenderSettingsData>>(change);
- const auto &data = typedChange->data;
- m_activeFrameGraph = data.activeFrameGraphId;
- m_renderPolicy = data.renderPolicy;
- m_pickMethod = data.pickMethod;
- m_pickResultMode = data.pickResultMode;
- m_pickWorldSpaceTolerance = data.pickWorldSpaceTolerance;
- m_faceOrientationPickingMode = data.faceOrientationPickingMode;
-}
+ const QRenderSettings *node = qobject_cast<const QRenderSettings *>(frontEnd);
+ if (!node)
+ return;
-void RenderSettings::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("pickMethod"))
- 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("pickWorldSpaceTolerance"))
- m_pickWorldSpaceTolerance = propertyChange->value().toFloat();
- else if (propertyChange->propertyName() == QByteArrayLiteral("activeFrameGraph"))
- m_activeFrameGraph = propertyChange->value().value<QNodeId>();
- else if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy"))
- m_renderPolicy = propertyChange->value().value<QRenderSettings::RenderPolicy>();
- markDirty(AbstractRenderer::AllDirty);
- } else if (e->type() == CommandRequested) {
- QNodeCommandPtr command = qSharedPointerCast<QNodeCommand>(e);
- if (command->name() == QLatin1Literal("InvalidateFrame"))
- markDirty(AbstractRenderer::AllDirty);
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const Qt3DCore::QNodeId activeFGId = Qt3DCore::qIdForNode(node->activeFrameGraph());
+ if (activeFGId != m_activeFrameGraph) {
+ m_activeFrameGraph = activeFGId;
+ }
+
+ if (node->renderPolicy() != m_renderPolicy) {
+ m_renderPolicy = node->renderPolicy();
+ }
+
+ if (node->pickingSettings()->pickMethod() != m_pickMethod) {
+ m_pickMethod = node->pickingSettings()->pickMethod();
}
- BackendNode::sceneChangeEvent(e);
+ if (node->pickingSettings()->pickResultMode() != m_pickResultMode) {
+ m_pickResultMode = node->pickingSettings()->pickResultMode();
+ }
+
+ if (node->pickingSettings()->worldSpaceTolerance() != m_pickWorldSpaceTolerance) {
+ m_pickWorldSpaceTolerance = node->pickingSettings()->worldSpaceTolerance();
+ }
+
+ if (node->pickingSettings()->faceOrientationPickingMode() != m_faceOrientationPickingMode) {
+ m_faceOrientationPickingMode = node->pickingSettings()->faceOrientationPickingMode();
+ }
+
+ // Either because something above as changed or if QRenderSettingsPrivate::invalidFrame()
+ // was called
+ markDirty(AbstractRenderer::AllDirty);
}
RenderSettingsFunctor::RenderSettingsFunctor(AbstractRenderer *renderer)
@@ -131,8 +130,10 @@ void RenderSettingsFunctor::destroy(Qt3DCore::QNodeId id) const
Q_UNUSED(id);
// Deletes the old settings object
auto settings = m_renderer->settings();
- delete settings;
- m_renderer->setSettings(nullptr);
+ if (settings && settings->peerId() == id) {
+ m_renderer->setSettings(nullptr);
+ delete settings;
+ }
}
} // namespace Render
diff --git a/src/render/backend/rendersettings_p.h b/src/render/backend/rendersettings_p.h
index d2880c134..1c8c0ca72 100644
--- a/src/render/backend/rendersettings_p.h
+++ b/src/render/backend/rendersettings_p.h
@@ -67,7 +67,7 @@ class Q_AUTOTEST_EXPORT RenderSettings : public BackendNode
public:
RenderSettings();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
Qt3DCore::QNodeId activeFrameGraphID() const { return m_activeFrameGraph; }
QRenderSettings::RenderPolicy renderPolicy() const { return m_renderPolicy; }
@@ -80,8 +80,6 @@ public:
void setActiveFrameGraphId(Qt3DCore::QNodeId frameGraphNodeId) { m_activeFrameGraph = frameGraphNodeId; }
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QRenderSettings::RenderPolicy m_renderPolicy;
QPickingSettings::PickMethod m_pickMethod;
QPickingSettings::PickResultMode m_pickResultMode;
diff --git a/src/render/backend/rendertarget.cpp b/src/render/backend/rendertarget.cpp
index b0565a26b..088818c94 100644
--- a/src/render/backend/rendertarget.cpp
+++ b/src/render/backend/rendertarget.cpp
@@ -41,9 +41,6 @@
#include <Qt3DRender/qrendertarget.h>
#include <Qt3DRender/private/qrendertarget_p.h>
#include <Qt3DRender/qrendertargetoutput.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
#include <QVariant>
QT_BEGIN_NAMESPACE
@@ -58,11 +55,21 @@ RenderTarget::RenderTarget()
{
}
-void RenderTarget::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void RenderTarget::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QRenderTargetData>>(change);
- const auto &data = typedChange->data;
- m_renderOutputs = data.outputIds;
+ const QRenderTarget *node = qobject_cast<const QRenderTarget *>(frontEnd);
+ if (!node)
+ return;
+
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ auto outputIds = qIdsForNodes(node->outputs());
+ std::sort(std::begin(outputIds), std::end(outputIds));
+
+ if (m_renderOutputs != outputIds) {
+ m_renderOutputs = outputIds;
+ markDirty(AbstractRenderer::AllDirty);
+ }
}
void RenderTarget::cleanup()
@@ -87,33 +94,6 @@ QVector<Qt3DCore::QNodeId> RenderTarget::renderOutputs() const
return m_renderOutputs;
}
-void RenderTarget::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case Qt3DCore::PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("output")) {
- appendRenderOutput(change->addedNodeId());
- markDirty(AbstractRenderer::AllDirty);
- }
- break;
- }
-
- case Qt3DCore::PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("output")) {
- removeRenderOutput(change->removedNodeId());
- markDirty(AbstractRenderer::AllDirty);
- }
- break;
- }
-
- default:
- break;
- }
- BackendNode::sceneChangeEvent(e);
-}
-
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/rendertarget_p.h b/src/render/backend/rendertarget_p.h
index 5e3e63582..30769dcfc 100644
--- a/src/render/backend/rendertarget_p.h
+++ b/src/render/backend/rendertarget_p.h
@@ -76,11 +76,9 @@ public:
QVector<Qt3DCore::QNodeId> renderOutputs() const;
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QVector<Qt3DCore::QNodeId> m_renderOutputs;
};
diff --git a/src/render/backend/rendertargetoutput.cpp b/src/render/backend/rendertargetoutput.cpp
index cba92596d..e98acf3b8 100644
--- a/src/render/backend/rendertargetoutput.cpp
+++ b/src/render/backend/rendertargetoutput.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include <Qt3DRender/private/rendertargetoutput_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/private/qrendertargetoutput_p.h>
#include <QVariant>
@@ -55,15 +54,39 @@ RenderTargetOutput::RenderTargetOutput()
{
}
-void RenderTargetOutput::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void RenderTargetOutput::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QRenderTargetOutputData>>(change);
- const auto &data = typedChange->data;
- m_attachmentData.m_point = data.attachmentPoint;
- m_attachmentData.m_mipLevel = data.mipLevel;
- m_attachmentData.m_layer = data.layer;
- m_attachmentData.m_face = data.face;
- m_attachmentData.m_textureUuid = data.textureId;
+ const QRenderTargetOutput *node = qobject_cast<const QRenderTargetOutput *>(frontEnd);
+ if (!node)
+ return;
+
+ const bool oldEnabled = isEnabled();
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (node->attachmentPoint() != m_attachmentData.m_point) {
+ m_attachmentData.m_point = node->attachmentPoint();
+ markDirty(AbstractRenderer::AllDirty);
+ }
+ if (node->mipLevel() != m_attachmentData.m_mipLevel) {
+ m_attachmentData.m_mipLevel = node->mipLevel();
+ markDirty(AbstractRenderer::AllDirty);
+ }
+ if (node->layer() != m_attachmentData.m_layer) {
+ m_attachmentData.m_layer = node->layer();
+ markDirty(AbstractRenderer::AllDirty);
+ }
+ if (node->face() != m_attachmentData.m_face) {
+ m_attachmentData.m_face = node->face();
+ markDirty(AbstractRenderer::AllDirty);
+ }
+ const auto textureId = Qt3DCore::qIdForNode(node->texture());
+ if (textureId != m_attachmentData.m_textureUuid) {
+ m_attachmentData.m_textureUuid = textureId;
+ markDirty(AbstractRenderer::AllDirty);
+ }
+
+ if (oldEnabled != isEnabled())
+ markDirty(AbstractRenderer::AllDirty);
}
Qt3DCore::QNodeId RenderTargetOutput::textureUuid() const
@@ -96,31 +119,6 @@ QRenderTargetOutput::AttachmentPoint RenderTargetOutput::point() const
return m_attachmentData.m_point;
}
-void RenderTargetOutput::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (e->type() == PropertyUpdated) {
- if (propertyChange->propertyName() == QByteArrayLiteral("type")) {
- m_attachmentData.m_point = static_cast<QRenderTargetOutput::AttachmentPoint>(propertyChange->value().toInt());
- }
- else if (propertyChange->propertyName() == QByteArrayLiteral("texture")) {
- m_attachmentData.m_textureUuid = propertyChange->value().value<QNodeId>();
- }
- else if (propertyChange->propertyName() == QByteArrayLiteral("mipLevel")) {
- m_attachmentData.m_mipLevel = propertyChange->value().toInt();
- }
- else if (propertyChange->propertyName() == QByteArrayLiteral("layer")) {
- m_attachmentData.m_layer = propertyChange->value().toInt();
- }
- else if (propertyChange->propertyName() == QByteArrayLiteral("face")) {
- m_attachmentData.m_face = static_cast<QAbstractTexture::CubeMapFace>(propertyChange->value().toInt());
- }
- markDirty(AbstractRenderer::AllDirty);
- }
-
- BackendNode::sceneChangeEvent(e);
-}
-
Qt3DRender::Render::Attachment *RenderTargetOutput::attachment()
{
return &m_attachmentData;
diff --git a/src/render/backend/rendertargetoutput_p.h b/src/render/backend/rendertargetoutput_p.h
index 20476547b..d72f6d231 100644
--- a/src/render/backend/rendertargetoutput_p.h
+++ b/src/render/backend/rendertargetoutput_p.h
@@ -76,12 +76,11 @@ public:
QString name() const;
QAbstractTexture::CubeMapFace face() const;
QRenderTargetOutput::AttachmentPoint point() const;
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
Attachment *attachment();
const Attachment *attachment() const;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
Qt3DCore::QNodeId m_attachmentUuid;
Attachment m_attachmentData;
};
diff --git a/src/render/backend/resourceaccessor.cpp b/src/render/backend/resourceaccessor.cpp
index c6496976a..4f70df436 100644
--- a/src/render/backend/resourceaccessor.cpp
+++ b/src/render/backend/resourceaccessor.cpp
@@ -42,7 +42,6 @@
#include <private/nodemanagers_p.h>
#include <private/texture_p.h>
#include <private/rendertargetoutput_p.h>
-#include <private/texturedatamanager_p.h>
#include <private/gltexturemanager_p.h>
#include <private/managers_p.h>
#include <private/gltexture_p.h>
diff --git a/src/render/backend/transform.cpp b/src/render/backend/transform.cpp
index 20574d6f7..8e98801b7 100644
--- a/src/render/backend/transform.cpp
+++ b/src/render/backend/transform.cpp
@@ -52,7 +52,7 @@ namespace Qt3DRender {
namespace Render {
Transform::Transform()
- : BackendNode()
+ : BackendNode(ReadWrite)
, m_rotation()
, m_scale(1.0f, 1.0f, 1.0f)
, m_translation()
@@ -68,16 +68,6 @@ void Transform::cleanup()
QBackendNode::setEnabled(false);
}
-void Transform::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QTransformData>>(change);
- const auto &data = typedChange->data;
- m_rotation = data.rotation;
- m_scale = data.scale;
- m_translation = data.translation;
- updateMatrix();
-}
-
Matrix4x4 Transform::transformMatrix() const
{
return m_transformMatrix;
@@ -98,25 +88,25 @@ QVector3D Transform::translation() const
return m_translation;
}
-void Transform::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void Transform::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- // TODO: Flag the matrix as dirty and update all matrices batched in a job
- if (e->type() == PropertyUpdated) {
- const QPropertyUpdatedChangePtr &propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("scale3D")) {
- m_scale = propertyChange->value().value<QVector3D>();
- updateMatrix();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("rotation")) {
- m_rotation = propertyChange->value().value<QQuaternion>();
- updateMatrix();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("translation")) {
- m_translation = propertyChange->value().value<QVector3D>();
- updateMatrix();
- }
+ const Qt3DCore::QTransform *transform = qobject_cast<const Qt3DCore::QTransform *>(frontEnd);
+ if (!transform)
+ return;
+
+ bool dirty = m_rotation != transform->rotation();
+ m_rotation = transform->rotation();
+ dirty |= m_scale != transform->scale3D();
+ m_scale = transform->scale3D();
+ dirty |= m_translation != transform->translation();
+ m_translation = transform->translation();
+
+ if (dirty || firstTime) {
+ updateMatrix();
+ markDirty(AbstractRenderer::TransformDirty);
}
- markDirty(AbstractRenderer::TransformDirty);
- BackendNode::sceneChangeEvent(e);
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
}
void Transform::updateMatrix()
diff --git a/src/render/backend/transform_p.h b/src/render/backend/transform_p.h
index 8e3e9d639..8c0cd826a 100644
--- a/src/render/backend/transform_p.h
+++ b/src/render/backend/transform_p.h
@@ -76,13 +76,10 @@ public:
QQuaternion rotation() const;
QVector3D translation() const;
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
-
- void updateMatrix();
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) final;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
+ void updateMatrix();
Matrix4x4 m_transformMatrix;
QQuaternion m_rotation;
QVector3D m_scale;
diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h
index 7f273566e..09575a077 100644
--- a/src/render/backend/uniform_p.h
+++ b/src/render/backend/uniform_p.h
@@ -101,6 +101,7 @@ enum UniformType {
Mat3x4,
Mat4x3,
Sampler,
+ Image,
Unknown
};
@@ -111,7 +112,8 @@ public:
ScalarValue,
NodeId,
TextureValue,
- BufferValue
+ BufferValue,
+ ShaderImageValue
};
// UniformValue implicitely converts doubles to floats to ensure
diff --git a/src/render/framegraph/blitframebuffer.cpp b/src/render/framegraph/blitframebuffer.cpp
index 342594baf..0ecfbf5c4 100644
--- a/src/render/framegraph/blitframebuffer.cpp
+++ b/src/render/framegraph/blitframebuffer.cpp
@@ -39,7 +39,6 @@
#include <Qt3DRender/private/qblitframebuffer_p.h>
#include <Qt3DRender/private/blitframebuffer_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -60,48 +59,44 @@ BlitFramebuffer::BlitFramebuffer()
{
}
-void BlitFramebuffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void BlitFramebuffer::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("sourceRenderTarget")) {
- m_sourceRenderTargetId = propertyChange->value().value<QNodeId>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("destinationRenderTarget")) {
- m_destinationRenderTargetId = propertyChange->value().value<QNodeId>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("sourceRect")) {
- m_sourceRect = propertyChange->value().toRect();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("destinationRect")) {
- m_destinationRect = propertyChange->value().toRect();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("sourceAttachmentPoint")) {
- m_sourceAttachmentPoint = propertyChange->value().value<Qt3DRender::QRenderTargetOutput::AttachmentPoint>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("destinationAttachmentPoint")) {
- m_destinationAttachmentPoint = propertyChange->value().value<Qt3DRender::QRenderTargetOutput::AttachmentPoint>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("interpolationMethod")) {
- m_interpolationMethod = propertyChange->value().value<QBlitFramebuffer::InterpolationMethod>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- }
- FrameGraphNode::sceneChangeEvent(e);
-}
+ const QBlitFramebuffer *node = qobject_cast<const QBlitFramebuffer *>(frontEnd);
+ if (!node)
+ return;
-void BlitFramebuffer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QBlitFramebufferData> >(change);
- const auto &data = typedChange->data;
- m_sourceRect = data.m_sourceRect;
- m_destinationRect = data.m_destinationRect;
- m_sourceRenderTargetId = data.m_sourceRenderTargetId;
- m_destinationRenderTargetId = data.m_destinationRenderTargetId;
- m_sourceAttachmentPoint = data.m_sourceAttachmentPoint;
- m_destinationAttachmentPoint = data.m_destinationAttachmentPoint;
- m_interpolationMethod = data.m_interpolationMethod;
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (node->sourceRect().toRect() != m_sourceRect) {
+ m_sourceRect = node->sourceRect().toRect();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ if (node->destinationRect().toRect() != m_destinationRect) {
+ m_destinationRect = node->destinationRect().toRect();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ if (node->sourceAttachmentPoint() != m_sourceAttachmentPoint) {
+ m_sourceAttachmentPoint = node->sourceAttachmentPoint();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ if (node->destinationAttachmentPoint() != m_destinationAttachmentPoint) {
+ m_destinationAttachmentPoint = node->destinationAttachmentPoint();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ if (node->interpolationMethod() != m_interpolationMethod) {
+ m_interpolationMethod = node->interpolationMethod();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ const QNodeId destinationNodeId = qIdForNode(node->destination());
+ if (destinationNodeId != m_destinationRenderTargetId) {
+ m_destinationRenderTargetId = destinationNodeId;
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ const QNodeId sourceNodeId = qIdForNode(node->source());
+ if (sourceNodeId != m_sourceRenderTargetId) {
+ m_sourceRenderTargetId = sourceNodeId;
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
Qt3DRender::QRenderTargetOutput::AttachmentPoint BlitFramebuffer::destinationAttachmentPoint() const
diff --git a/src/render/framegraph/blitframebuffer_p.h b/src/render/framegraph/blitframebuffer_p.h
index 796c223ca..fa9ddacd9 100644
--- a/src/render/framegraph/blitframebuffer_p.h
+++ b/src/render/framegraph/blitframebuffer_p.h
@@ -65,7 +65,7 @@ class Q_AUTOTEST_EXPORT BlitFramebuffer : public FrameGraphNode
public:
BlitFramebuffer();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
Qt3DCore::QNodeId sourceRenderTargetId() const;
@@ -82,8 +82,6 @@ public:
QBlitFramebuffer::InterpolationMethod interpolationMethod() const;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
Qt3DCore::QNodeId m_sourceRenderTargetId;
Qt3DCore::QNodeId m_destinationRenderTargetId;
QRect m_sourceRect;
diff --git a/src/render/framegraph/buffercapture.cpp b/src/render/framegraph/buffercapture.cpp
index 4e89150df..b5e80eb29 100644
--- a/src/render/framegraph/buffercapture.cpp
+++ b/src/render/framegraph/buffercapture.cpp
@@ -40,7 +40,6 @@
#include <Qt3DRender/private/qbuffercapture_p.h>
#include <Qt3DRender/private/buffercapture_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/framegraph/cameraselectornode.cpp b/src/render/framegraph/cameraselectornode.cpp
index 357611c7c..3beb0ef71 100644
--- a/src/render/framegraph/cameraselectornode.cpp
+++ b/src/render/framegraph/cameraselectornode.cpp
@@ -40,9 +40,7 @@
#include "cameraselectornode_p.h"
#include <Qt3DRender/private/qcameraselector_p.h>
#include <Qt3DRender/private/renderer_p.h>
-#include <Qt3DCore/private/qchangearbiter_p.h>
#include <Qt3DCore/qentity.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/renderlogging_p.h>
QT_BEGIN_NAMESPACE
@@ -57,25 +55,19 @@ CameraSelector::CameraSelector()
{
}
-void CameraSelector::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void CameraSelector::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QCameraSelectorData>>(change);
- const auto &data = typedChange->data;
- m_cameraUuid = data.cameraId;
-}
+ const QCameraSelector *node = qobject_cast<const QCameraSelector *>(frontEnd);
+ if (!node)
+ return;
-void CameraSelector::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- qCDebug(Render::Framegraph) << Q_FUNC_INFO;
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("camera")) {
- m_cameraUuid = propertyChange->value().value<QNodeId>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const QNodeId cameraId = qIdForNode(node->camera());
+ if (m_cameraUuid != cameraId) {
+ m_cameraUuid = cameraId;
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
- FrameGraphNode::sceneChangeEvent(e);
}
QNodeId CameraSelector::cameraUuid() const
diff --git a/src/render/framegraph/cameraselectornode_p.h b/src/render/framegraph/cameraselectornode_p.h
index 0e532d68f..dd7e050d0 100644
--- a/src/render/framegraph/cameraselectornode_p.h
+++ b/src/render/framegraph/cameraselectornode_p.h
@@ -69,12 +69,11 @@ class CameraSelector : public FrameGraphNode
public:
CameraSelector();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
Qt3DCore::QNodeId cameraUuid() const;
-private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+private:
Qt3DCore::QNodeId m_cameraUuid;
};
diff --git a/src/render/framegraph/clearbuffers.cpp b/src/render/framegraph/clearbuffers.cpp
index ab6225a4b..3f99e0e20 100644
--- a/src/render/framegraph/clearbuffers.cpp
+++ b/src/render/framegraph/clearbuffers.cpp
@@ -39,7 +39,6 @@
#include "clearbuffers_p.h"
#include <Qt3DRender/private/qclearbuffers_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -50,53 +49,55 @@ namespace Render {
static QVector4D vec4dFromColor(const QColor &color)
{
- return QVector4D(color.redF(), color.greenF(), color.blueF(), color.alphaF());
+ if (!color.isValid())
+ return QVector4D(0.0f, 0.0f, 0.0f, 1.0f);
+ return QVector4D(float(color.redF()), float(color.greenF()), float(color.blueF()), float(color.alphaF()));
}
ClearBuffers::ClearBuffers()
: FrameGraphNode(FrameGraphNode::ClearBuffers)
, m_type(QClearBuffers::None)
+ , m_clearColor(vec4dFromColor(m_clearColorAsColor))
+ , m_clearColorAsColor(Qt::black)
, m_clearDepthValue(1.f)
, m_clearStencilValue(0)
{
}
-void ClearBuffers::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void ClearBuffers::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QClearBuffersData>>(change);
- const auto &data = typedChange->data;
- m_type = data.buffersType;
- m_clearColorAsColor = data.clearColor;
- m_clearColor = vec4dFromColor(m_clearColorAsColor);
- m_clearDepthValue = data.clearDepthValue;
- m_clearStencilValue = data.clearStencilValue;
- m_colorBufferId = data.bufferId;
-}
+ const QClearBuffers *node = qobject_cast<const QClearBuffers *>(frontEnd);
+ if (!node)
+ return;
-void ClearBuffers::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("buffers")) {
- m_type = static_cast<QClearBuffers::BufferType>(propertyChange->value().toInt());
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("clearColor")) {
- m_clearColorAsColor = propertyChange->value().value<QColor>();
- m_clearColor = vec4dFromColor(m_clearColorAsColor);
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("clearDepthValue")) {
- m_clearDepthValue = propertyChange->value().toFloat();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("clearStencilValue")) {
- m_clearStencilValue = propertyChange->value().toInt();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("colorBuffer")) {
- m_colorBufferId = propertyChange->value().value<QNodeId>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (m_clearColorAsColor != node->clearColor()) {
+ m_clearColorAsColor = node->clearColor();
+ m_clearColor = vec4dFromColor(node->clearColor());
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ if (!qFuzzyCompare(m_clearDepthValue, node->clearDepthValue())) {
+ m_clearDepthValue = node->clearDepthValue();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ if (m_clearStencilValue != node->clearStencilValue()) {
+ m_clearStencilValue = node->clearStencilValue();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ const QNodeId colorBufferId = qIdForNode(node->colorBuffer());
+ if (m_colorBufferId != colorBufferId) {
+ m_colorBufferId = colorBufferId;
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ if (m_type != node->buffers()) {
+ m_type = node->buffers();
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
- FrameGraphNode::sceneChangeEvent(e);
}
QClearBuffers::BufferType ClearBuffers::type() const
diff --git a/src/render/framegraph/clearbuffers_p.h b/src/render/framegraph/clearbuffers_p.h
index e3c56c165..ca55d2a98 100644
--- a/src/render/framegraph/clearbuffers_p.h
+++ b/src/render/framegraph/clearbuffers_p.h
@@ -67,8 +67,6 @@ class ClearBuffers : public FrameGraphNode
public:
ClearBuffers();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
-
QClearBuffers::BufferType type() const;
float clearDepthValue() const;
int clearStencilValue() const;
@@ -85,10 +83,9 @@ public:
QColor clearColorAsColor() const;
bool clearsAllColorBuffers() const;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QClearBuffers::BufferType m_type;
QVector4D m_clearColor;
QColor m_clearColorAsColor;
diff --git a/src/render/framegraph/dispatchcompute.cpp b/src/render/framegraph/dispatchcompute.cpp
index f7e9dcff4..4161d37b5 100644
--- a/src/render/framegraph/dispatchcompute.cpp
+++ b/src/render/framegraph/dispatchcompute.cpp
@@ -39,7 +39,6 @@
#include "dispatchcompute_p.h"
#include <Qt3DRender/private/qdispatchcompute_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -66,32 +65,26 @@ void DispatchCompute::cleanup()
m_workGroups[2] = 1;
}
-void DispatchCompute::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void DispatchCompute::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QDispatchComputeData>>(change);
- const auto &data = typedChange->data;
- m_workGroups[0] = data.workGroupX;
- m_workGroups[1] = data.workGroupY;
- m_workGroups[2] = data.workGroupZ;
-}
+ const QDispatchCompute *node = qobject_cast<const QDispatchCompute *>(frontEnd);
+ if (!node)
+ return;
-void DispatchCompute::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- if (e->type() == Qt3DCore::PropertyUpdated) {
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("workGroupX")) {
- m_workGroups[0] = propertyChange->value().toInt();
- markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::ComputeDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("workGroupY")) {
- m_workGroups[1] = propertyChange->value().toInt();
- markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::ComputeDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("workGroupZ")) {
- m_workGroups[2] = propertyChange->value().toInt();
- markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::ComputeDirty);
- }
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (m_workGroups[0] != node->workGroupX()) {
+ m_workGroups[0] = node->workGroupX();
+ markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::ComputeDirty);
+ }
+ if (m_workGroups[1] != node->workGroupY()) {
+ m_workGroups[1] = node->workGroupY();
+ markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::ComputeDirty);
+ }
+ if (m_workGroups[2] != node->workGroupZ()) {
+ m_workGroups[2] = node->workGroupZ();
+ markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::ComputeDirty);
}
- FrameGraphNode::sceneChangeEvent(e);
}
} // Render
diff --git a/src/render/framegraph/dispatchcompute_p.h b/src/render/framegraph/dispatchcompute_p.h
index aa88a35c5..24a641938 100644
--- a/src/render/framegraph/dispatchcompute_p.h
+++ b/src/render/framegraph/dispatchcompute_p.h
@@ -68,13 +68,13 @@ public:
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
inline int x() const Q_DECL_NOTHROW { return m_workGroups[0]; }
inline int y() const Q_DECL_NOTHROW { return m_workGroups[1]; }
inline int z() const Q_DECL_NOTHROW { return m_workGroups[2]; }
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
int m_workGroups[3];
};
diff --git a/src/render/framegraph/framegraph.pri b/src/render/framegraph/framegraph.pri
index b969c85e5..bb833422f 100644
--- a/src/render/framegraph/framegraph.pri
+++ b/src/render/framegraph/framegraph.pri
@@ -64,7 +64,12 @@ HEADERS += \
$$PWD/qwaitfence_p.h \
$$PWD/qsetfence_p.h \
$$PWD/setfence_p.h \
- $$PWD/waitfence_p.h
+ $$PWD/waitfence_p.h \
+ $$PWD/qnopicking.h \
+ $$PWD/nopicking_p.h \
+ $$PWD/qsubtreeenabler.h \
+ $$PWD/qsubtreeenabler_p.h \
+ $$PWD/subtreeenabler_p.h
SOURCES += \
$$PWD/cameraselectornode.cpp \
@@ -110,4 +115,8 @@ SOURCES += \
$$PWD/qsetfence.cpp \
$$PWD/qwaitfence.cpp \
$$PWD/setfence.cpp \
- $$PWD/waitfence.cpp
+ $$PWD/waitfence.cpp \
+ $$PWD/qnopicking.cpp \
+ $$PWD/nopicking.cpp \
+ $$PWD/qsubtreeenabler.cpp \
+ $$PWD/subtreeenabler.cpp
diff --git a/src/render/framegraph/framegraphnode.cpp b/src/render/framegraph/framegraphnode.cpp
index 16f54df3b..58ff05dc0 100644
--- a/src/render/framegraph/framegraphnode.cpp
+++ b/src/render/framegraph/framegraphnode.cpp
@@ -41,7 +41,6 @@
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -66,13 +65,6 @@ FrameGraphNode::~FrameGraphNode()
{
}
-void FrameGraphNode::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- // Set up the parent child relationship and enabled state
- const auto creationChange = qSharedPointerCast<QFrameGraphNodeCreatedChangeBase>(change);
- setParentId(creationChange->parentFrameGraphNodeId());
-}
-
void FrameGraphNode::setFrameGraphManager(FrameGraphManager *manager)
{
if (m_manager != manager)
@@ -128,34 +120,33 @@ QVector<FrameGraphNode *> FrameGraphNode::children() const
return children;
}
-void FrameGraphNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void FrameGraphNode::cleanup()
{
- switch (e->type()) {
-
- case Qt3DCore::PropertyUpdated: {
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) {
- d_func()->m_enabled = propertyChange->value().toBool();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("parentFrameGraphUpdated")) {
- auto newParent = propertyChange->value().value<Qt3DCore::QNodeId>();
- setParentId(newParent);
- markDirty(AbstractRenderer::AllDirty);
- }
- break;
- }
- default:
- markDirty(AbstractRenderer::AllDirty);
- break;
- }
+ setParentId({});
}
-void FrameGraphNode::cleanup()
+void FrameGraphNode::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- setParentId({});
+ const QFrameGraphNode *node = qobject_cast<const QFrameGraphNode *>(frontEnd);
+
+ const auto parentId = Qt3DCore::qIdForNode(node->parentFrameGraphNode());
+ if (parentId != m_parentId) {
+ setParentId(parentId);
+ // TO DO: Check if FrameGraphDirty wouldn't be enough here
+ markDirty(AbstractRenderer::AllDirty);
+ }
+
+ if (node->isEnabled() != d_func()->m_enabled) {
+ d_func()->m_enabled = node->isEnabled();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ if (firstTime)
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/framegraph/framegraphnode_p.h b/src/render/framegraph/framegraphnode_p.h
index 6aa3b3d6d..846dc8060 100644
--- a/src/render/framegraph/framegraphnode_p.h
+++ b/src/render/framegraph/framegraphnode_p.h
@@ -90,7 +90,7 @@ public:
Viewport,
ClearBuffers,
SortMethod,
- SubtreeSelector,
+ SubtreeEnabler,
StateSet,
NoDraw,
FrustumCulling,
@@ -103,7 +103,8 @@ public:
ProximityFilter,
BlitFramebuffer,
SetFence,
- WaitFence
+ WaitFence,
+ NoPicking
};
FrameGraphNodeType nodeType() const { return m_nodeType; }
@@ -120,11 +121,10 @@ public:
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
protected:
FrameGraphNode(FrameGraphNodeType nodeType, QBackendNode::Mode mode = QBackendNode::ReadOnly);
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) override;
private:
FrameGraphNodeType m_nodeType;
diff --git a/src/render/framegraph/framegraphvisitor.cpp b/src/render/framegraph/framegraphvisitor.cpp
index cd8b08219..9af0297a0 100644
--- a/src/render/framegraph/framegraphvisitor.cpp
+++ b/src/render/framegraph/framegraphvisitor.cpp
@@ -41,6 +41,7 @@
#include "framegraphvisitor_p.h"
#include "framegraphnode_p.h"
+#include "subtreeenabler_p.h"
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/managers_p.h>
#include <QThreadPool>
@@ -61,6 +62,7 @@ FrameGraphVisitor::FrameGraphVisitor(const FrameGraphManager *manager)
QVector<FrameGraphNode *> FrameGraphVisitor::traverse(FrameGraphNode *root)
{
m_leaves.clear();
+ m_enablersToDisable.clear();
Q_ASSERT_X(root, Q_FUNC_INFO, "The FrameGraphRoot is null");
@@ -72,12 +74,23 @@ QVector<FrameGraphNode *> FrameGraphVisitor::traverse(FrameGraphNode *root)
return m_leaves;
}
+// intended to be called after traverse
+// (returns data that is captured during the traverse)
+QVector<FrameGraphNode *> &&FrameGraphVisitor::takeEnablersToDisable()
+{
+ return std::move(m_enablersToDisable);
+}
+
void FrameGraphVisitor::visit(Render::FrameGraphNode *node)
{
- // TO DO: check if node is a subtree selector
- // in which case, we only visit the subtrees returned
- // by the selector functor and not all the children
- // as we would otherwise do
+ if (node->nodeType() == Render::FrameGraphNode::SubtreeEnabler) {
+ if (!node->isEnabled())
+ return;
+ if (static_cast<SubtreeEnabler*>(node)->enablement() == QSubtreeEnabler::SingleShot) {
+ node->setEnabled(false);
+ m_enablersToDisable.push_back(node);
+ }
+ }
// Recurse to children (if we have any), otherwise if this is a leaf node,
// initiate a rendering from the current camera
diff --git a/src/render/framegraph/framegraphvisitor_p.h b/src/render/framegraph/framegraphvisitor_p.h
index f4c0d7796..5706a169d 100644
--- a/src/render/framegraph/framegraphvisitor_p.h
+++ b/src/render/framegraph/framegraphvisitor_p.h
@@ -72,12 +72,14 @@ public:
explicit FrameGraphVisitor(const FrameGraphManager *nodeManager);
QVector<FrameGraphNode *> traverse(FrameGraphNode *root);
+ QVector<FrameGraphNode *> &&takeEnablersToDisable();
private:
void visit(Render::FrameGraphNode *node);
const FrameGraphManager *m_manager;
QVector<FrameGraphNode *> m_leaves;
+ QVector<FrameGraphNode *> m_enablersToDisable;
};
} // namespace Render
diff --git a/src/render/framegraph/frustumculling.cpp b/src/render/framegraph/frustumculling.cpp
index 9f38d6be9..cf3a4ec57 100644
--- a/src/render/framegraph/frustumculling.cpp
+++ b/src/render/framegraph/frustumculling.cpp
@@ -39,7 +39,6 @@
#include "frustumculling_p.h"
#include <Qt3DRender/qfrustumculling.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/framegraph/layerfilternode.cpp b/src/render/framegraph/layerfilternode.cpp
index f9881be0d..f50fc1306 100644
--- a/src/render/framegraph/layerfilternode.cpp
+++ b/src/render/framegraph/layerfilternode.cpp
@@ -40,9 +40,7 @@
#include "layerfilternode_p.h"
#include "qlayerfilter.h"
#include <Qt3DRender/private/qlayerfilter_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -57,48 +55,25 @@ LayerFilterNode::LayerFilterNode()
{
}
-void LayerFilterNode::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void LayerFilterNode::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QLayerFilterData>>(change);
- const auto &data = typedChange->data;
- setLayerIds(data.layerIds);
- m_filterMode = data.filterMode;
-}
+ const QLayerFilter *node = qobject_cast<const QLayerFilter *>(frontEnd);
+ if (!node)
+ return;
-void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("layer"))
- m_layerIds.append(change->addedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::LayersDirty);
- break;
- }
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("layer"))
- m_layerIds.removeOne(change->removedNodeId());
+ if (m_filterMode != node->filterMode()) {
+ m_filterMode = node->filterMode();
markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::LayersDirty);
- break;
}
- case PropertyUpdated: {
- const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("filterMode")) {
- m_filterMode = static_cast<QLayerFilter::FilterMode>(change->value().value<int>());
- markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::LayersDirty);
- break;
- }
- }
-
- default:
- break;
+ auto layerIds = qIdsForNodes(node->layers());
+ std::sort(std::begin(layerIds), std::end(layerIds));
+ if (m_layerIds != layerIds) {
+ m_layerIds = layerIds;
+ markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::LayersDirty);
}
-
- FrameGraphNode::sceneChangeEvent(e);
}
QNodeIdVector LayerFilterNode::layerIds() const
diff --git a/src/render/framegraph/layerfilternode_p.h b/src/render/framegraph/layerfilternode_p.h
index 18ba4ee7a..27cdc49d3 100644
--- a/src/render/framegraph/layerfilternode_p.h
+++ b/src/render/framegraph/layerfilternode_p.h
@@ -53,6 +53,7 @@
#include <Qt3DRender/private/framegraphnode_p.h>
#include <Qt3DRender/QLayerFilter>
+#include <Qt3DRender/QLayer>
#include <QStringList>
QT_BEGIN_NAMESPACE
@@ -68,15 +69,14 @@ class LayerFilterNode : public FrameGraphNode
public:
LayerFilterNode();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+
Qt3DCore::QNodeIdVector layerIds() const;
void setLayerIds(const Qt3DCore::QNodeIdVector &list);
QLayerFilter::FilterMode filterMode() const;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
Qt3DCore::QNodeIdVector m_layerIds;
QLayerFilter::FilterMode m_filterMode;
};
diff --git a/src/render/framegraph/memorybarrier.cpp b/src/render/framegraph/memorybarrier.cpp
index 59b3071ab..bcc81464a 100644
--- a/src/render/framegraph/memorybarrier.cpp
+++ b/src/render/framegraph/memorybarrier.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "memorybarrier_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/qmemorybarrier_p.h>
QT_BEGIN_NAMESPACE
@@ -62,24 +61,18 @@ QMemoryBarrier::Operations MemoryBarrier::waitOperations() const
return m_waitOperations;
}
-void MemoryBarrier::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void MemoryBarrier::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- if (e->type() == Qt3DCore::PropertyUpdated) {
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("waitOperations")) {
- m_waitOperations = propertyChange->value().value<QMemoryBarrier::Operations>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- }
- FrameGraphNode::sceneChangeEvent(e);
-}
+ const QMemoryBarrier *node = qobject_cast<const QMemoryBarrier *>(frontEnd);
+ if (!node)
+ return;
-void MemoryBarrier::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QMemoryBarrierData>>(change);
- const QMemoryBarrierData &data = typedChange->data;
- m_waitOperations = data.waitOperations;
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (node->waitOperations() != m_waitOperations) {
+ m_waitOperations = node->waitOperations();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
} // Render
diff --git a/src/render/framegraph/memorybarrier_p.h b/src/render/framegraph/memorybarrier_p.h
index e0fd3e9cd..ce545cd09 100644
--- a/src/render/framegraph/memorybarrier_p.h
+++ b/src/render/framegraph/memorybarrier_p.h
@@ -67,10 +67,9 @@ public:
~MemoryBarrier();
QMemoryBarrier::Operations waitOperations() const;
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
QMemoryBarrier::Operations m_waitOperations;
};
diff --git a/src/render/framegraph/nodraw.cpp b/src/render/framegraph/nodraw.cpp
index f2020d7ce..f64eb92d7 100644
--- a/src/render/framegraph/nodraw.cpp
+++ b/src/render/framegraph/nodraw.cpp
@@ -39,7 +39,6 @@
#include "nodraw_p.h"
#include <Qt3DRender/qnodraw.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/renderers/opengl/renderer/glcommands.cpp b/src/render/framegraph/nopicking.cpp
index fd7ee9fe8..e36e2894b 100644
--- a/src/render/renderers/opengl/renderer/glcommands.cpp
+++ b/src/render/framegraph/nopicking.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -37,31 +37,25 @@
**
****************************************************************************/
-#include "glcommands_p.h"
-#include <Qt3DRender/private/renderer_p.h>
-#include <Qt3DRender/private/graphicscontext_p.h>
-#include <Qt3DRender/private/nodemanagers_p.h>
+#include "nopicking_p.h"
QT_BEGIN_NAMESPACE
-namespace Qt3DRender {
+using namespace Qt3DCore;
+namespace Qt3DRender {
namespace Render {
-LoadShaderCommand::LoadShaderCommand(Shader *shader)
- : m_shader(shader)
+NoPicking::NoPicking()
+ : FrameGraphNode(FrameGraphNode::NoPicking)
{
- Q_ASSERT(m_shader);
}
-void LoadShaderCommand::execute(Renderer *renderer, GraphicsContext *ctx)
+NoPicking::~NoPicking()
{
- NodeManagers *nodeManagers = renderer->nodeManagers();
- ctx->loadShader(m_shader, nodeManagers->shaderManager());
}
} // Render
-
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/renderers/opengl/renderer/glcommands_p.h b/src/render/framegraph/nopicking_p.h
index 5ed360759..4ecf6e33b 100644
--- a/src/render/renderers/opengl/renderer/glcommands_p.h
+++ b/src/render/framegraph/nopicking_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -37,9 +37,8 @@
**
****************************************************************************/
-#ifndef QT3DRENDER_RENDER_GLCOMMANDS_P_H
-#define QT3DRENDER_RENDER_GLCOMMANDS_P_H
-
+#ifndef QT3DRENDER_RENDER_NOPICKING_P_H
+#define QT3DRENDER_RENDER_NOPICKING_P_H
//
// W A R N I N G
// -------------
@@ -51,39 +50,25 @@
// We mean it.
//
-#include <Qt3DRender/qt3drender_global.h>
+#include <Qt3DRender/private/framegraphnode_p.h>
QT_BEGIN_NAMESPACE
-
namespace Qt3DRender {
namespace Render {
-class GraphicsContext;
-class Renderer;
-class Shader;
-
-class GLCommand
+class Q_AUTOTEST_EXPORT NoPicking : public FrameGraphNode
{
public:
- virtual void execute(Renderer *renderer, GraphicsContext *ctx) = 0;
+ NoPicking();
+ ~NoPicking();
};
-class Q_AUTOTEST_EXPORT LoadShaderCommand : public GLCommand
-{
-public:
- explicit LoadShaderCommand(Shader *shader);
- Shader *shader() const { return m_shader; }
- void execute(Renderer *renderer, GraphicsContext *ctx) Q_DECL_OVERRIDE;
-
-private:
- Shader *m_shader = nullptr;
-};
} // Render
} // Qt3DRender
QT_END_NAMESPACE
-#endif // QT3DRENDER_RENDER_GLCOMMANDS_P_H
+#endif // QT3DRENDER_RENDER_NOPICKING_P_H
diff --git a/src/render/framegraph/proximityfilter.cpp b/src/render/framegraph/proximityfilter.cpp
index cdfd7e51e..03dd2a7ec 100644
--- a/src/render/framegraph/proximityfilter.cpp
+++ b/src/render/framegraph/proximityfilter.cpp
@@ -39,7 +39,6 @@
#include "proximityfilter_p.h"
#include <Qt3DRender/private/qproximityfilter_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -53,29 +52,24 @@ ProximityFilter::ProximityFilter()
{
}
-void ProximityFilter::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void ProximityFilter::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QProximityFilterData>>(change);
- const QProximityFilterData &data = typedChange->data;
- m_entityId = data.entityId;
- m_distanceThreshold = data.distanceThreshold;
-}
+ const QProximityFilter *node = qobject_cast<const QProximityFilter *>(frontEnd);
+ if (!node)
+ return;
-void ProximityFilter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- qCDebug(Render::Framegraph) << Q_FUNC_INFO;
- if (e->type() == Qt3DCore::PropertyUpdated) {
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("entity")) {
- m_entityId = propertyChange->value().value<Qt3DCore::QNodeId>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("distanceThreshold")) {
- m_distanceThreshold = propertyChange->value().toFloat();
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const auto entityId = Qt3DCore::qIdForNode(node->entity());
+ if (entityId != m_entityId) {
+ m_entityId = entityId;
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ if (node->distanceThreshold() != m_distanceThreshold) {
+ m_distanceThreshold = node->distanceThreshold();
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
- FrameGraphNode::sceneChangeEvent(e);
}
} // namespace Render
diff --git a/src/render/framegraph/proximityfilter_p.h b/src/render/framegraph/proximityfilter_p.h
index e57b53dea..5c2f7ad66 100644
--- a/src/render/framegraph/proximityfilter_p.h
+++ b/src/render/framegraph/proximityfilter_p.h
@@ -64,7 +64,7 @@ class Q_AUTOTEST_EXPORT ProximityFilter : public FrameGraphNode
public:
ProximityFilter();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
float distanceThreshold() const { return m_distanceThreshold; }
Qt3DCore::QNodeId entityId() const { return m_entityId; }
@@ -76,8 +76,6 @@ public:
#endif
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
float m_distanceThreshold;
Qt3DCore::QNodeId m_entityId;
};
diff --git a/src/render/framegraph/qblitframebuffer.cpp b/src/render/framegraph/qblitframebuffer.cpp
index d0e1bdbf3..3a26e3d56 100644
--- a/src/render/framegraph/qblitframebuffer.cpp
+++ b/src/render/framegraph/qblitframebuffer.cpp
@@ -40,7 +40,6 @@
#include "qblitframebuffer.h"
#include "qblitframebuffer_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
QT_BEGIN_NAMESPACE
@@ -364,6 +363,7 @@ void QBlitFramebuffer::setDestination(QRenderTarget *destination)
}
}
+// TO DO Qt6: convert QRectF to QRect
/*!
Sets the source rectangle to \a inputRect. The coordinates are assumed to
follow the normal Qt coordinate system, meaning Y runs from top to bottom.
diff --git a/src/render/framegraph/qbuffercapture.cpp b/src/render/framegraph/qbuffercapture.cpp
index d1d301077..0c12a3aff 100644
--- a/src/render/framegraph/qbuffercapture.cpp
+++ b/src/render/framegraph/qbuffercapture.cpp
@@ -40,7 +40,6 @@
#include <Qt3DRender/qbuffercapture.h>
#include <Qt3DRender/private/qbuffercapture_p.h>
#include <Qt3DCore/QSceneChange>
-#include <Qt3DCore/QPropertyUpdatedChange>
#include <Qt3DRender/QFrameGraphNodeCreatedChange>
QT_BEGIN_NAMESPACE
diff --git a/src/render/framegraph/qcameraselector.cpp b/src/render/framegraph/qcameraselector.cpp
index 45abf638e..af293dc56 100644
--- a/src/render/framegraph/qcameraselector.cpp
+++ b/src/render/framegraph/qcameraselector.cpp
@@ -41,7 +41,6 @@
#include "qcameraselector_p.h"
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/private/qentity_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/framegraph/qclearbuffers.cpp b/src/render/framegraph/qclearbuffers.cpp
index 4cc4c98b6..31a31420c 100644
--- a/src/render/framegraph/qclearbuffers.cpp
+++ b/src/render/framegraph/qclearbuffers.cpp
@@ -39,7 +39,6 @@
#include "qclearbuffers.h"
#include "qclearbuffers_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/framegraph/qframegraphnode.cpp b/src/render/framegraph/qframegraphnode.cpp
index d52b728a8..2390cb1c9 100644
--- a/src/render/framegraph/qframegraphnode.cpp
+++ b/src/render/framegraph/qframegraphnode.cpp
@@ -40,7 +40,6 @@
#include "qframegraphnode.h"
#include "qframegraphnode_p.h"
#include <Qt3DRender/qframegraphnodecreatedchange.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/QNode>
@@ -258,13 +257,9 @@ Qt3DCore::QNodeCreatedChangeBasePtr QFrameGraphNode::createNodeCreationChange()
void QFrameGraphNode::onParentChanged(QObject *)
{
- const auto parentID = parentFrameGraphNode() ? parentFrameGraphNode()->id() : Qt3DCore::QNodeId();
- auto parentChange = Qt3DCore::QPropertyUpdatedChangePtr::create(id());
- parentChange->setPropertyName("parentFrameGraphUpdated");
- parentChange->setValue(QVariant::fromValue(parentID));
- const bool blocked = blockNotifications(false);
- notifyObservers(parentChange);
- blockNotifications(blocked);
+ // Direct sync update request
+ Q_D(QFrameGraphNode);
+ d->update();
}
} // namespace Qt3DRender
diff --git a/src/render/framegraph/qlayerfilter.cpp b/src/render/framegraph/qlayerfilter.cpp
index 04ebca572..8bad46f5d 100644
--- a/src/render/framegraph/qlayerfilter.cpp
+++ b/src/render/framegraph/qlayerfilter.cpp
@@ -40,9 +40,6 @@
#include "qlayerfilter.h"
#include "qlayerfilter_p.h"
#include "qlayer.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
QT_BEGIN_NAMESPACE
@@ -206,11 +203,7 @@ void QLayerFilter::addLayer(QLayer *layer)
if (!layer->parent())
layer->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(id(), layer);
- change->setPropertyName("layer");
- d->notifyObservers(change);
- }
+ d->updateNode(layer, "layer", Qt3DCore::PropertyValueAdded);
}
}
@@ -221,11 +214,7 @@ void QLayerFilter::removeLayer(QLayer *layer)
{
Q_ASSERT(layer);
Q_D(QLayerFilter);
- if (d->m_changeArbiter != nullptr) {
- const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(id(), layer);
- change->setPropertyName("layer");
- d->notifyObservers(change);
- }
+ d->updateNode(layer, "layer", Qt3DCore::PropertyValueRemoved);
d->m_layers.removeOne(layer);
// Remove bookkeeping connection
d->unregisterDestructionHelper(layer);
diff --git a/src/render/framegraph/qmemorybarrier.cpp b/src/render/framegraph/qmemorybarrier.cpp
index b39537dcf..5da462f1b 100644
--- a/src/render/framegraph/qmemorybarrier.cpp
+++ b/src/render/framegraph/qmemorybarrier.cpp
@@ -140,7 +140,7 @@ void QMemoryBarrier::setWaitOperations(QMemoryBarrier::Operations waitOperations
if (waitOperations != d->m_waitOperations) {
d->m_waitOperations = waitOperations;
emit waitOperationsChanged(waitOperations);
- d->notifyPropertyChange("waitOperations", QVariant::fromValue(waitOperations));
+ d->notifyPropertyChange("waitOperations", QVariant::fromValue(waitOperations)); // TODOSYNC
}
}
diff --git a/src/render/framegraph/qnopicking.cpp b/src/render/framegraph/qnopicking.cpp
new file mode 100644
index 000000000..069560175
--- /dev/null
+++ b/src/render/framegraph/qnopicking.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qnopicking.h"
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+/*!
+ \class Qt3DRender::QNoPicking
+ \inmodule Qt3DRender
+ \since 5.14
+
+ \brief When a Qt3DRender::QNoPicking node is present in a FrameGraph
+ branch, this prevents the render aspect from performing picking selection
+ for the given branch.
+
+ When disabled, a Qt3DRender::QNoPicking node won't prevent picking from
+ being performed. Toggling the enabled property is therefore a way to make a
+ Qt3DRender::QNoPicking active or inactive.
+
+ When using multiple subviewports in the FrameGraph, QNoPicking can be
+ useful to prevent picking conflicts between overlapping viewports or non
+ visual ones. It can also be used as an optimization to prevent unnecessary
+ work for hidden viewports or for sections of the scenes which don't require
+ any picking.
+
+ \code
+ Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport();
+ Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(viewport);
+ Qt3DRender::QNoPicking *noPicking = new Qt3DRender::QNoPicking(cameraSelector);
+
+ Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers(noPicking);
+ clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthBuffer);
+
+ Qt3DRender::QRenderPassFilter *mainPass = new Qt3DRender::QRenderPassFilter(cameraSelector);
+ ....
+ Qt3DRender::QRenderPassFilter *previewPass = new Qt3DRender::QRenderPassFilter(cameraSelector);
+ ....
+ \endcode
+ \sa Qt3DRender::QObjectPicker, Qt3DRender::QRayCaster, Qt3DRender::QScreenRayCaster
+ */
+
+/*!
+ \qmltype NoPicking
+ \instantiates Qt3DRender::QNoPicking
+ \inherits FrameGraphNode
+ \inqmlmodule Qt3D.Render
+ \since 5.14
+
+ \brief When a NoPicking node is present in a FrameGraph branch, this
+ prevents the render aspect from performing picking selection for the given
+ branch.
+
+ When disabled, a NoPicking node won't prevent picking from being performed.
+ Toggling the enabled property is therefore a way to make a NoPicking active
+ or inactive.
+
+ When using multiple subviewports in the FrameGraph, NoPicking can be useful
+ to prevent picking conflicts between overlapping viewports or non visual
+ ones. It can also be used as an optimization to prevent unnecessary work for
+ hidden viewports or for sections of the scenes which don't require any
+ picking.
+
+
+ \code
+
+ Viewport {
+ CameraSelector {
+ NoPicking {
+ ClearBuffers {
+ buffers: ClearBuffers.ColorDepthBuffer
+ NoDraw { } // Prevents from drawing anything
+ }
+ RenderPassFilter {
+ ...
+ }
+ RenderPassFilter {
+ ...
+ }
+ }
+ }
+ }
+
+ \endcode
+ \sa ObjectPicker, RayCaster, ScreenRayCaster
+
+*/
+
+QNoPicking::QNoPicking(Qt3DCore::QNode *parent)
+ : QFrameGraphNode(parent)
+{
+}
+
+QNoPicking::~QNoPicking()
+{
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/qnopicking.h b/src/render/framegraph/qnopicking.h
new file mode 100644
index 000000000..e3bd6e2fd
--- /dev/null
+++ b/src/render/framegraph/qnopicking.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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_QNOPICKING_H
+#define QT3DRENDER_QNOPICKING_H
+
+#include <Qt3DRender/qframegraphnode.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class Q_3DRENDERSHARED_EXPORT QNoPicking : public QFrameGraphNode
+{
+ Q_OBJECT
+public:
+ explicit QNoPicking(Qt3DCore::QNode *parent = nullptr);
+ ~QNoPicking();
+};
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QNOPICKING_H
diff --git a/src/render/framegraph/qrendercapture.cpp b/src/render/framegraph/qrendercapture.cpp
index 5bda569f9..2169f72dd 100644
--- a/src/render/framegraph/qrendercapture.cpp
+++ b/src/render/framegraph/qrendercapture.cpp
@@ -326,11 +326,9 @@ QRenderCaptureReply *QRenderCapture::requestCapture(int captureId)
d->replyDestroyed(reply);
});
- Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(id()));
- change->setPropertyName(QByteArrayLiteral("renderCaptureRequest"));
const QRenderCaptureRequest request = { captureId, QRect() };
- change->setValue(QVariant::fromValue(request));
- d->notifyObservers(change);
+ d->m_pendingRequests.push_back(request);
+ d->update();
return reply;
}
@@ -351,11 +349,9 @@ QRenderCaptureReply *QRenderCapture::requestCapture(const QRect &rect)
d->replyDestroyed(reply);
});
- Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(id()));
- change->setPropertyName(QByteArrayLiteral("renderCaptureRequest"));
const QRenderCaptureRequest request = { captureId, rect };
- change->setValue(QVariant::fromValue(request));
- d->notifyObservers(change);
+ d->m_pendingRequests.push_back(request);
+ d->update();
captureId++;
diff --git a/src/render/framegraph/qrendercapture_p.h b/src/render/framegraph/qrendercapture_p.h
index 4e509cc59..3dec4d280 100644
--- a/src/render/framegraph/qrendercapture_p.h
+++ b/src/render/framegraph/qrendercapture_p.h
@@ -57,6 +57,12 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
+struct QRenderCaptureRequest
+{
+ int captureId;
+ QRect rect;
+};
+
class QRenderCapturePrivate : public QFrameGraphNodePrivate
{
public:
@@ -64,6 +70,7 @@ public:
~QRenderCapturePrivate();
QVector<QRenderCaptureReply *> m_waitingReplies;
QMutex m_mutex;
+ mutable QVector<QRenderCaptureRequest> m_pendingRequests;
QRenderCaptureReply *createReply(int captureId);
QRenderCaptureReply *takeReply(int captureId);
@@ -82,6 +89,7 @@ public:
int m_captureId;
bool m_complete;
+
Q_DECLARE_PUBLIC(QRenderCaptureReply)
};
@@ -100,12 +108,6 @@ struct RenderCaptureData
typedef QSharedPointer<RenderCaptureData> RenderCaptureDataPtr;
-struct QRenderCaptureRequest
-{
- int captureId;
- QRect rect;
-};
-
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/framegraph/qrenderpassfilter.cpp b/src/render/framegraph/qrenderpassfilter.cpp
index 56c229d9c..952657eb6 100644
--- a/src/render/framegraph/qrenderpassfilter.cpp
+++ b/src/render/framegraph/qrenderpassfilter.cpp
@@ -42,9 +42,6 @@
#include <Qt3DRender/qfilterkey.h>
#include <Qt3DRender/qparameter.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
QT_BEGIN_NAMESPACE
@@ -142,11 +139,7 @@ void QRenderPassFilter::addMatch(QFilterKey *filterKey)
if (!filterKey->parent())
filterKey->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), filterKey);
- change->setPropertyName("match");
- d->notifyObservers(change);
- }
+ d->updateNode(filterKey, "match", Qt3DCore::PropertyValueAdded);
}
}
@@ -158,11 +151,7 @@ void QRenderPassFilter::removeMatch(QFilterKey *filterKey)
Q_ASSERT(filterKey);
Q_D(QRenderPassFilter);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), filterKey);
- change->setPropertyName("match");
- d->notifyObservers(change);
- }
+ d->updateNode(filterKey, "match", Qt3DCore::PropertyValueRemoved);
d->m_matchList.removeOne(filterKey);
// Remove bookkeeping connection
d->unregisterDestructionHelper(filterKey);
@@ -188,11 +177,7 @@ void QRenderPassFilter::addParameter(QParameter *parameter)
if (!parameter->parent())
parameter->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueAdded);
}
}
@@ -204,11 +189,7 @@ void QRenderPassFilter::removeParameter(QParameter *parameter)
Q_ASSERT(parameter);
Q_D(QRenderPassFilter);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
d->m_parameters.removeOne(parameter);
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
diff --git a/src/render/framegraph/qrenderstateset.cpp b/src/render/framegraph/qrenderstateset.cpp
index 6f70456ab..5341b3c7d 100644
--- a/src/render/framegraph/qrenderstateset.cpp
+++ b/src/render/framegraph/qrenderstateset.cpp
@@ -41,9 +41,6 @@
#include "qrenderstateset_p.h"
#include <Qt3DRender/qrenderstate.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
QT_BEGIN_NAMESPACE
@@ -194,11 +191,7 @@ void QRenderStateSet::addRenderState(QRenderState *state)
if (!state->parent())
state->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), state);
- change->setPropertyName("renderState");
- d->notifyObservers(change);
- }
+ d->updateNode(state, "renderState", Qt3DCore::PropertyValueAdded);
}
}
@@ -210,11 +203,7 @@ void QRenderStateSet::removeRenderState(QRenderState *state)
Q_ASSERT(state);
Q_D(QRenderStateSet);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), state);
- change->setPropertyName("renderState");
- d->notifyObservers(change);
- }
+ d->updateNode(state, "renderState", Qt3DCore::PropertyValueRemoved);
d->m_renderStates.removeOne(state);
// Remove bookkeeping connection
d->unregisterDestructionHelper(state);
diff --git a/src/render/framegraph/qrendersurfaceselector.cpp b/src/render/framegraph/qrendersurfaceselector.cpp
index 848d86f53..df30663cb 100644
--- a/src/render/framegraph/qrendersurfaceselector.cpp
+++ b/src/render/framegraph/qrendersurfaceselector.cpp
@@ -44,7 +44,6 @@
#include <QtGui/QScreen>
#include <QtGui/QOffscreenSurface>
#include <Qt3DCore/qentity.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qrendersettings.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
@@ -252,31 +251,17 @@ void QRenderSurfaceSelector::setSurface(QObject *surfaceObject)
d->m_surfaceEventFilter->setSurface(window);
if (window) {
- d->m_widthConn = QObject::connect(window, &QWindow::widthChanged, [=] (int width) {
- if (d->m_changeArbiter != nullptr) {
- Qt3DCore::QPropertyUpdatedChangePtr change(
- new Qt3DCore::QPropertyUpdatedChange(id()));
-
- change->setPropertyName("width");
- change->setValue(QVariant::fromValue(width));
- d->notifyObservers(change);
- }
+ d->m_widthConn = QObject::connect(window, &QWindow::widthChanged, [=] (int) {
+ d->update();
});
- d->m_heightConn = QObject::connect(window, &QWindow::heightChanged, [=] (int height) {
- if (d->m_changeArbiter != nullptr) {
- Qt3DCore::QPropertyUpdatedChangePtr change(
- new Qt3DCore::QPropertyUpdatedChange(id()));
-
- change->setPropertyName("height");
- change->setValue(QVariant::fromValue(height));
- d->notifyObservers(change);
- }
+ d->m_heightConn = QObject::connect(window, &QWindow::heightChanged, [=] (int) {
+ d->update();
});
d->m_screenConn = QObject::connect(window, &QWindow::screenChanged, [=] (QScreen *screen) {
- if (screen && surfacePixelRatio() != screen->devicePixelRatio())
- setSurfacePixelRatio(screen->devicePixelRatio());
+ if (screen && !qFuzzyCompare(surfacePixelRatio(), float(screen->devicePixelRatio())))
+ setSurfacePixelRatio(float(screen->devicePixelRatio()));
});
- setSurfacePixelRatio(window->devicePixelRatio());
+ setSurfacePixelRatio(float(window->devicePixelRatio()));
}
break;
@@ -306,7 +291,7 @@ QSize QRenderSurfaceSelector::externalRenderTargetSize() const
void QRenderSurfaceSelector::setSurfacePixelRatio(float ratio)
{
Q_D(QRenderSurfaceSelector);
- if (d->m_surfacePixelRatio == ratio)
+ if (qFuzzyCompare(d->m_surfacePixelRatio, ratio))
return;
d->m_surfacePixelRatio = ratio;
emit surfacePixelRatioChanged(ratio);
diff --git a/src/render/framegraph/qrendertargetselector.cpp b/src/render/framegraph/qrendertargetselector.cpp
index 1b4afc7e6..c997c23cc 100644
--- a/src/render/framegraph/qrendertargetselector.cpp
+++ b/src/render/framegraph/qrendertargetselector.cpp
@@ -40,7 +40,6 @@
#include "qrendertargetselector.h"
#include "qrendertargetselector_p.h"
#include <Qt3DRender/qrendertarget.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/qrenderpass_p.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
@@ -153,13 +152,7 @@ void QRenderTargetSelector::setOutputs(const QVector<QRenderTargetOutput::Attach
Q_D(QRenderTargetSelector);
if (buffers != d->m_outputs) {
d->m_outputs = buffers;
-
- if (d->m_changeArbiter) {
- auto change = QPropertyUpdatedChangePtr::create(d->m_id);
- change->setPropertyName("outputs");
- change->setValue(QVariant::fromValue(d->m_outputs));
- d->notifyObservers(change);
- }
+ d->update();
}
}
diff --git a/src/render/framegraph/qsortpolicy.cpp b/src/render/framegraph/qsortpolicy.cpp
index 6f852afbd..a24dd5eae 100644
--- a/src/render/framegraph/qsortpolicy.cpp
+++ b/src/render/framegraph/qsortpolicy.cpp
@@ -102,6 +102,8 @@ QSortPolicyPrivate::QSortPolicyPrivate()
\value FrontToBack sort the objects from front to back. The opposite of
BackToFront.
+
+ \value [since 5.14] Texture sort the objects to minimize texture changes.
*/
/*!
@@ -124,6 +126,7 @@ QSortPolicyPrivate::QSortPolicyPrivate()
\li Material - sort the objects based on their material value
\li FrontToBack - sort the objects from front to back. The opposite of
BackToFront.
+ \li [since 5.14] Texture - sort the objects to minimize texture changes.
\endlist
*/
@@ -178,7 +181,10 @@ void QSortPolicy::setSortTypes(const QVector<SortType> &sortTypes)
if (sortTypes != d->m_sortTypes) {
d->m_sortTypes = sortTypes;
emit sortTypesChanged(sortTypes);
+
+ const bool wasBlocked = blockNotifications(true);
emit sortTypesChanged(sortTypesInt());
+ blockNotifications(wasBlocked);
}
}
diff --git a/src/render/framegraph/qsortpolicy.h b/src/render/framegraph/qsortpolicy.h
index 67dfe6ac2..a302caa8b 100644
--- a/src/render/framegraph/qsortpolicy.h
+++ b/src/render/framegraph/qsortpolicy.h
@@ -60,7 +60,8 @@ public:
StateChangeCost = (1 << 0),
BackToFront = (1 << 1),
Material = (1 << 2),
- FrontToBack = (1 << 3)
+ FrontToBack = (1 << 3),
+ Texture = (1 << 4),
};
Q_ENUM(SortType) // LCOV_EXCL_LINE
diff --git a/src/render/framegraph/qsubtreeenabler.cpp b/src/render/framegraph/qsubtreeenabler.cpp
new file mode 100644
index 000000000..d2c25852b
--- /dev/null
+++ b/src/render/framegraph/qsubtreeenabler.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** 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 "qsubtreeenabler_p.h"
+#include <Qt3DRender/qframegraphnodecreatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender
+{
+
+/*!
+ \class Qt3DRender::QSubtreeEnabler
+ \inmodule Qt3DRender
+ \brief Enables or disables entire subtrees of framegraph nodes.
+ \since 5.14
+
+ While QFrameGraphNodes can be individually enabled and disabled via the
+ \c enabled property, this can become tedious when an entire path
+ needs to be turned on or off. QSubtreeEnabler is a convenience node
+ that makes this use case trivial, allowing all of its children to be
+ controlled by a single switch.
+
+ QSubtreeEnabler is enabled by default.
+*/
+
+/*!
+ \qmltype SubtreeEnabler
+ \inqmlmodule Qt3D.Render
+ \since 5.14
+ \instantiates Qt3DRender::QSubtreeEnabler
+ \inherits FrameGraphNode
+ \brief Enables or disables entire subtrees of frame graph nodes.
+
+ While FrameGraphNodes can be individually enabled and disabled via the
+ \c enabled property, this can become tedious when an entire path
+ needs to be turned on or off. SubtreeEnabler is a convenience node
+ that makes this use case trivial, allowing all of its children to be
+ controlled by a single switch.
+
+ For example, the following simplified frame graph includes a subtree for
+ debug rendering that can easily be enabled only when debugging.
+
+ \qml
+ RenderSurfaceSelector {
+ ClearBuffers {
+ Viewport {
+ CameraSelector {}
+ }
+ }
+
+ SubtreeEnabler {
+ enabled: showDebugView
+ Viewport {
+ CameraSelector {
+ RenderPassFilter {}
+ }
+ }
+ }
+ }
+ \endqml
+
+ SubtreeEnabler is enabled by default.
+ */
+
+QSubtreeEnabler::QSubtreeEnabler(Qt3DCore::QNode *parent)
+ : QFrameGraphNode(*new QSubtreeEnablerPrivate, parent)
+{
+}
+
+QSubtreeEnabler::~QSubtreeEnabler()
+{
+}
+
+/*!
+ \enum QSubtreeEnabler::Enablement
+
+ Specifies whether subtree enablement is persistent or transient.
+
+ \value Persistent
+ The value of enabled is persistent. This is the default.
+
+ \value SingleShot
+ The value of enabled will last for a single frame and then be reset to false.
+ This might be used for a subtree drawing to an FBO, for example, to only update
+ the FBO when the relevant portions of the scene changed.
+*/
+
+/*!
+ \qmlproperty enumeration Qt3D.Render::SubtreeEnabler::enablement
+ Controls whether subtree enablement is persistent or transient.
+
+ \value Persistent
+ The value of enabled is persistent. This is the default.
+
+ \value SingleShot
+ The value of enabled will last for a single frame and then be reset to false.
+ This might be used for a subtree drawing to an FBO, for example, to only update
+ the FBO when the relevant portions of the scene changed.
+*/
+
+/*!
+ \property Qt3DRender::QSubtreeEnabler::enablement
+ Controls whether subtree enablement is persistent or transient.
+*/
+QSubtreeEnabler::Enablement QSubtreeEnabler::enablement() const
+{
+ Q_D(const QSubtreeEnabler);
+ return d->m_enablement;
+}
+
+void QSubtreeEnabler::setEnablement(QSubtreeEnabler::Enablement enablement)
+{
+ Q_D(QSubtreeEnabler);
+ if (d->m_enablement == enablement)
+ return;
+ d->m_enablement = enablement;
+ emit enablementChanged(d->m_enablement);
+}
+
+/*!
+ \qmlmethod void Qt3D.Render::SubtreeEnabler::requestUpdate()
+ Requests that the subtree be enabled.
+
+ A conveninence method intended to be used with \c SingleShot enablement.
+ */
+
+/*!
+ Requests that the subtree be enabled.
+
+ A conveninence method intended to be used with \c SingleShot enablement.
+ */
+void QSubtreeEnabler::requestUpdate()
+{
+ setEnabled(true);
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QSubtreeEnabler::createNodeCreationChange() const
+{
+ auto creationChange = QFrameGraphNodeCreatedChangePtr<QSubtreeEnablerData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QSubtreeEnabler);
+ data.enablement = d->m_enablement;
+ return creationChange;
+}
+
+} //Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/qsubtreeenabler.h b/src/render/framegraph/qsubtreeenabler.h
new file mode 100644
index 000000000..558e3b8b7
--- /dev/null
+++ b/src/render/framegraph/qsubtreeenabler.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** 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_QSUBTREEENABLER_H
+#define QT3DRENDER_QSUBTREEENABLER_H
+
+#include <Qt3DRender/QFrameGraphNode>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender
+{
+
+class QSubtreeEnablerPrivate;
+
+class Q_3DRENDERSHARED_EXPORT QSubtreeEnabler : public QFrameGraphNode
+{
+ Q_OBJECT
+ Q_PROPERTY(Enablement enablement READ enablement WRITE setEnablement NOTIFY enablementChanged)
+public:
+ explicit QSubtreeEnabler(Qt3DCore::QNode *parent = nullptr);
+ ~QSubtreeEnabler();
+
+ enum Enablement {
+ Persistent,
+ SingleShot
+ };
+ Q_ENUM(Enablement)
+
+ Enablement enablement() const;
+ void setEnablement(Enablement enablement);
+
+ Q_INVOKABLE void requestUpdate();
+
+Q_SIGNALS:
+ void enablementChanged(Qt3DRender::QSubtreeEnabler::Enablement enablement);
+
+private:
+ Q_DECLARE_PRIVATE(QSubtreeEnabler)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} //Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSUBTREEENABLER_H
diff --git a/src/render/framegraph/qsubtreeenabler_p.h b/src/render/framegraph/qsubtreeenabler_p.h
new file mode 100644
index 000000000..72354fe89
--- /dev/null
+++ b/src/render/framegraph/qsubtreeenabler_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** 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_QSUBTREEENABLER_P_H
+#define QT3DRENDER_QSUBTREEENABLER_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 "qsubtreeenabler.h"
+#include <private/qframegraphnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QSubtreeEnablerPrivate : public QFrameGraphNodePrivate
+{
+public:
+ QSubtreeEnablerPrivate() = default;
+
+ QSubtreeEnabler::Enablement m_enablement = QSubtreeEnabler::Persistent;
+
+ Q_DECLARE_PUBLIC(QSubtreeEnabler)
+};
+
+struct QSubtreeEnablerData
+{
+ QSubtreeEnabler::Enablement enablement;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSUBTREEENABLER_P_H
diff --git a/src/render/framegraph/qtechniquefilter.cpp b/src/render/framegraph/qtechniquefilter.cpp
index 404ad6991..c22e83381 100644
--- a/src/render/framegraph/qtechniquefilter.cpp
+++ b/src/render/framegraph/qtechniquefilter.cpp
@@ -41,9 +41,6 @@
#include "qtechniquefilter_p.h"
#include <Qt3DRender/qfilterkey.h>
#include <Qt3DRender/qparameter.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
QT_BEGIN_NAMESPACE
@@ -147,11 +144,7 @@ void QTechniqueFilter::addMatch(QFilterKey *filterKey)
if (!filterKey->parent())
filterKey->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), filterKey);
- change->setPropertyName("matchAll");
- d->notifyObservers(change);
- }
+ d->updateNode(filterKey, "matchAll", Qt3DCore::PropertyValueAdded);
}
}
@@ -162,11 +155,7 @@ void QTechniqueFilter::removeMatch(QFilterKey *filterKey)
{
Q_ASSERT(filterKey);
Q_D(QTechniqueFilter);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), filterKey);
- change->setPropertyName("matchAll");
- d->notifyObservers(change);
- }
+ d->updateNode(filterKey, "matchAll", Qt3DCore::PropertyValueRemoved);
d->m_matchList.removeOne(filterKey);
// Remove bookkeeping connection
d->unregisterDestructionHelper(filterKey);
@@ -192,11 +181,7 @@ void QTechniqueFilter::addParameter(QParameter *parameter)
if (!parameter->parent())
parameter->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueAdded);
}
}
@@ -207,11 +192,7 @@ void QTechniqueFilter::removeParameter(QParameter *parameter)
{
Q_ASSERT(parameter);
Q_D(QTechniqueFilter);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
d->m_parameters.removeOne(parameter);
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
diff --git a/src/render/framegraph/qviewport.cpp b/src/render/framegraph/qviewport.cpp
index 539e02d65..34716c5b5 100644
--- a/src/render/framegraph/qviewport.cpp
+++ b/src/render/framegraph/qviewport.cpp
@@ -40,7 +40,6 @@
#include "qviewport.h"
#include "qviewport_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/framegraph/rendercapture.cpp b/src/render/framegraph/rendercapture.cpp
index 166294889..68d62b6a5 100644
--- a/src/render/framegraph/rendercapture.cpp
+++ b/src/render/framegraph/rendercapture.cpp
@@ -70,16 +70,23 @@ QRenderCaptureRequest RenderCapture::takeCaptureRequest()
return m_requestedCaptures.takeFirst();
}
-void RenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void RenderCapture::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- if (e->type() == Qt3DCore::PropertyUpdated) {
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("renderCaptureRequest")) {
- requestCapture(propertyChange->value().value<QRenderCaptureRequest>());
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
+ const QRenderCapture *node = qobject_cast<const QRenderCapture *>(frontEnd);
+ if (!node)
+ return;
+
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const QRenderCapturePrivate *d = static_cast<const QRenderCapturePrivate *>(QFrameGraphNodePrivate::get(node));
+ const auto newPendingsCaptures = std::move(d->m_pendingRequests);
+ if (newPendingsCaptures.size() > 0) {
+ m_requestedCaptures.append(newPendingsCaptures);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
- FrameGraphNode::sceneChangeEvent(e);
+
+ if (firstTime)
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
// called by render thread
diff --git a/src/render/framegraph/rendercapture_p.h b/src/render/framegraph/rendercapture_p.h
index 71fa01ec1..4560c525d 100644
--- a/src/render/framegraph/rendercapture_p.h
+++ b/src/render/framegraph/rendercapture_p.h
@@ -68,8 +68,7 @@ public:
void addRenderCapture(int captureId, const QImage &image);
void sendRenderCaptures();
-protected:
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) final;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
private:
diff --git a/src/render/framegraph/renderpassfilternode.cpp b/src/render/framegraph/renderpassfilternode.cpp
index e3da1e36d..bcec38fb6 100644
--- a/src/render/framegraph/renderpassfilternode.cpp
+++ b/src/render/framegraph/renderpassfilternode.cpp
@@ -42,9 +42,6 @@
#include "qrenderpassfilter.h"
#include <Qt3DRender/private/qrenderpassfilter_p.h>
#include <Qt3DRender/qparameter.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
QT_BEGIN_NAMESPACE
@@ -58,16 +55,33 @@ RenderPassFilter::RenderPassFilter()
{
}
-void RenderPassFilter::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void RenderPassFilter::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QRenderPassFilterData>>(change);
- const auto &data = typedChange->data;
- m_filters = data.matchIds;
- m_parameterPack.clear();
- m_parameterPack.setParameters(data.parameterIds);
+ const QRenderPassFilter *node = qobject_cast<const QRenderPassFilter *>(frontEnd);
+ if (!node)
+ return;
+
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (firstTime)
+ m_parameterPack.clear();
+
+ auto parameters = qIdsForNodes(node->parameters());
+ std::sort(std::begin(parameters), std::end(parameters));
+ if (m_parameterPack.parameters() != parameters) {
+ m_parameterPack.setParameters(parameters);
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ auto filterIds = qIdsForNodes(node->matchAny());
+ std::sort(std::begin(filterIds), std::end(filterIds));
+ if (m_filters != filterIds) {
+ m_filters = filterIds;
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
+
QVector<Qt3DCore::QNodeId> RenderPassFilter::filters() const
{
return m_filters;
@@ -89,40 +103,6 @@ QVector<Qt3DCore::QNodeId> RenderPassFilter::parameters() const
return m_parameterPack.parameters();
}
-void RenderPassFilter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
-
- switch (e->type()) {
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("match")) {
- appendFilter(change->addedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (change->propertyName() == QByteArrayLiteral("parameter")) {
- m_parameterPack.appendParameter(change->addedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- break;
- }
-
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("match")) {
- removeFilter(change->removedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (change->propertyName() == QByteArrayLiteral("parameter")) {
- m_parameterPack.removeParameter(change->removedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- break;
- }
-
- default:
- break;
- }
- FrameGraphNode::sceneChangeEvent(e);
-}
-
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/framegraph/renderpassfilternode_p.h b/src/render/framegraph/renderpassfilternode_p.h
index 398d42049..157a162bb 100644
--- a/src/render/framegraph/renderpassfilternode_p.h
+++ b/src/render/framegraph/renderpassfilternode_p.h
@@ -76,11 +76,9 @@ public:
QVector<Qt3DCore::QNodeId> parameters() const;
void appendFilter(Qt3DCore::QNodeId criterionId);
void removeFilter(Qt3DCore::QNodeId criterionId);
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QVector<Qt3DCore::QNodeId> m_filters;
ParameterPack m_parameterPack;
};
diff --git a/src/render/framegraph/rendersurfaceselector.cpp b/src/render/framegraph/rendersurfaceselector.cpp
index 16a1199b5..a1e639df5 100644
--- a/src/render/framegraph/rendersurfaceselector.cpp
+++ b/src/render/framegraph/rendersurfaceselector.cpp
@@ -40,7 +40,6 @@
#include "rendersurfaceselector_p.h"
#include <Qt3DRender/qrendersurfaceselector.h>
#include <Qt3DRender/private/qrendersurfaceselector_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <QtGui/qwindow.h>
#include <QtGui/qscreen.h>
@@ -73,6 +72,7 @@ namespace Render {
RenderSurfaceSelector::RenderSurfaceSelector()
: FrameGraphNode(FrameGraphNode::Surface)
+ , m_surfaceObj(nullptr)
, m_surface(nullptr)
, m_width(0)
, m_height(0)
@@ -80,57 +80,48 @@ RenderSurfaceSelector::RenderSurfaceSelector()
{
}
-void RenderSurfaceSelector::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void RenderSurfaceSelector::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QRenderSurfaceSelectorData>>(change);
- const auto &data = typedChange->data;
- m_surface = surfaceFromQObject(data.surface);
- m_renderTargetSize = data.externalRenderTargetSize;
- m_devicePixelRatio = data.surfacePixelRatio;
+ const QRenderSurfaceSelector *node = qobject_cast<const QRenderSurfaceSelector *>(frontEnd);
+ if (!node)
+ return;
- if (m_surface && m_surface->surfaceClass() == QSurface::Window) {
- QWindow *window = static_cast<QWindow *>(m_surface);
- m_width = window->width();
- m_height = window->height();
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (node->surface() != m_surfaceObj) {
+ m_surfaceObj = node->surface();
+ m_surface = surfaceFromQObject(m_surfaceObj);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
-}
-void RenderSurfaceSelector::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- qCDebug(Render::Framegraph) << Q_FUNC_INFO;
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("surface")) {
- m_surface = surfaceFromQObject(propertyChange->value().value<QObject *>());
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("externalRenderTargetSize")) {
- setRenderTargetSize(propertyChange->value().toSize());
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("width")) {
- m_width = propertyChange->value().toInt();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("height")) {
- m_height = propertyChange->value().toInt();
+ if (m_surface && m_surface->surfaceClass() == QSurface::Window) {
+ QWindow *window = static_cast<QWindow *>(m_surface);
+ if (window->width() != m_width) {
+ m_width = window->width();
markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("surfacePixelRatio")) {
- m_devicePixelRatio = propertyChange->value().toFloat();
+ }
+ if (window->height() != m_height) {
+ m_height = window->height();
markDirty(AbstractRenderer::FrameGraphDirty);
}
}
- FrameGraphNode::sceneChangeEvent(e);
+
+ if (node->externalRenderTargetSize() != m_renderTargetSize) {
+ m_renderTargetSize = node->externalRenderTargetSize();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ if (node->surfacePixelRatio() != m_devicePixelRatio) {
+ m_devicePixelRatio = node->surfacePixelRatio();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
QSize RenderSurfaceSelector::renderTargetSize() const
{
if (m_renderTargetSize.isValid())
return m_renderTargetSize;
- {
- SurfaceLocker lock(m_surface);
- if (lock.isSurfaceValid() && m_surface && m_surface->size().isValid())
- return m_surface->size();
- }
- return QSize();
+ return QSize(m_width, m_height);
}
} // namespace Render
diff --git a/src/render/framegraph/rendersurfaceselector_p.h b/src/render/framegraph/rendersurfaceselector_p.h
index 74863aa36..f1a139e84 100644
--- a/src/render/framegraph/rendersurfaceselector_p.h
+++ b/src/render/framegraph/rendersurfaceselector_p.h
@@ -68,7 +68,7 @@ public:
QSize renderTargetSize() const;
void setRenderTargetSize(const QSize &size) { m_renderTargetSize = size; }
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
QSurface *surface() const { return m_surface; }
inline int width() const Q_DECL_NOTHROW { return m_width; }
@@ -76,8 +76,7 @@ public:
inline float devicePixelRatio() const Q_DECL_NOTHROW { return m_devicePixelRatio; }
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
+ QObject *m_surfaceObj;
QSurface *m_surface;
QSize m_renderTargetSize;
int m_width;
diff --git a/src/render/framegraph/rendertargetselectornode.cpp b/src/render/framegraph/rendertargetselectornode.cpp
index 615608bd2..614a749a5 100644
--- a/src/render/framegraph/rendertargetselectornode.cpp
+++ b/src/render/framegraph/rendertargetselectornode.cpp
@@ -43,7 +43,6 @@
#include <Qt3DRender/qrendertargetselector.h>
#include <Qt3DRender/private/qrendertargetselector_p.h>
#include <Qt3DRender/qrendertarget.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DRender/qrendertargetoutput.h>
@@ -59,29 +58,24 @@ RenderTargetSelector::RenderTargetSelector() :
{
}
-void RenderTargetSelector::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void RenderTargetSelector::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QRenderTargetSelectorData>>(change);
- const auto &data = typedChange->data;
- m_renderTargetUuid = data.targetId;
- m_outputs = data.outputs;
-}
+ const QRenderTargetSelector *node = qobject_cast<const QRenderTargetSelector *>(frontEnd);
+ if (!node)
+ return;
-void RenderTargetSelector::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- qCDebug(Render::Framegraph) << Q_FUNC_INFO;
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("target")) {
- m_renderTargetUuid = propertyChange->value().value<QNodeId>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("outputs")) {
- m_outputs = propertyChange->value().value<QVector<Qt3DRender::QRenderTargetOutput::AttachmentPoint> >();
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const QNodeId renderTargetId = qIdForNode(node->target());
+ if (renderTargetId != m_renderTargetUuid) {
+ m_renderTargetUuid = renderTargetId;
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ if (node->outputs() != m_outputs) {
+ m_outputs = node->outputs();
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
- FrameGraphNode::sceneChangeEvent(e);
}
} // namespace Render
diff --git a/src/render/framegraph/rendertargetselectornode_p.h b/src/render/framegraph/rendertargetselectornode_p.h
index 81ac8a3d3..232ee9ecc 100644
--- a/src/render/framegraph/rendertargetselectornode_p.h
+++ b/src/render/framegraph/rendertargetselectornode_p.h
@@ -66,14 +66,12 @@ class RenderTargetSelector : public FrameGraphNode
public:
RenderTargetSelector();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
Qt3DCore::QNodeId renderTargetUuid() const { return m_renderTargetUuid; }
QVector<QRenderTargetOutput::AttachmentPoint> outputs() const { return m_outputs; }
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
Qt3DCore::QNodeId m_renderTargetUuid;
QVector<QRenderTargetOutput::AttachmentPoint> m_outputs;
};
diff --git a/src/render/framegraph/sortpolicy.cpp b/src/render/framegraph/sortpolicy.cpp
index b81d1f6cb..5c61966c0 100644
--- a/src/render/framegraph/sortpolicy.cpp
+++ b/src/render/framegraph/sortpolicy.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "sortpolicy_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/qsortpolicy_p.h>
QT_BEGIN_NAMESPACE
@@ -53,18 +52,19 @@ SortPolicy::SortPolicy()
{
}
-void SortPolicy::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void SortPolicy::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- if (e->type() == Qt3DCore::PropertyUpdated) {
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("sortTypes")) {
- auto sortTypesInt = propertyChange->value().value<QVector<int>>();
- m_sortTypes.clear();
- transformVector(sortTypesInt, m_sortTypes);
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
+ const QSortPolicy *node = qobject_cast<const QSortPolicy *>(frontEnd);
+ if (!node)
+ return;
+
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const auto sortTypes = node->sortTypes();
+ if (sortTypes != m_sortTypes) {
+ m_sortTypes = sortTypes;
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
- FrameGraphNode::sceneChangeEvent(e);
}
QVector<QSortPolicy::SortType> SortPolicy::sortTypes() const
@@ -72,14 +72,6 @@ QVector<QSortPolicy::SortType> SortPolicy::sortTypes() const
return m_sortTypes;
}
-void SortPolicy::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
-{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QSortPolicyData>>(change);
- const QSortPolicyData &data = typedChange->data;
- m_sortTypes = data.sortTypes;
-}
-
} // namepace Render
} // namespace Qt3DRender
diff --git a/src/render/framegraph/sortpolicy_p.h b/src/render/framegraph/sortpolicy_p.h
index ef928af7b..8d572ead7 100644
--- a/src/render/framegraph/sortpolicy_p.h
+++ b/src/render/framegraph/sortpolicy_p.h
@@ -65,13 +65,11 @@ class Q_AUTOTEST_EXPORT SortPolicy : public FrameGraphNode
public:
SortPolicy();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
QVector<Qt3DRender::QSortPolicy::SortType> sortTypes() const;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QVector<Qt3DRender::QSortPolicy::SortType> m_sortTypes;
};
diff --git a/src/render/framegraph/statesetnode.cpp b/src/render/framegraph/statesetnode.cpp
index 96551684e..c494c572b 100644
--- a/src/render/framegraph/statesetnode.cpp
+++ b/src/render/framegraph/statesetnode.cpp
@@ -43,9 +43,6 @@
#include <Qt3DRender/private/qrenderstateset_p.h>
#include <Qt3DRender/private/genericstate_p.h>
#include <Qt3DRender/private/renderstateset_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
QT_BEGIN_NAMESPACE
@@ -68,40 +65,20 @@ QVector<QNodeId> StateSetNode::renderStates() const
return m_renderStates;
}
-void StateSetNode::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void StateSetNode::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QRenderStateSetData>>(change);
- const auto &data = typedChange->data;
- for (const auto &stateId : qAsConst(data.renderStateIds))
- addRenderState(stateId);
-}
+ const QRenderStateSet *node = qobject_cast<const QRenderStateSet *>(frontEnd);
+ if (!node)
+ return;
-void StateSetNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("renderState")) {
- addRenderState(change->addedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- break;
- }
-
- case PropertyValueRemoved: {
- const auto propertyChange = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("renderState")) {
- removeRenderState(propertyChange->removedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- break;
- }
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
- default:
- break;
+ auto stateIds = qIdsForNodes(node->renderStates());
+ std::sort(std::begin(stateIds), std::end(stateIds));
+ if (m_renderStates != stateIds) {
+ m_renderStates = stateIds;
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
- FrameGraphNode::sceneChangeEvent(e);
}
void StateSetNode::addRenderState(QNodeId renderStateId)
diff --git a/src/render/framegraph/statesetnode_p.h b/src/render/framegraph/statesetnode_p.h
index d33e118cb..5081f3215 100644
--- a/src/render/framegraph/statesetnode_p.h
+++ b/src/render/framegraph/statesetnode_p.h
@@ -68,13 +68,13 @@ public:
inline bool hasRenderStates() const { return !m_renderStates.empty(); }
QVector<Qt3DCore::QNodeId> renderStates() const;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+
protected:
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
void addRenderState(Qt3DCore::QNodeId renderStateId);
void removeRenderState(Qt3DCore::QNodeId renderStateId);
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
QVector<Qt3DCore::QNodeId> m_renderStates;
};
diff --git a/src/render/jobs/loadtexturedatajob.cpp b/src/render/framegraph/subtreeenabler.cpp
index 55232d74f..160e1a5b5 100644
--- a/src/render/jobs/loadtexturedatajob.cpp
+++ b/src/render/framegraph/subtreeenabler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2019 Ford Motor Company
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -37,49 +37,56 @@
**
****************************************************************************/
-#include "loadtexturedatajob_p.h"
-#include <Qt3DRender/private/nodemanagers_p.h>
-#include <Qt3DRender/private/texturedatamanager_p.h>
-#include <Qt3DRender/qtextureimagedata.h>
-#include <Qt3DRender/private/job_common_p.h>
-#include <Qt3DRender/private/qtextureimagedata_p.h>
+#include "subtreeenabler_p.h"
+#include <Qt3DRender/private/qsubtreeenabler_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
+
namespace Render {
-LoadTextureDataJob::LoadTextureDataJob(const QTextureGeneratorPtr &texGen)
- : m_texGen(texGen)
- , m_imgDataGen(nullptr)
+SubtreeEnabler::SubtreeEnabler()
+ : FrameGraphNode(FrameGraphNode::SubtreeEnabler, FrameGraphNode::ReadWrite)
{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadTextureData, 0);
}
-LoadTextureDataJob::LoadTextureDataJob(const QTextureImageDataGeneratorPtr &imgDataGen)
- : m_texGen(nullptr)
- , m_imgDataGen(imgDataGen)
+void SubtreeEnabler::sendDisableToFrontend()
{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadTextureData, 0);
-}
+ if (m_enablement != QSubtreeEnabler::SingleShot)
+ return;
-LoadTextureDataJob::~LoadTextureDataJob()
-{
+ if (isEnabled())
+ return;
+
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("enabled");
+ e->setValue(false);
+ notifyObservers(e);
}
-void LoadTextureDataJob::run()
+void SubtreeEnabler::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- 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);
+ const QSubtreeEnabler *node = qobject_cast<const QSubtreeEnabler *>(frontEnd);
+ if (!node)
+ return;
+
+ if (node->isEnabled() != isEnabled())
+ markDirty(AbstractRenderer::AllDirty);
+
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const auto enablement = node->enablement();
+ if (enablement != m_enablement) {
+ m_enablement = enablement;
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
}
-} // namespace Render
-} // namespace Qt3DRender
+} //Render
+
+} //Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/framegraph/subtreeenabler_p.h b/src/render/framegraph/subtreeenabler_p.h
new file mode 100644
index 000000000..2de8dfabf
--- /dev/null
+++ b/src/render/framegraph/subtreeenabler_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** 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 SUBTREEENABLER_P_H
+#define SUBTREEENABLER_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/qsubtreeenabler.h>
+#include <Qt3DRender/private/framegraphnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Q_AUTOTEST_EXPORT SubtreeEnabler : public FrameGraphNode
+{
+public:
+ SubtreeEnabler();
+ QSubtreeEnabler::Enablement enablement() const { return m_enablement; }
+ void sendDisableToFrontend();
+
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+
+private:
+ QSubtreeEnabler::Enablement m_enablement = QSubtreeEnabler::Persistent;
+};
+
+} //Render
+
+} //Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // SUBTREEENABLER_P_H
diff --git a/src/render/framegraph/techniquefilternode.cpp b/src/render/framegraph/techniquefilternode.cpp
index 8816984ee..b3b70e9cb 100644
--- a/src/render/framegraph/techniquefilternode.cpp
+++ b/src/render/framegraph/techniquefilternode.cpp
@@ -43,9 +43,6 @@
#include <Qt3DRender/private/qtechniquefilter_p.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/qparameter.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
QT_BEGIN_NAMESPACE
@@ -59,13 +56,30 @@ TechniqueFilter::TechniqueFilter()
{
}
-void TechniqueFilter::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void TechniqueFilter::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QTechniqueFilterData>>(change);
- const auto &data = typedChange->data;
- m_filters = data.matchIds;
- m_parameterPack.setParameters(data.parameterIds);
+ const QTechniqueFilter *node = qobject_cast<const QTechniqueFilter *>(frontEnd);
+ if (!node)
+ return;
+
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (firstTime)
+ m_parameterPack.clear();
+
+ auto parameters = qIdsForNodes(node->parameters());
+ std::sort(std::begin(parameters), std::end(parameters));
+ if (m_parameterPack.parameters() != parameters) {
+ m_parameterPack.setParameters(parameters);
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ auto filterIds = qIdsForNodes(node->matchAll());
+ std::sort(std::begin(filterIds), std::end(filterIds));
+ if (m_filters != filterIds) {
+ m_filters = filterIds;
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
QVector<Qt3DCore::QNodeId> TechniqueFilter::parameters() const
@@ -89,39 +103,6 @@ void TechniqueFilter::removeFilter(Qt3DCore::QNodeId criterionId)
m_filters.removeOne(criterionId);
}
-void TechniqueFilter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("matchAll")) {
- appendFilter(change->addedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (change->propertyName() == QByteArrayLiteral("parameter")) {
- m_parameterPack.appendParameter(change->addedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- break;
- }
-
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("matchAll")) {
- removeFilter(change->removedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (change->propertyName() == QByteArrayLiteral("parameter")) {
- m_parameterPack.removeParameter(change->removedNodeId());
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- break;
- }
-
- default:
- break;
- }
- FrameGraphNode::sceneChangeEvent(e);
-}
-
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/framegraph/techniquefilternode_p.h b/src/render/framegraph/techniquefilternode_p.h
index d7e6c1508..e424e37e5 100644
--- a/src/render/framegraph/techniquefilternode_p.h
+++ b/src/render/framegraph/techniquefilternode_p.h
@@ -79,11 +79,9 @@ public:
QVector<Qt3DCore::QNodeId> parameters() const;
QVector<Qt3DCore::QNodeId> filters() const;
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
void appendFilter(Qt3DCore::QNodeId criterionId);
void removeFilter(Qt3DCore::QNodeId criterionId);
diff --git a/src/render/framegraph/viewportnode.cpp b/src/render/framegraph/viewportnode.cpp
index b3b53b0f9..5396d97e2 100644
--- a/src/render/framegraph/viewportnode.cpp
+++ b/src/render/framegraph/viewportnode.cpp
@@ -40,7 +40,6 @@
#include "viewportnode_p.h"
#include <Qt3DRender/qviewport.h>
#include <Qt3DRender/private/qviewport_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -59,16 +58,28 @@ ViewportNode::ViewportNode()
{
}
-void ViewportNode::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+
+void ViewportNode::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QViewportData>>(change);
- const auto &data = typedChange->data;
- m_xMin = data.normalizedRect.x();
- m_xMax = data.normalizedRect.width();
- m_yMin = data.normalizedRect.y();
- m_yMax = data.normalizedRect.height();
- m_gamma = data.gamma;
+ const QViewport *node = qobject_cast<const QViewport *>(frontEnd);
+ if (!node)
+ return;
+
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const QRectF oldRect(m_xMin, m_yMin, m_xMax, m_yMax);
+ if (oldRect != node->normalizedRect()) {
+ m_xMin = node->normalizedRect().x();
+ m_yMin = node->normalizedRect().y();
+ m_xMax = node->normalizedRect().width();
+ m_yMax = node->normalizedRect().height();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+
+ if (node->gamma() != m_gamma) {
+ m_gamma = node->gamma();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
float ViewportNode::xMin() const
@@ -118,25 +129,6 @@ void ViewportNode::setGamma(float gamma)
m_gamma = gamma;
}
-void ViewportNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("normalizedRect")) {
- QRectF normalizedRect = propertyChange->value().toRectF();
- setXMin(normalizedRect.x());
- setYMin(normalizedRect.y());
- setXMax(normalizedRect.width());
- setYMax(normalizedRect.height());
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("gamma")) {
- setGamma(propertyChange->value().toFloat());
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- }
- FrameGraphNode::sceneChangeEvent(e);
-}
-
QRectF ViewportNode::computeViewport(const QRectF &childViewport, const ViewportNode *parentViewport)
{
QRectF vp(parentViewport->xMin(),
diff --git a/src/render/framegraph/viewportnode_p.h b/src/render/framegraph/viewportnode_p.h
index 799b9b3dc..3e291a9da 100644
--- a/src/render/framegraph/viewportnode_p.h
+++ b/src/render/framegraph/viewportnode_p.h
@@ -84,13 +84,11 @@ public:
float gamma() const;
void setGamma(float gamma);
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
static QRectF computeViewport(const QRectF &childViewport, const ViewportNode *parentViewport);
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
float m_xMin;
float m_yMin;
float m_xMax;
diff --git a/src/render/framegraph/waitfence.cpp b/src/render/framegraph/waitfence.cpp
index 9480fb7a0..829730bbf 100644
--- a/src/render/framegraph/waitfence.cpp
+++ b/src/render/framegraph/waitfence.cpp
@@ -39,7 +39,6 @@
#include "waitfence_p.h"
#include <Qt3DRender/private/qwaitfence_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
//
// W A R N I N G
@@ -71,33 +70,30 @@ WaitFence::~WaitFence()
{
}
-void WaitFence::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void WaitFence::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- if (e->type() == Qt3DCore::PropertyUpdated) {
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("handle")) {
- m_data.handle = propertyChange->value();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("handleType")) {
- m_data.handleType = static_cast<QWaitFence::HandleType>(propertyChange->value().toInt());
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("timeout")) {
- m_data.timeout = propertyChange->value().value<quint64>();
- markDirty(AbstractRenderer::FrameGraphDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("waitOnCPU")) {
- m_data.waitOnCPU = propertyChange->value().toBool();
- markDirty(AbstractRenderer::FrameGraphDirty);
- }
- }
- FrameGraphNode::sceneChangeEvent(e);
-}
+ const QWaitFence *node = qobject_cast<const QWaitFence *>(frontEnd);
+ if (!node)
+ return;
-void WaitFence::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- FrameGraphNode::initializeFromPeer(change);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QWaitFenceData>>(change);
- const QWaitFenceData &data = typedChange->data;
- m_data = data;
+ FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (node->handleType() != m_data.handleType) {
+ m_data.handleType = node->handleType();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ if (node->handle() != m_data.handle) {
+ m_data.handle = node->handle();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ if (node->timeout() != m_data.timeout) {
+ m_data.timeout = node->timeout();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ if (node->waitOnCPU() != m_data.waitOnCPU) {
+ m_data.waitOnCPU = node->waitOnCPU();
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
} // namespace Render
diff --git a/src/render/framegraph/waitfence_p.h b/src/render/framegraph/waitfence_p.h
index dd48e0efa..811fc80a2 100644
--- a/src/render/framegraph/waitfence_p.h
+++ b/src/render/framegraph/waitfence_p.h
@@ -68,11 +68,9 @@ public:
~WaitFence();
inline QWaitFenceData data() const { return m_data; }
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) override;
-
QWaitFenceData m_data;
};
diff --git a/src/render/frontend/qcamera.cpp b/src/render/frontend/qcamera.cpp
index c2df23c6d..2dcec7ed6 100644
--- a/src/render/frontend/qcamera.cpp
+++ b/src/render/frontend/qcamera.cpp
@@ -281,6 +281,18 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit)
*/
/*!
+ * \qmlproperty Qt3DRender::QCameraLens QCamera::lens
+ * Holds the CameraLens component of the camera.
+ * \since 5.14
+ */
+
+/*!
+ * \qmlproperty Qt3DCore::QTransform QCamera::transform
+ * Holds the Transform component of the camera.
+ * \since 5.14
+ */
+
+/*!
* \qmlproperty real Qt3D.Render::Camera::fieldOfView
* Holds the current vertical field of view of the camera in degrees.
*
@@ -423,6 +435,18 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit)
*/
/*!
+ * \property QCamera::lens
+ * Holds the Qt3DRender::QCameraLens component of the camera.
+ * \since 5.14
+ */
+
+/*!
+ * \property QCamera::transform
+ * Holds the Qt3DCore::QTransform component of the camera.
+ * \since 5.14
+ */
+
+/*!
* \property QCamera::fieldOfView
* Holds the current vertical field of view in degrees.
*
diff --git a/src/render/frontend/qcamera.h b/src/render/frontend/qcamera.h
index 7d717972e..b57f57957 100644
--- a/src/render/frontend/qcamera.h
+++ b/src/render/frontend/qcamera.h
@@ -80,6 +80,9 @@ class Q_3DRENDERSHARED_EXPORT QCamera : public Qt3DCore::QEntity
Q_PROPERTY(QVector3D viewVector READ viewVector NOTIFY viewVectorChanged)
Q_PROPERTY(QMatrix4x4 viewMatrix READ viewMatrix NOTIFY viewMatrixChanged)
+ Q_PROPERTY(Qt3DRender::QCameraLens *lens READ lens CONSTANT REVISION 14)
+ Q_PROPERTY(Qt3DCore::QTransform *transform READ transform CONSTANT REVISION 14)
+
public:
explicit QCamera(QNode *parent = nullptr);
~QCamera();
diff --git a/src/render/frontend/qcameralens.cpp b/src/render/frontend/qcameralens.cpp
index 6c3598fe2..cf30b714a 100644
--- a/src/render/frontend/qcameralens.cpp
+++ b/src/render/frontend/qcameralens.cpp
@@ -228,13 +228,17 @@ QCameraLensPrivate::QCameraLensPrivate()
{
}
+
void QCameraLens::viewAll(Qt3DCore::QNodeId cameraId)
{
Q_D(QCameraLens);
if (d->m_projectionType == PerspectiveProjection) {
QVariant v;
v.setValue(cameraId);
- d->m_pendingViewAllCommand = sendCommand(QLatin1Literal("QueryRootBoundingVolume"), v);
+ d->m_pendingViewAllCommand = {QLatin1String("QueryRootBoundingVolume"),
+ v,
+ id()};
+ d->update();
}
}
@@ -245,7 +249,10 @@ void QCameraLens::viewEntity(Qt3DCore::QNodeId entityId, Qt3DCore::QNodeId camer
QVector<Qt3DCore::QNodeId> ids = {entityId, cameraId};
QVariant v;
v.setValue(ids);
- d->m_pendingViewAllCommand = sendCommand(QLatin1Literal("QueryEntityBoundingVolume"), v);
+ d->m_pendingViewAllCommand = {QLatin1String("QueryEntityBoundingVolume"),
+ v,
+ id()};
+ d->update();
}
}
@@ -253,7 +260,7 @@ void QCameraLensPrivate::processViewAllCommand(Qt3DCore::QNodeCommand::CommandId
const QVariant &data)
{
Q_Q(QCameraLens);
- if (m_pendingViewAllCommand != commandId)
+ if (!m_pendingViewAllCommand || m_pendingViewAllCommand.commandId != commandId)
return;
QVector<float> boundingVolumeData = data.value< QVector<float> >();
@@ -262,7 +269,7 @@ void QCameraLensPrivate::processViewAllCommand(Qt3DCore::QNodeCommand::CommandId
QVector3D center(boundingVolumeData[0], boundingVolumeData[1], boundingVolumeData[2]);
float radius = boundingVolumeData[3];
Q_EMIT q->viewSphere(center, radius);
- m_pendingViewAllCommand = Qt3DCore::QNodeCommand::CommandId();
+ m_pendingViewAllCommand = {};
}
/*!
@@ -641,7 +648,7 @@ void QCameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
case Qt3DCore::CommandRequested: {
Qt3DCore::QNodeCommandPtr command = qSharedPointerCast<Qt3DCore::QNodeCommand>(change);
- if (command->name() == QLatin1Literal("ViewAll"))
+ if (command->name() == QLatin1String("ViewAll"))
d->processViewAllCommand(command->inReplyTo(), command->data());
}
break;
diff --git a/src/render/frontend/qcameralens_p.h b/src/render/frontend/qcameralens_p.h
index 111ab6522..5c5a6a42a 100644
--- a/src/render/frontend/qcameralens_p.h
+++ b/src/render/frontend/qcameralens_p.h
@@ -57,14 +57,31 @@
#include "qcameralens.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
-
#include <QtGui/qmatrix4x4.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
+struct CameraLensCommand
+{
+ QString name;
+ QVariant data;
+ Qt3DCore::QNodeCommand::CommandId commandId;
+
+ inline operator bool() const { return !name.isEmpty(); }
+};
+
+inline bool operator ==(const CameraLensCommand &a, const CameraLensCommand &b) noexcept
+{
+ return a.name == b.name && a.data == b.data && a.commandId == b.commandId;
+}
+
+inline bool operator !=(const CameraLensCommand &a, const CameraLensCommand &b) noexcept
+{
+ return !(a == b);
+}
+
class Q_3DRENDERSHARED_PRIVATE_EXPORT QCameraLensPrivate : public Qt3DCore::QComponentPrivate
{
public:
@@ -106,7 +123,7 @@ public:
float m_exposure;
- Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand;
+ CameraLensCommand m_pendingViewAllCommand;
void processViewAllCommand(Qt3DCore::QNodeCommand::CommandId commandId, const QVariant &data);
private:
diff --git a/src/render/frontend/qcomputecommand.cpp b/src/render/frontend/qcomputecommand.cpp
index e7acdd94a..d0c9f5805 100644
--- a/src/render/frontend/qcomputecommand.cpp
+++ b/src/render/frontend/qcomputecommand.cpp
@@ -39,7 +39,6 @@
#include "qcomputecommand.h"
#include "qcomputecommand_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -156,10 +155,7 @@ QComputeCommandPrivate::QComputeCommandPrivate()
void QComputeCommandPrivate::setFrameCount(int frameCount)
{
m_frameCount = frameCount;
- const auto propertyChange = Qt3DCore::QPropertyUpdatedChangePtr::create(m_id);
- propertyChange->setPropertyName("frameCount");
- propertyChange->setValue(m_frameCount);
- notifyObservers(propertyChange);
+ update();
}
/*!
diff --git a/src/render/frontend/qlevelofdetail.cpp b/src/render/frontend/qlevelofdetail.cpp
index a3596a518..3d0cb9553 100644
--- a/src/render/frontend/qlevelofdetail.cpp
+++ b/src/render/frontend/qlevelofdetail.cpp
@@ -40,7 +40,6 @@
#include "qlevelofdetail.h"
#include "qlevelofdetail_p.h"
#include "qcamera.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -55,6 +54,15 @@ QLevelOfDetailPrivate::QLevelOfDetailPrivate()
{
}
+void QLevelOfDetailPrivate::setCurrentIndex(int currentIndex)
+{
+ Q_Q(QLevelOfDetail);
+ if (m_currentIndex != currentIndex) {
+ m_currentIndex = currentIndex;
+ emit q->currentIndexChanged(m_currentIndex);
+ }
+}
+
/*!
\class Qt3DRender::QLevelOfDetail
\inmodule Qt3DRender
@@ -317,20 +325,6 @@ Qt3DCore::QNodeCreatedChangeBasePtr QLevelOfDetail::createNodeCreationChange() c
return creationChange;
}
-/*! \internal */
-void QLevelOfDetail::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
-{
- Q_D(QLevelOfDetail);
- Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
- if (e->type() == Qt3DCore::PropertyUpdated) {
- if (e->propertyName() == QByteArrayLiteral("currentIndex")) {
- int ndx = e->value().value<int>();
- d->m_currentIndex = ndx;
- emit currentIndexChanged(ndx);
- }
- }
-}
-
QCamera *QLevelOfDetail::camera() const
{
Q_D(const QLevelOfDetail);
@@ -367,10 +361,7 @@ int QLevelOfDetail::currentIndex() const
void QLevelOfDetail::setCurrentIndex(int currentIndex)
{
Q_D(QLevelOfDetail);
- if (d->m_currentIndex != currentIndex) {
- d->m_currentIndex = currentIndex;
- emit currentIndexChanged(d->m_currentIndex);
- }
+ d->setCurrentIndex(currentIndex);
}
QLevelOfDetail::ThresholdType QLevelOfDetail::thresholdType() const
diff --git a/src/render/frontend/qlevelofdetail.h b/src/render/frontend/qlevelofdetail.h
index 308a4d3c0..f6c09a287 100644
--- a/src/render/frontend/qlevelofdetail.h
+++ b/src/render/frontend/qlevelofdetail.h
@@ -97,7 +97,6 @@ Q_SIGNALS:
protected:
explicit QLevelOfDetail(QLevelOfDetailPrivate &dd, Qt3DCore::QNode *parent = nullptr);
Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
private:
Q_DECLARE_PRIVATE(QLevelOfDetail)
diff --git a/src/render/frontend/qlevelofdetail_p.h b/src/render/frontend/qlevelofdetail_p.h
index 7b409e4ca..429128427 100644
--- a/src/render/frontend/qlevelofdetail_p.h
+++ b/src/render/frontend/qlevelofdetail_p.h
@@ -72,6 +72,8 @@ public:
void _q_radiusChanged(float radius);
void _q_centerChanged(const QVector3D &center);
+ virtual void setCurrentIndex(int currentIndex);
+
QCamera *m_camera;
int m_currentIndex;
QLevelOfDetail::ThresholdType m_thresholdType;
diff --git a/src/render/frontend/qlevelofdetailswitch.cpp b/src/render/frontend/qlevelofdetailswitch.cpp
index 845fdd5a6..7b888fe98 100644
--- a/src/render/frontend/qlevelofdetailswitch.cpp
+++ b/src/render/frontend/qlevelofdetailswitch.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qlevelofdetailswitch.h"
+#include "qlevelofdetailswitch_p.h"
#include "qlevelofdetail_p.h"
#include "qglobal.h"
#include <Qt3DCore/QEntity>
@@ -47,6 +48,38 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
+QLevelOfDetailSwitchPrivate::QLevelOfDetailSwitchPrivate()
+ : QLevelOfDetailPrivate()
+{
+
+}
+
+void QLevelOfDetailSwitchPrivate::setCurrentIndex(int currentIndex)
+{
+ Q_Q(QLevelOfDetailSwitch);
+
+ bool changed = m_currentIndex != currentIndex;
+ QLevelOfDetailPrivate::setCurrentIndex(currentIndex);
+
+ if (!changed)
+ return;
+
+ int entityIndex = 0;
+ const auto entities = q->entities();
+ for (Qt3DCore::QEntity *entity : entities) {
+ const auto childNodes = entity->childNodes();
+ for (Qt3DCore::QNode *childNode : childNodes) {
+ Qt3DCore::QEntity *childEntity = qobject_cast<Qt3DCore::QEntity *>(childNode);
+ if (childEntity) {
+ childEntity->setEnabled(entityIndex == currentIndex);
+ entityIndex++;
+ }
+ }
+
+ break; // only work on the first entity, LOD should not be shared
+ }
+}
+
/*!
\class Qt3DRender::QLevelOfDetailSwitch
\inmodule Qt3DRender
@@ -84,9 +117,9 @@ namespace Qt3DRender {
Constructs a new QLevelOfDetailSwitch with the specified \a parent.
*/
QLevelOfDetailSwitch::QLevelOfDetailSwitch(QNode *parent)
- : QLevelOfDetail(parent)
+ : QLevelOfDetail(*new QLevelOfDetailSwitchPrivate(), parent)
{
- Q_D(QLevelOfDetail);
+ Q_D(QLevelOfDetailSwitch);
d->m_currentIndex = -1;
}
@@ -101,34 +134,6 @@ QLevelOfDetailSwitch::QLevelOfDetailSwitch(QLevelOfDetailPrivate &dd, QNode *par
{
}
-/*! \internal */
-void QLevelOfDetailSwitch::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
-{
- Q_D(QLevelOfDetail);
- Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
- if (e->type() == Qt3DCore::PropertyUpdated) {
- if (e->propertyName() == QByteArrayLiteral("currentIndex")) {
- int ndx = e->value().value<int>();
- d->m_currentIndex = ndx;
- emit currentIndexChanged(ndx);
-
- int entityIndex = 0;
- const auto entities = this->entities();
- for (Qt3DCore::QEntity *entity : entities) {
- const auto childNodes = entity->childNodes();
- for (Qt3DCore::QNode *childNode : childNodes) {
- Qt3DCore::QEntity *childEntity = qobject_cast<Qt3DCore::QEntity *>(childNode);
- if (childEntity) {
- childEntity->setEnabled(entityIndex == ndx);
- entityIndex++;
- }
- }
- break; // only work on the first entity, LOD should not be shared
- }
- }
- }
-}
-
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/frontend/qlevelofdetailswitch.h b/src/render/frontend/qlevelofdetailswitch.h
index 1615d16e6..90f4ee3e2 100644
--- a/src/render/frontend/qlevelofdetailswitch.h
+++ b/src/render/frontend/qlevelofdetailswitch.h
@@ -45,6 +45,7 @@
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
+class QLevelOfDetailSwitchPrivate;
class Q_3DRENDERSHARED_EXPORT QLevelOfDetailSwitch : public QLevelOfDetail
{
@@ -56,10 +57,9 @@ public:
protected:
explicit QLevelOfDetailSwitch(QLevelOfDetailPrivate &dd, Qt3DCore::QNode *parent = nullptr);
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
private:
- Q_DECLARE_PRIVATE(QLevelOfDetail)
+ Q_DECLARE_PRIVATE(QLevelOfDetailSwitch)
};
} // namespace Qt3DRender
diff --git a/src/render/frontend/qlevelofdetailswitch_p.h b/src/render/frontend/qlevelofdetailswitch_p.h
new file mode 100644
index 000000000..51321c986
--- /dev/null
+++ b/src/render/frontend/qlevelofdetailswitch_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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_QLEVELOFDETAILSWITCH_P_H
+#define QT3DRENDER_QLEVELOFDETAILSWITCH_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/qlevelofdetail_p.h>
+#include <Qt3DRender/qlevelofdetailswitch.h>
+
+#include <QVector3D>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class Q_3DRENDERSHARED_PRIVATE_EXPORT QLevelOfDetailSwitchPrivate : public QLevelOfDetailPrivate
+{
+public:
+ QLevelOfDetailSwitchPrivate();
+
+ Q_DECLARE_PUBLIC(QLevelOfDetailSwitch)
+
+ void setCurrentIndex(int currentIndex) override;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QLEVELOFDETAILSWITCH_P_H
diff --git a/src/render/frontend/qpickingsettings.cpp b/src/render/frontend/qpickingsettings.cpp
index 84e61e141..0c858aef2 100644
--- a/src/render/frontend/qpickingsettings.cpp
+++ b/src/render/frontend/qpickingsettings.cpp
@@ -199,7 +199,7 @@ void QPickingSettings::setPickMethod(QPickingSettings::PickMethod pickMethod)
* \value NearestPick Only the nearest entity to picking ray origin intersected by the picking ray
* is picked (default).
* \value AllPicks All entities that intersect the picking ray are picked.
- * \value PriorityPick Selects the entity whose object picker has the highest
+ * \value NearestPriorityPick Selects the entity whose object picker has the highest
* value. If several object pickers have the same priority, the closest one on
* the ray is selected.
*
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index c60488e16..271eb9c11 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -41,7 +41,6 @@
#include "qrenderaspect_p.h"
#include <Qt3DRender/private/nodemanagers_p.h>
-#include <Qt3DRender/private/texturedatamanager_p.h>
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/scenemanager_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
@@ -67,6 +66,7 @@
#include <Qt3DRender/qshaderdata.h>
#include <Qt3DRender/qrenderstateset.h>
#include <Qt3DRender/qnodraw.h>
+#include <Qt3DRender/qnopicking.h>
#include <Qt3DRender/qcameralens.h>
#include <Qt3DRender/qattribute.h>
#include <Qt3DRender/qbuffer.h>
@@ -90,10 +90,13 @@
#include <Qt3DRender/qblitframebuffer.h>
#include <Qt3DRender/qsetfence.h>
#include <Qt3DRender/qwaitfence.h>
+#include <Qt3DRender/qshaderimage.h>
+#include <Qt3DRender/qsubtreeenabler.h>
#include <Qt3DCore/qarmature.h>
#include <Qt3DCore/qjoint.h>
#include <Qt3DCore/qskeletonloader.h>
+#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/cameraselectornode_p.h>
#include <Qt3DRender/private/layerfilternode_p.h>
#include <Qt3DRender/private/cameralens_p.h>
@@ -112,10 +115,10 @@
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DRender/private/nodefunctor_p.h>
#include <Qt3DRender/private/framegraphnode_p.h>
-#include <Qt3DRender/private/loadtexturedatajob_p.h>
#include <Qt3DRender/private/textureimage_p.h>
#include <Qt3DRender/private/statesetnode_p.h>
#include <Qt3DRender/private/nodraw_p.h>
+#include <Qt3DRender/private/nopicking_p.h>
#include <Qt3DRender/private/vsyncframeadvanceservice_p.h>
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/buffer_p.h>
@@ -147,6 +150,7 @@
#include <Qt3DRender/private/memorybarrier_p.h>
#include <Qt3DRender/private/shaderbuilder_p.h>
#include <Qt3DRender/private/blitframebuffer_p.h>
+#include <Qt3DRender/private/subtreeenabler_p.h>
#include <Qt3DRender/private/armature_p.h>
#include <Qt3DRender/private/skeleton_p.h>
#include <Qt3DRender/private/joint_p.h>
@@ -154,6 +158,7 @@
#include <Qt3DRender/private/proximityfilter_p.h>
#include <Qt3DRender/private/setfence_p.h>
#include <Qt3DRender/private/waitfence_p.h>
+#include <Qt3DRender/private/shaderimage_p.h>
#include <private/qrenderpluginfactory_p.h>
#include <private/qrenderplugin_p.h>
@@ -228,6 +233,12 @@ QRenderAspectPrivate *QRenderAspectPrivate::findPrivate(Qt3DCore::QAspectEngine
return nullptr;
}
+void QRenderAspectPrivate::syncDirtyFrontEndNode(QNode *node, QBackendNode *backend, bool firstTime) const
+{
+ Render::BackendNode *renderBackend = static_cast<Render::BackendNode *>(backend);
+ renderBackend->syncFromFrontEnd(node, firstTime);
+}
+
/*! \internal */
void QRenderAspectPrivate::registerBackendTypes()
{
@@ -238,77 +249,80 @@ void QRenderAspectPrivate::registerBackendTypes()
qRegisterMetaType<Qt3DRender::QFrameGraphNode *>();
qRegisterMetaType<Qt3DRender::QCamera*>();
qRegisterMetaType<Qt3DRender::QShaderProgram*>();
+ qRegisterMetaType<Qt3DRender::QViewport*>();
qRegisterMetaType<Qt3DCore::QJoint*>();
- q->registerBackendType<Qt3DCore::QEntity>(QSharedPointer<Render::RenderEntityFunctor>::create(m_renderer, m_nodeManagers));
- q->registerBackendType<Qt3DCore::QTransform>(QSharedPointer<Render::NodeFunctor<Render::Transform, Render::TransformManager> >::create(m_renderer));
+ q->registerBackendType<Qt3DCore::QEntity, true>(QSharedPointer<Render::RenderEntityFunctor>::create(m_renderer, m_nodeManagers));
+ q->registerBackendType<Qt3DCore::QTransform, true>(QSharedPointer<Render::NodeFunctor<Render::Transform, Render::TransformManager> >::create(m_renderer));
- q->registerBackendType<Qt3DRender::QCameraLens>(QSharedPointer<Render::CameraLensFunctor>::create(m_renderer, q));
- q->registerBackendType<QLayer>(QSharedPointer<Render::NodeFunctor<Render::Layer, Render::LayerManager> >::create(m_renderer));
- q->registerBackendType<QLevelOfDetail>(QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(m_renderer));
- q->registerBackendType<QLevelOfDetailSwitch>(QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(m_renderer));
- q->registerBackendType<QSceneLoader>(QSharedPointer<Render::RenderSceneFunctor>::create(m_renderer, m_nodeManagers->sceneManager()));
- q->registerBackendType<QRenderTarget>(QSharedPointer<Render::NodeFunctor<Render::RenderTarget, Render::RenderTargetManager> >::create(m_renderer));
- q->registerBackendType<QRenderTargetOutput>(QSharedPointer<Render::NodeFunctor<Render::RenderTargetOutput, Render::AttachmentManager> >::create(m_renderer));
- q->registerBackendType<QRenderSettings>(QSharedPointer<Render::RenderSettingsFunctor>::create(m_renderer));
- q->registerBackendType<QRenderState>(QSharedPointer<Render::NodeFunctor<Render::RenderStateNode, Render::RenderStateManager> >::create(m_renderer));
+ q->registerBackendType<Qt3DRender::QCameraLens, true>(QSharedPointer<Render::CameraLensFunctor>::create(m_renderer, q));
+ q->registerBackendType<QLayer, true>(QSharedPointer<Render::NodeFunctor<Render::Layer, Render::LayerManager> >::create(m_renderer));
+ q->registerBackendType<QLevelOfDetail, true>(QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(m_renderer));
+ q->registerBackendType<QLevelOfDetailSwitch, true>(QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(m_renderer));
+ q->registerBackendType<QSceneLoader, true>(QSharedPointer<Render::RenderSceneFunctor>::create(m_renderer, m_nodeManagers->sceneManager()));
+ q->registerBackendType<QRenderTarget, true>(QSharedPointer<Render::NodeFunctor<Render::RenderTarget, Render::RenderTargetManager> >::create(m_renderer));
+ q->registerBackendType<QRenderTargetOutput, true>(QSharedPointer<Render::NodeFunctor<Render::RenderTargetOutput, Render::AttachmentManager> >::create(m_renderer));
+ q->registerBackendType<QRenderSettings, true>(QSharedPointer<Render::RenderSettingsFunctor>::create(m_renderer));
+ q->registerBackendType<QRenderState, true>(QSharedPointer<Render::NodeFunctor<Render::RenderStateNode, Render::RenderStateManager> >::create(m_renderer));
// Geometry + Compute
- q->registerBackendType<QAttribute>(QSharedPointer<Render::NodeFunctor<Render::Attribute, Render::AttributeManager> >::create(m_renderer));
- q->registerBackendType<QBuffer>(QSharedPointer<Render::BufferFunctor>::create(m_renderer, m_nodeManagers->bufferManager()));
- q->registerBackendType<QComputeCommand>(QSharedPointer<Render::NodeFunctor<Render::ComputeCommand, Render::ComputeCommandManager> >::create(m_renderer));
- q->registerBackendType<QGeometry>(QSharedPointer<Render::NodeFunctor<Render::Geometry, Render::GeometryManager> >::create(m_renderer));
- q->registerBackendType<QGeometryRenderer>(QSharedPointer<Render::GeometryRendererFunctor>::create(m_renderer, m_nodeManagers->geometryRendererManager()));
- q->registerBackendType<Qt3DCore::QArmature>(QSharedPointer<Render::NodeFunctor<Render::Armature, Render::ArmatureManager>>::create(m_renderer));
- q->registerBackendType<Qt3DCore::QAbstractSkeleton>(QSharedPointer<Render::SkeletonFunctor>::create(m_renderer, m_nodeManagers->skeletonManager(), m_nodeManagers->jointManager()));
- q->registerBackendType<Qt3DCore::QJoint>(QSharedPointer<Render::JointFunctor>::create(m_renderer, m_nodeManagers->jointManager(), m_nodeManagers->skeletonManager()));
+ q->registerBackendType<QAttribute, true>(QSharedPointer<Render::NodeFunctor<Render::Attribute, Render::AttributeManager> >::create(m_renderer));
+ q->registerBackendType<QBuffer, true>(QSharedPointer<Render::BufferFunctor>::create(m_renderer, m_nodeManagers->bufferManager()));
+ q->registerBackendType<QComputeCommand, true>(QSharedPointer<Render::NodeFunctor<Render::ComputeCommand, Render::ComputeCommandManager> >::create(m_renderer));
+ q->registerBackendType<QGeometry, true>(QSharedPointer<Render::NodeFunctor<Render::Geometry, Render::GeometryManager> >::create(m_renderer));
+ q->registerBackendType<QGeometryRenderer, true>(QSharedPointer<Render::GeometryRendererFunctor>::create(m_renderer, m_nodeManagers->geometryRendererManager()));
+ q->registerBackendType<Qt3DCore::QArmature, true>(QSharedPointer<Render::NodeFunctor<Render::Armature, Render::ArmatureManager>>::create(m_renderer));
+ q->registerBackendType<Qt3DCore::QAbstractSkeleton, true>(QSharedPointer<Render::SkeletonFunctor>::create(m_renderer, m_nodeManagers->skeletonManager(), m_nodeManagers->jointManager()));
+ q->registerBackendType<Qt3DCore::QJoint, true>(QSharedPointer<Render::JointFunctor>::create(m_renderer, m_nodeManagers->jointManager(), m_nodeManagers->skeletonManager()));
// Textures
- q->registerBackendType<QAbstractTexture>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager()));
- q->registerBackendType<QAbstractTextureImage>(QSharedPointer<Render::TextureImageFunctor>::create(m_renderer,
- m_nodeManagers->textureImageManager(),
- m_nodeManagers->textureImageDataManager()));
+ q->registerBackendType<QAbstractTexture, true>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager()));
+ q->registerBackendType<QAbstractTextureImage, true>(QSharedPointer<Render::TextureImageFunctor>::create(m_renderer,
+ m_nodeManagers->textureImageManager()));
// Material system
- q->registerBackendType<QEffect>(QSharedPointer<Render::NodeFunctor<Render::Effect, Render::EffectManager> >::create(m_renderer));
- q->registerBackendType<QFilterKey>(QSharedPointer<Render::NodeFunctor<Render::FilterKey, Render::FilterKeyManager> >::create(m_renderer));
- q->registerBackendType<QAbstractLight>(QSharedPointer<Render::RenderLightFunctor>::create(m_renderer, m_nodeManagers));
- q->registerBackendType<QEnvironmentLight>(QSharedPointer<Render::NodeFunctor<Render::EnvironmentLight, Render::EnvironmentLightManager> >::create(m_renderer));
- q->registerBackendType<QMaterial>(QSharedPointer<Render::NodeFunctor<Render::Material, Render::MaterialManager> >::create(m_renderer));
- q->registerBackendType<QParameter>(QSharedPointer<Render::NodeFunctor<Render::Parameter, Render::ParameterManager> >::create(m_renderer));
- q->registerBackendType<QRenderPass>(QSharedPointer<Render::NodeFunctor<Render::RenderPass, Render::RenderPassManager> >::create(m_renderer));
- q->registerBackendType<QShaderData>(QSharedPointer<Render::RenderShaderDataFunctor>::create(m_renderer, m_nodeManagers));
- q->registerBackendType<QShaderProgram>(QSharedPointer<Render::NodeFunctor<Render::Shader, Render::ShaderManager> >::create(m_renderer));
- q->registerBackendType<QShaderProgramBuilder>(QSharedPointer<Render::NodeFunctor<Render::ShaderBuilder, Render::ShaderBuilderManager> >::create(m_renderer));
- q->registerBackendType<QTechnique>(QSharedPointer<Render::TechniqueFunctor>::create(m_renderer, m_nodeManagers));
+ q->registerBackendType<QEffect, true>(QSharedPointer<Render::NodeFunctor<Render::Effect, Render::EffectManager> >::create(m_renderer));
+ q->registerBackendType<QFilterKey, true>(QSharedPointer<Render::NodeFunctor<Render::FilterKey, Render::FilterKeyManager> >::create(m_renderer));
+ q->registerBackendType<QAbstractLight, true>(QSharedPointer<Render::RenderLightFunctor>::create(m_renderer, m_nodeManagers));
+ q->registerBackendType<QEnvironmentLight, true>(QSharedPointer<Render::NodeFunctor<Render::EnvironmentLight, Render::EnvironmentLightManager> >::create(m_renderer));
+ q->registerBackendType<QMaterial, true>(QSharedPointer<Render::NodeFunctor<Render::Material, Render::MaterialManager> >::create(m_renderer));
+ q->registerBackendType<QParameter, true>(QSharedPointer<Render::NodeFunctor<Render::Parameter, Render::ParameterManager> >::create(m_renderer));
+ q->registerBackendType<QRenderPass, true>(QSharedPointer<Render::NodeFunctor<Render::RenderPass, Render::RenderPassManager> >::create(m_renderer));
+ q->registerBackendType<QShaderData, true>(QSharedPointer<Render::RenderShaderDataFunctor>::create(m_renderer, m_nodeManagers));
+ q->registerBackendType<QShaderProgram, true>(QSharedPointer<Render::NodeFunctor<Render::Shader, Render::ShaderManager> >::create(m_renderer));
+ q->registerBackendType<QShaderProgramBuilder, true>(QSharedPointer<Render::NodeFunctor<Render::ShaderBuilder, Render::ShaderBuilderManager> >::create(m_renderer));
+ q->registerBackendType<QTechnique, true>(QSharedPointer<Render::TechniqueFunctor>::create(m_renderer, m_nodeManagers));
+ q->registerBackendType<QShaderImage, true>(QSharedPointer<Render::NodeFunctor<Render::ShaderImage, Render::ShaderImageManager>>::create(m_renderer));
// Framegraph
- q->registerBackendType<QFrameGraphNode>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::FrameGraphNode, QFrameGraphNode> >::create(m_renderer));
- q->registerBackendType<QCameraSelector>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::CameraSelector, QCameraSelector> >::create(m_renderer));
- q->registerBackendType<QClearBuffers>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ClearBuffers, QClearBuffers> >::create(m_renderer));
- q->registerBackendType<QDispatchCompute>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::DispatchCompute, QDispatchCompute> >::create(m_renderer));
- q->registerBackendType<QFrustumCulling>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::FrustumCulling, QFrustumCulling> >::create(m_renderer));
- q->registerBackendType<QLayerFilter>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::LayerFilterNode, QLayerFilter> >::create(m_renderer));
- q->registerBackendType<QNoDraw>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::NoDraw, QNoDraw> >::create(m_renderer));
- q->registerBackendType<QRenderPassFilter>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderPassFilter, QRenderPassFilter> >::create(m_renderer));
- q->registerBackendType<QRenderStateSet>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::StateSetNode, QRenderStateSet> >::create(m_renderer));
- q->registerBackendType<QRenderSurfaceSelector>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderSurfaceSelector, QRenderSurfaceSelector> >::create(m_renderer));
- q->registerBackendType<QRenderTargetSelector>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderTargetSelector, QRenderTargetSelector> >::create(m_renderer));
- q->registerBackendType<QSortPolicy>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::SortPolicy, QSortPolicy> >::create(m_renderer));
- q->registerBackendType<QTechniqueFilter>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::TechniqueFilter, QTechniqueFilter> >::create(m_renderer));
- q->registerBackendType<QViewport>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ViewportNode, QViewport> >::create(m_renderer));
- q->registerBackendType<QRenderCapture>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderCapture, QRenderCapture> >::create(m_renderer));
- q->registerBackendType<QBufferCapture>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::BufferCapture, QBufferCapture> >::create(m_renderer));
- q->registerBackendType<QMemoryBarrier>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::MemoryBarrier, QMemoryBarrier> >::create(m_renderer));
- q->registerBackendType<QProximityFilter>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ProximityFilter, QProximityFilter> >::create(m_renderer));
- q->registerBackendType<QBlitFramebuffer>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::BlitFramebuffer, QBlitFramebuffer> >::create(m_renderer));
- q->registerBackendType<QSetFence>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::SetFence, QSetFence> >::create(m_renderer));
- q->registerBackendType<QWaitFence>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::WaitFence, QWaitFence> >::create(m_renderer));
+ q->registerBackendType<QFrameGraphNode, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::FrameGraphNode, QFrameGraphNode> >::create(m_renderer));
+ q->registerBackendType<QCameraSelector, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::CameraSelector, QCameraSelector> >::create(m_renderer));
+ q->registerBackendType<QClearBuffers, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ClearBuffers, QClearBuffers> >::create(m_renderer));
+ q->registerBackendType<QDispatchCompute, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::DispatchCompute, QDispatchCompute> >::create(m_renderer));
+ q->registerBackendType<QFrustumCulling, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::FrustumCulling, QFrustumCulling> >::create(m_renderer));
+ q->registerBackendType<QLayerFilter, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::LayerFilterNode, QLayerFilter> >::create(m_renderer));
+ q->registerBackendType<QNoDraw, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::NoDraw, QNoDraw> >::create(m_renderer));
+ q->registerBackendType<QRenderPassFilter, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderPassFilter, QRenderPassFilter> >::create(m_renderer));
+ q->registerBackendType<QRenderStateSet, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::StateSetNode, QRenderStateSet> >::create(m_renderer));
+ q->registerBackendType<QRenderSurfaceSelector, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderSurfaceSelector, QRenderSurfaceSelector> >::create(m_renderer));
+ q->registerBackendType<QRenderTargetSelector, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderTargetSelector, QRenderTargetSelector> >::create(m_renderer));
+ q->registerBackendType<QSortPolicy, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::SortPolicy, QSortPolicy> >::create(m_renderer));
+ q->registerBackendType<QTechniqueFilter, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::TechniqueFilter, QTechniqueFilter> >::create(m_renderer));
+ q->registerBackendType<QViewport, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ViewportNode, QViewport> >::create(m_renderer));
+ q->registerBackendType<QRenderCapture, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderCapture, QRenderCapture> >::create(m_renderer));
+ q->registerBackendType<QBufferCapture, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::BufferCapture, QBufferCapture> >::create(m_renderer));
+ q->registerBackendType<QMemoryBarrier, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::MemoryBarrier, QMemoryBarrier> >::create(m_renderer));
+ q->registerBackendType<QProximityFilter, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ProximityFilter, QProximityFilter> >::create(m_renderer));
+ q->registerBackendType<QBlitFramebuffer, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::BlitFramebuffer, QBlitFramebuffer> >::create(m_renderer));
+ q->registerBackendType<QSetFence, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::SetFence, QSetFence> >::create(m_renderer));
+ q->registerBackendType<QWaitFence, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::WaitFence, QWaitFence> >::create(m_renderer));
+ q->registerBackendType<QNoPicking, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::NoPicking, QNoPicking> >::create(m_renderer));
+ q->registerBackendType<QSubtreeEnabler, true>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::SubtreeEnabler, QSubtreeEnabler> >::create(m_renderer));
// Picking
- q->registerBackendType<QObjectPicker>(QSharedPointer<Render::NodeFunctor<Render::ObjectPicker, Render::ObjectPickerManager> >::create(m_renderer));
- q->registerBackendType<QRayCaster>(QSharedPointer<Render::NodeFunctor<Render::RayCaster, Render::RayCasterManager> >::create(m_renderer));
- q->registerBackendType<QScreenRayCaster>(QSharedPointer<Render::NodeFunctor<Render::RayCaster, Render::RayCasterManager> >::create(m_renderer));
+ q->registerBackendType<QObjectPicker, true>(QSharedPointer<Render::NodeFunctor<Render::ObjectPicker, Render::ObjectPickerManager> >::create(m_renderer));
+ q->registerBackendType<QRayCaster, true>(QSharedPointer<Render::NodeFunctor<Render::RayCaster, Render::RayCasterManager> >::create(m_renderer));
+ q->registerBackendType<QScreenRayCaster, true>(QSharedPointer<Render::NodeFunctor<Render::RayCaster, Render::RayCasterManager> >::create(m_renderer));
// Plugins
for (const QString &plugin : qAsConst(m_pluginConfig))
@@ -356,6 +370,7 @@ void QRenderAspectPrivate::unregisterBackendTypes()
unregisterBackendType<QShaderProgram>();
unregisterBackendType<QShaderProgramBuilder>();
unregisterBackendType<QTechnique>();
+ unregisterBackendType<QShaderImage>();
// Framegraph
unregisterBackendType<QCameraSelector>();
@@ -376,6 +391,7 @@ void QRenderAspectPrivate::unregisterBackendTypes()
unregisterBackendType<QMemoryBarrier>();
unregisterBackendType<QSetFence>();
unregisterBackendType<QWaitFence>();
+ unregisterBackendType<QSubtreeEnabler>();
// Picking
unregisterBackendType<QObjectPicker>();
@@ -432,9 +448,9 @@ void QRenderAspectPrivate::renderInitialize(QOpenGLContext *context)
}
/*! \internal */
-void QRenderAspectPrivate::renderSynchronous(bool blocking)
+void QRenderAspectPrivate::renderSynchronous(bool swapBuffers)
{
- m_renderer->doRender(blocking);
+ m_renderer->doRender(swapBuffers);
}
/*
@@ -473,34 +489,16 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
if (d->m_renderer->isRunning() && d->m_renderer->settings()) {
Render::NodeManagers *manager = d->m_renderer->nodeManagers();
- QAspectJobPtr textureLoadingSync = d->m_renderer->syncTextureLoadingJob();
- textureLoadingSync->removeDependency(QWeakPointer<QAspectJob>());
-
- // Launch texture generator jobs
- const QVector<QTextureImageDataGeneratorPtr> pendingImgGen = manager->textureImageDataManager()->pendingGenerators();
- for (const QTextureImageDataGeneratorPtr &imgGen : pendingImgGen) {
- auto loadTextureJob = Render::LoadTextureDataJobPtr::create(imgGen);
- textureLoadingSync->addDependency(loadTextureJob);
- loadTextureJob->setNodeManagers(manager);
- jobs.append(loadTextureJob);
- }
- const QVector<QTextureGeneratorPtr> pendingTexGen = manager->textureDataManager()->pendingGenerators();
- for (const QTextureGeneratorPtr &texGen : pendingTexGen) {
- auto loadTextureJob = Render::LoadTextureDataJobPtr::create(texGen);
- textureLoadingSync->addDependency(loadTextureJob);
- loadTextureJob->setNodeManagers(manager);
- jobs.append(loadTextureJob);
- }
+ QAspectJobPtr loadingJobSync = d->m_renderer->syncLoadingJobs();
+ loadingJobSync->removeDependency(QWeakPointer<QAspectJob>());
- // Launch skeleton loader jobs. We join on the syncTextureLoadingJob for now
- // which should likely be renamed to something more generic or we introduce
- // another synchronizing job for skeleton loading
+ // Launch skeleton loader jobs once all loading jobs have completed.
const QVector<Render::HSkeleton> skeletonsToLoad =
manager->skeletonManager()->takeDirtySkeletons(Render::SkeletonManager::SkeletonDataDirty);
for (const auto &skeletonHandle : skeletonsToLoad) {
auto loadSkeletonJob = Render::LoadSkeletonJobPtr::create(skeletonHandle);
loadSkeletonJob->setNodeManagers(manager);
- textureLoadingSync->addDependency(loadSkeletonJob);
+ loadingJobSync->addDependency(loadSkeletonJob);
jobs.append(loadSkeletonJob);
}
@@ -551,7 +549,7 @@ void QRenderAspect::onEngineStartup()
Render::NodeManagers *managers = d->m_renderer->nodeManagers();
Render::Entity *rootEntity = managers->lookupResource<Render::Entity, Render::EntityManager>(rootEntityId());
Q_ASSERT(rootEntity);
- d->m_renderer->setSceneRoot(d, rootEntity);
+ d->m_renderer->setSceneRoot(rootEntity);
}
void QRenderAspect::onRegistered()
diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h
index 28a9b2453..62e373b11 100644
--- a/src/render/frontend/qrenderaspect_p.h
+++ b/src/render/frontend/qrenderaspect_p.h
@@ -86,12 +86,14 @@ public:
static QRenderAspectPrivate* findPrivate(Qt3DCore::QAspectEngine *engine);
+ void syncDirtyFrontEndNode(Qt3DCore::QNode *node, Qt3DCore::QBackendNode *backend, bool firstTime) const override;
+
void registerBackendTypes();
void unregisterBackendTypes();
void loadSceneParsers();
void loadRenderPlugin(const QString &pluginName);
void renderInitialize(QOpenGLContext *context);
- void renderSynchronous(bool blocking = false);
+ void renderSynchronous(bool swapBuffers = true);
void renderShutdown();
void registerBackendType(const QMetaObject &, const Qt3DCore::QBackendNodeMapperPtr &functor);
QVector<Qt3DCore::QAspectJobPtr> createGeometryRendererJobs();
diff --git a/src/render/frontend/qrenderplugin_p.h b/src/render/frontend/qrenderplugin_p.h
index c34dabefc..110c8295a 100644
--- a/src/render/frontend/qrenderplugin_p.h
+++ b/src/render/frontend/qrenderplugin_p.h
@@ -75,6 +75,10 @@ protected:
{
aspect->registerBackendType(obj, functor);
}
+ void registerBackendType(QRenderAspect *aspect, const QMetaObject &obj, const Qt3DCore::QBackendNodeMapperPtr &functor, bool supportsSyncing)
+ {
+ aspect->registerBackendType(obj, functor, supportsSyncing);
+ }
void unregisterBackendType(QRenderAspect *aspect, const QMetaObject &obj)
{
aspect->unregisterBackendType(obj);
diff --git a/src/render/frontend/qrendersettings.cpp b/src/render/frontend/qrendersettings.cpp
index 23f88eb10..d106e4205 100644
--- a/src/render/frontend/qrendersettings.cpp
+++ b/src/render/frontend/qrendersettings.cpp
@@ -96,28 +96,33 @@ void QRenderSettingsPrivate::init()
q, SLOT(_q_onWorldSpaceToleranceChanged(float)));
}
+void QRenderSettingsPrivate::invalidateFrame()
+{
+ update();
+}
+
/*! \internal */
void QRenderSettingsPrivate::_q_onPickingMethodChanged(QPickingSettings::PickMethod pickMethod)
{
- notifyPropertyChange("pickMethod", pickMethod);
+ notifyPropertyChange("pickMethod", pickMethod);// TODOSYNC
}
/*! \internal */
void QRenderSettingsPrivate::_q_onPickResultModeChanged(QPickingSettings::PickResultMode pickResultMode)
{
- notifyPropertyChange("pickResultMode", pickResultMode);
+ notifyPropertyChange("pickResultMode", pickResultMode);// TODOSYNC
}
/*! \internal */
void QRenderSettingsPrivate::_q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode)
{
- notifyPropertyChange("faceOrientationPickingMode", faceOrientationPickingMode);
+ notifyPropertyChange("faceOrientationPickingMode", faceOrientationPickingMode);// TODOSYNC
}
/*! \internal */
void QRenderSettingsPrivate::_q_onWorldSpaceToleranceChanged(float worldSpaceTolerance)
{
- notifyPropertyChange("pickWorldSpaceTolerance", worldSpaceTolerance);
+ notifyPropertyChange("pickWorldSpaceTolerance", worldSpaceTolerance);// TODOSYNC
}
QRenderSettings::QRenderSettings(Qt3DCore::QNode *parent)
@@ -156,6 +161,12 @@ QPickingSettings *QRenderSettings::pickingSettings()
return &(d->m_pickingSettings);
}
+const QPickingSettings *QRenderSettings::pickingSettings() const
+{
+ Q_D(const QRenderSettings);
+ return &(d->m_pickingSettings);
+}
+
/*!
\qmlproperty FrameGraphNode RenderSettings::activeFrameGraph
diff --git a/src/render/frontend/qrendersettings.h b/src/render/frontend/qrendersettings.h
index 9d2baa58b..c8771a8fa 100644
--- a/src/render/frontend/qrendersettings.h
+++ b/src/render/frontend/qrendersettings.h
@@ -71,6 +71,7 @@ public:
Q_ENUM(RenderPolicy) // LCOV_EXCL_LINE
QPickingSettings* pickingSettings();
+ const QPickingSettings* pickingSettings() const;
QFrameGraphNode *activeFrameGraph() const;
RenderPolicy renderPolicy() const;
diff --git a/src/render/frontend/qrendersettings_p.h b/src/render/frontend/qrendersettings_p.h
index f91397bd2..88f91810a 100644
--- a/src/render/frontend/qrendersettings_p.h
+++ b/src/render/frontend/qrendersettings_p.h
@@ -71,6 +71,8 @@ public:
QFrameGraphNode *m_activeFrameGraph;
QRenderSettings::RenderPolicy m_renderPolicy;
+ void invalidateFrame();
+
void _q_onPickingMethodChanged(QPickingSettings::PickMethod pickMethod);
void _q_onPickResultModeChanged(QPickingSettings::PickResultMode pickResultMode);
void _q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode);
diff --git a/src/render/frontend/qrendertarget.cpp b/src/render/frontend/qrendertarget.cpp
index 9aa9c8c41..57eecd795 100644
--- a/src/render/frontend/qrendertarget.cpp
+++ b/src/render/frontend/qrendertarget.cpp
@@ -40,9 +40,6 @@
#include "qrendertarget.h"
#include "qrendertarget_p.h"
#include "qrendertargetoutput.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
QT_BEGIN_NAMESPACE
@@ -126,11 +123,7 @@ void QRenderTarget::addOutput(QRenderTargetOutput *output)
if (!output->parent())
output->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), output);
- change->setPropertyName("output");
- d->notifyObservers(change);
- }
+ d->updateNode(output, "output", Qt3DCore::PropertyValueAdded);
}
}
@@ -141,11 +134,7 @@ void QRenderTarget::removeOutput(QRenderTargetOutput *output)
{
Q_D(QRenderTarget);
- if (output && d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), output);
- change->setPropertyName("output");
- d->notifyObservers(change);
- }
+ d->updateNode(output, "output", Qt3DCore::PropertyValueRemoved);
d->m_outputs.removeOne(output);
// Remove bookkeeping connection
d->unregisterDestructionHelper(output);
diff --git a/src/render/frontend/qrendertargetoutput.cpp b/src/render/frontend/qrendertargetoutput.cpp
index 14ac9c817..8c0d86134 100644
--- a/src/render/frontend/qrendertargetoutput.cpp
+++ b/src/render/frontend/qrendertargetoutput.cpp
@@ -40,7 +40,6 @@
#include "qrendertargetoutput.h"
#include "qrendertargetoutput_p.h"
#include "qtexture.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/frontend/render-frontend.pri b/src/render/frontend/render-frontend.pri
index 1fafcc294..0153e9c97 100644
--- a/src/render/frontend/render-frontend.pri
+++ b/src/render/frontend/render-frontend.pri
@@ -9,6 +9,7 @@ HEADERS += \
$$PWD/qlevelofdetail.h \
$$PWD/qlevelofdetail_p.h \
$$PWD/qlevelofdetailswitch.h \
+ $$PWD/qlevelofdetailswitch_p.h \
$$PWD/qrendertarget.h \
$$PWD/qrendertarget_p.h \
$$PWD/sphere_p.h \
diff --git a/src/render/geometry/armature.cpp b/src/render/geometry/armature.cpp
index 15a26c9ec..6e417952b 100644
--- a/src/render/geometry/armature.cpp
+++ b/src/render/geometry/armature.cpp
@@ -36,7 +36,8 @@
#include "armature_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qarmature.h>
+#include <Qt3DCore/qabstractskeleton.h>
#include <Qt3DCore/private/qarmature_p.h>
@@ -52,32 +53,20 @@ Armature::Armature()
{
}
-void Armature::cleanup()
+void Armature::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- m_skeletonId = Qt3DCore::QNodeId();
- setEnabled(false);
-}
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QArmature *node = qobject_cast<const QArmature *>(frontEnd);
+ if (!node)
+ return;
-void Armature::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- const auto typedChange = qSharedPointerCast<QNodeCreatedChange<QArmatureData>>(change);
- m_skeletonId = typedChange->data.skeletonId;
+ m_skeletonId = node->skeleton() ? node->skeleton()->id() : QNodeId{};
}
-void Armature::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void Armature::cleanup()
{
- switch (e->type()) {
- case Qt3DCore::PropertyUpdated: {
- const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("skeleton"))
- m_skeletonId = change->value().value<QNodeId>();
- break;
- }
-
- default:
- break;
- }
- QBackendNode::sceneChangeEvent(e);
+ m_skeletonId = Qt3DCore::QNodeId();
+ setEnabled(false);
}
} // namespace Render
diff --git a/src/render/geometry/armature_p.h b/src/render/geometry/armature_p.h
index 3e6e52a3f..39baa4a79 100644
--- a/src/render/geometry/armature_p.h
+++ b/src/render/geometry/armature_p.h
@@ -63,7 +63,7 @@ class Q_AUTOTEST_EXPORT Armature : public BackendNode
public:
Armature();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
void cleanup();
Qt3DCore::QNodeId skeletonId() const { return m_skeletonId; }
@@ -73,8 +73,6 @@ public:
const UniformValue &skinningPaletteUniform() const { return m_skinningPaletteUniform; }
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
Qt3DCore::QNodeId m_skeletonId;
UniformValue m_skinningPaletteUniform;
};
diff --git a/src/render/geometry/attribute.cpp b/src/render/geometry/attribute.cpp
index bc6b27851..de44c5fe3 100644
--- a/src/render/geometry/attribute.cpp
+++ b/src/render/geometry/attribute.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "attribute_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qbuffer.h>
#include <Qt3DRender/private/qattribute_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
@@ -83,78 +82,54 @@ void Attribute::cleanup()
m_nameId = 0;
}
-void Attribute::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void Attribute::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAttributeData>>(change);
- const auto &data = typedChange->data;
- m_bufferId = data.bufferId;
- m_name = data.name;
- m_nameId = StringToInt::lookupId(m_name);
- m_vertexBaseType = data.vertexBaseType;
- m_vertexSize = data.vertexSize;
- m_count = data.count;
- m_byteStride = data.byteStride;
- m_byteOffset = data.byteOffset;
- m_divisor = data.divisor;
- m_attributeType = data.attributeType;
- m_attributeDirty = true;
-}
-
-/*!
- \fn Qt3DRender::QAttribute::dataSizeChanged(uint vertexSize)
-
- The signal is emitted with \a vertexSize when the dataSize changes.
-
-*/
-/*!
- \fn Qt3DRender::QAttribute::dataTypeChanged(Qt3DRender::QAttribute::VertexBaseType vertexBaseType)
-
- The signal is emitted with \a vertexBaseType when the dataType changed.
-*/
-void Attribute::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyUpdated: {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- QByteArray propertyName = propertyChange->propertyName();
-
- if (propertyName == QByteArrayLiteral("name")) {
- m_name = propertyChange->value().toString();
- m_nameId = StringToInt::lookupId(m_name);
- m_attributeDirty = true;
- } else if (propertyName == QByteArrayLiteral("vertexBaseType")) {
- m_vertexBaseType = static_cast<QAttribute::VertexBaseType>(propertyChange->value().value<int>());
- m_attributeDirty = true;
- } else if (propertyName == QByteArrayLiteral("vertexSize")) {
- m_vertexSize = propertyChange->value().value<uint>();
- m_attributeDirty = true;
- } else if (propertyName == QByteArrayLiteral("count")) {
- m_count = propertyChange->value().value<uint>();
- m_attributeDirty = true;
- } else if (propertyName == QByteArrayLiteral("byteStride")) {
- m_byteStride = propertyChange->value().value<uint>();
- m_attributeDirty = true;
- } else if (propertyName == QByteArrayLiteral("byteOffset")) {
- m_byteOffset = propertyChange->value().value<uint>();
- m_attributeDirty = true;
- } else if (propertyName == QByteArrayLiteral("divisor")) {
- m_divisor = propertyChange->value().value<uint>();
- m_attributeDirty = true;
- } else if (propertyName == QByteArrayLiteral("attributeType")) {
- m_attributeType = static_cast<QAttribute::AttributeType>(propertyChange->value().value<int>());
- m_attributeDirty = true;
- } else if (propertyName == QByteArrayLiteral("buffer")) {
- m_bufferId = propertyChange->value().value<QNodeId>();
- m_attributeDirty = true;
- }
- markDirty(AbstractRenderer::AllDirty);
- break;
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QAttribute *node = qobject_cast<const QAttribute *>(frontEnd);
+ if (!node)
+ return;
+
+ m_attributeDirty = firstTime;
+ if (m_name != node->name()) {
+ m_name = node->name();
+ m_nameId = StringToInt::lookupId(m_name);
+ m_attributeDirty = true;
}
-
- default:
- break;
+ if (m_vertexBaseType != node->vertexBaseType()) {
+ m_vertexBaseType = node->vertexBaseType();
+ m_attributeDirty = true;
}
- BackendNode::sceneChangeEvent(e);
+ if (m_vertexSize != node->vertexSize()) {
+ m_vertexSize = node->vertexSize();
+ m_attributeDirty = true;
+ }
+ if (m_count != node->count()) {
+ m_count = node->count();
+ m_attributeDirty = true;
+ }
+ if (m_byteStride != node->byteStride()) {
+ m_byteStride = node->byteStride();
+ m_attributeDirty = true;
+ }
+ if (m_byteOffset != node->byteOffset()) {
+ m_byteOffset = node->byteOffset();
+ m_attributeDirty = true;
+ }
+ if (m_divisor != node->divisor()) {
+ m_divisor = node->divisor();
+ m_attributeDirty = true;
+ }
+ if (m_attributeType != node->attributeType()) {
+ m_attributeType = node->attributeType();
+ m_attributeDirty = true;
+ }
+ const auto bufferId = node->buffer() ? node->buffer()->id() : QNodeId{};
+ if (bufferId != m_bufferId) {
+ m_bufferId = bufferId;
+ m_attributeDirty = true;
+ }
+
+ markDirty(AbstractRenderer::AllDirty);
}
void Attribute::unsetDirty()
diff --git a/src/render/geometry/attribute_p.h b/src/render/geometry/attribute_p.h
index e01537605..4b47146e1 100644
--- a/src/render/geometry/attribute_p.h
+++ b/src/render/geometry/attribute_p.h
@@ -68,7 +68,7 @@ public:
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
inline Qt3DCore::QNodeId bufferId() const { return m_bufferId; }
inline QString name() const { return m_name; }
@@ -84,8 +84,6 @@ public:
void unsetDirty();
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
Qt3DCore::QNodeId m_bufferId;
QString m_name;
int m_nameId;
diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp
index d60f89c7d..998db3640 100644
--- a/src/render/geometry/buffer.cpp
+++ b/src/render/geometry/buffer.cpp
@@ -113,28 +113,6 @@ void Buffer::updateDataFromGPUToCPU(QByteArray data)
notifyObservers(e);
}
-void Buffer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QBufferData>>(change);
- const auto &data = typedChange->data;
- m_data = data.data;
- m_usage = data.usage;
- m_syncData = data.syncData;
- m_access = data.access;
- m_bufferDirty = true;
-
- if (!m_data.isEmpty())
- forceDataUpload();
-
- m_functor = data.functor;
- Q_ASSERT(m_manager);
- if (m_functor)
- m_manager->addDirtyBuffer(peerId());
-
- m_manager->addBufferReference(peerId());
- markDirty(AbstractRenderer::BuffersDirty);
-}
-
void Buffer::forceDataUpload()
{
// We push back an update with offset = -1
@@ -145,40 +123,50 @@ void Buffer::forceDataUpload()
m_bufferUpdates.push_back(updateNewData);
}
-void Buffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void Buffer::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- QByteArray propertyName = propertyChange->propertyName();
- if (propertyName == QByteArrayLiteral("data")) {
- QByteArray newData = propertyChange->value().toByteArray();
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QBuffer *node = qobject_cast<const QBuffer *>(frontEnd);
+ if (!node)
+ return;
+
+ if (firstTime && m_manager != nullptr)
+ m_manager->addBufferReference(peerId());
+
+ m_syncData = node->isSyncData();
+ m_access = node->accessType();
+ if (m_usage != node->usage()) {
+ m_usage = node->usage();
+ m_bufferDirty = true;
+ }
+ {
+ QBufferDataGeneratorPtr newGenerator = node->dataGenerator();
+ bool dirty = (newGenerator && m_functor && !(*newGenerator == *m_functor)) ||
+ (newGenerator.isNull() && !m_functor.isNull()) ||
+ (!newGenerator.isNull() && m_functor.isNull());
+ m_bufferDirty |= dirty;
+ m_functor = newGenerator;
+ if (m_functor && m_manager != nullptr)
+ m_manager->addDirtyBuffer(peerId());
+ }
+ {
+ QVariant v = node->property("QT3D_updateData");
+ if (v.isValid()) {
+ Qt3DRender::QBufferUpdate updateData = v.value<Qt3DRender::QBufferUpdate>();
+ m_data.replace(updateData.offset, updateData.data.size(), updateData.data);
+ m_bufferUpdates.push_back(updateData);
+ m_bufferDirty = true;
+ const_cast<QBuffer *>(node)->setProperty("QT3D_updateData", {});
+ } else {
+ QByteArray newData = node->data();
bool dirty = m_data != newData;
m_bufferDirty |= dirty;
m_data = newData;
- if (dirty)
+ if (dirty && !m_data.isEmpty())
forceDataUpload();
- } else if (propertyName == QByteArrayLiteral("updateData")) {
- Qt3DRender::QBufferUpdate updateData = propertyChange->value().value<Qt3DRender::QBufferUpdate>();
- m_data.replace(updateData.offset, updateData.data.size(), updateData.data);
- m_bufferUpdates.push_back(updateData);
- m_bufferDirty = true;
- } else if (propertyName == QByteArrayLiteral("usage")) {
- m_usage = static_cast<QBuffer::UsageType>(propertyChange->value().value<int>());
- m_bufferDirty = true;
- } else if (propertyName == QByteArrayLiteral("accessType")) {
- m_access = static_cast<QBuffer::AccessType>(propertyChange->value().value<int>());
- } else if (propertyName == QByteArrayLiteral("dataGenerator")) {
- QBufferDataGeneratorPtr newGenerator = propertyChange->value().value<QBufferDataGeneratorPtr>();
- m_bufferDirty |= !(newGenerator && m_functor && *newGenerator == *m_functor);
- m_functor = newGenerator;
- if (m_functor && m_manager != nullptr)
- m_manager->addDirtyBuffer(peerId());
- } else if (propertyName == QByteArrayLiteral("syncData")) {
- m_syncData = propertyChange->value().toBool();
}
- markDirty(AbstractRenderer::BuffersDirty);
}
- BackendNode::sceneChangeEvent(e);
+ markDirty(AbstractRenderer::BuffersDirty);
}
// Called by Renderer once the buffer has been uploaded to OpenGL
diff --git a/src/render/geometry/buffer_p.h b/src/render/geometry/buffer_p.h
index 9a171599d..a3f52d1b3 100644
--- a/src/render/geometry/buffer_p.h
+++ b/src/render/geometry/buffer_p.h
@@ -73,7 +73,7 @@ public:
~Buffer();
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
void setManager(BufferManager *manager);
void executeFunctor();
@@ -88,7 +88,6 @@ public:
void unsetDirty();
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
void forceDataUpload();
QBuffer::UsageType m_usage;
diff --git a/src/render/geometry/buffermanager.cpp b/src/render/geometry/buffermanager.cpp
index 14b552879..92f87ab13 100644
--- a/src/render/geometry/buffermanager.cpp
+++ b/src/render/geometry/buffermanager.cpp
@@ -83,12 +83,12 @@ QVector<Qt3DCore::QNodeId> BufferManager::takeBuffersToRelease()
{
QMutexLocker lock(&m_mutex);
QVector<Qt3DCore::QNodeId> buffersToRelease;
- QMutableHashIterator<Qt3DCore::QNodeId, int> it(m_bufferReferences);
- while (it.hasNext()) {
- it.next();
+ for (auto it = m_bufferReferences.begin(), end = m_bufferReferences.end(); it != end; /*erasing*/) {
if (it.value() == 0) {
buffersToRelease.append(it.key());
- it.remove();
+ it = m_bufferReferences.erase(it);
+ } else {
+ ++it;
}
}
return buffersToRelease;
diff --git a/src/render/geometry/geometry.cpp b/src/render/geometry/geometry.cpp
index 4ee02a74d..56ea936be 100644
--- a/src/render/geometry/geometry.cpp
+++ b/src/render/geometry/geometry.cpp
@@ -42,8 +42,8 @@
#include <Qt3DRender/qgeometry.h>
#include <Qt3DRender/private/qgeometry_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
+
+#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -76,51 +76,29 @@ void Geometry::cleanup()
m_shouldNotifyMaxExtentChanged = false;
}
-void Geometry::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QGeometryData>>(change);
- const auto &data = typedChange->data;
- m_attributes = data.attributeIds;
- m_boundingPositionAttribute = data.boundingVolumePositionAttributeId;
- m_geometryDirty = true;
- markDirty(AbstractRenderer::GeometryDirty);
-}
-
-void Geometry::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void Geometry::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- switch (e->type()) {
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("attribute")) {
- m_attributes.push_back(change->addedNodeId());
- m_geometryDirty = true;
- }
- break;
- }
-
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("attribute")) {
- m_attributes.removeOne(change->removedNodeId());
- m_geometryDirty = true;
- }
- break;
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QGeometry *node = qobject_cast<const QGeometry *>(frontEnd);
+ if (!node)
+ return;
+
+ m_geometryDirty |= firstTime;
+
+ QNodeIdVector attribs = qIdsForNodes(node->attributes());
+ std::sort(std::begin(attribs), std::end(attribs));
+ if (m_attributes != attribs) {
+ m_attributes = attribs;
+ m_geometryDirty = true;
}
- case PropertyUpdated: {
+ if ((node->boundingVolumePositionAttribute() && node->boundingVolumePositionAttribute()->id() != m_boundingPositionAttribute) ||
// Note: doesn't set dirtyness as this parameter changing doesn't need a new VAO update.
- const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("boundingVolumePositionAttribute")) {
- m_boundingPositionAttribute = change->value().value<QNodeId>();
- break;
- }
+ (!node->boundingVolumePositionAttribute() && !m_boundingPositionAttribute.isNull())) {
+ m_boundingPositionAttribute = node->boundingVolumePositionAttribute() ? node->boundingVolumePositionAttribute()->id() : QNodeId{};
}
- default:
- break;
- }
markDirty(AbstractRenderer::GeometryDirty);
- BackendNode::sceneChangeEvent(e);
}
void Geometry::unsetDirty()
diff --git a/src/render/geometry/geometry_p.h b/src/render/geometry/geometry_p.h
index e66524787..429a577b0 100644
--- a/src/render/geometry/geometry_p.h
+++ b/src/render/geometry/geometry_p.h
@@ -68,7 +68,7 @@ public:
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
inline QVector<Qt3DCore::QNodeId> attributes() const { return m_attributes; }
inline bool isDirty() const { return m_geometryDirty; }
@@ -82,8 +82,6 @@ public:
void notifyExtentChanged();
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QVector<Qt3DCore::QNodeId> m_attributes;
bool m_geometryDirty;
Qt3DCore::QNodeId m_boundingPositionAttribute;
diff --git a/src/render/geometry/geometryrenderer.cpp b/src/render/geometry/geometryrenderer.cpp
index ea059c6ee..3b460f48c 100644
--- a/src/render/geometry/geometryrenderer.cpp
+++ b/src/render/geometry/geometryrenderer.cpp
@@ -43,8 +43,6 @@
#include <Qt3DRender/private/qgeometryrenderer_p.h>
#include <Qt3DRender/private/qmesh_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DCore/private/qtypedpropertyupdatechange_p.h>
#include <Qt3DCore/private/qservicelocator_p.h>
@@ -105,98 +103,50 @@ void GeometryRenderer::setManager(GeometryRendererManager *manager)
m_manager = manager;
}
-void GeometryRenderer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void GeometryRenderer::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QGeometryRendererData>>(change);
- const auto &data = typedChange->data;
- m_geometryId = data.geometryId;
- m_instanceCount = data.instanceCount;
- m_vertexCount = data.vertexCount;
- m_indexOffset = data.indexOffset;
- m_firstInstance = data.firstInstance;
- m_firstVertex = data.firstVertex;
- m_indexBufferByteOffset = data.indexBufferByteOffset;
- m_restartIndexValue = data.restartIndexValue;
- m_verticesPerPatch = data.verticesPerPatch;
- m_primitiveRestartEnabled = data.primitiveRestart;
- m_primitiveType = data.primitiveType;
-
- Q_ASSERT(m_manager);
- m_geometryFactory = data.geometryFactory;
- if (m_geometryFactory)
- m_manager->addDirtyGeometryRenderer(peerId());
-
- m_dirty = true;
- markDirty(AbstractRenderer::GeometryDirty);
-}
-
-void GeometryRenderer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyUpdated: {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- QByteArray propertyName = propertyChange->propertyName();
-
- if (propertyName == QByteArrayLiteral("instanceCount")) {
- m_instanceCount = propertyChange->value().value<int>();
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("vertexCount")) {
- m_vertexCount = propertyChange->value().value<int>();
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("indexOffset")) {
- m_indexOffset = propertyChange->value().value<int>();
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("firstInstance")) {
- m_firstInstance = propertyChange->value().value<int>();
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("firstVertex")) {
- m_firstVertex = propertyChange->value().value<int>();
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("indexBufferByteOffset")) {
- m_indexBufferByteOffset = propertyChange->value().value<int>();
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("restartIndexValue")) {
- m_restartIndexValue = propertyChange->value().value<int>();
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("verticesPerPatch")) {
- m_verticesPerPatch = propertyChange->value().value<int>();
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("primitiveRestartEnabled")) {
- m_primitiveRestartEnabled = propertyChange->value().toBool();
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("primitiveType")) {
- m_primitiveType = static_cast<QGeometryRenderer::PrimitiveType>(propertyChange->value().value<int>());
- m_dirty = true;
- } else if (propertyName == QByteArrayLiteral("geometryFactory")) {
- QGeometryFactoryPtr newFunctor = propertyChange->value().value<QGeometryFactoryPtr>();
- const bool functorDirty = ((m_geometryFactory && !newFunctor)
- || (!m_geometryFactory && newFunctor)
- || (m_geometryFactory && newFunctor && !(*newFunctor == *m_geometryFactory)));
- m_dirty |= functorDirty;
- if (functorDirty) {
- m_geometryFactory = newFunctor;
- if (m_geometryFactory && m_manager != nullptr)
- m_manager->addDirtyGeometryRenderer(peerId());
- }
- } else if (propertyName == QByteArrayLiteral("geometry")) {
- m_geometryId = propertyChange->value().value<Qt3DCore::QNodeId>();
- m_dirty = true;
- }
- break;
- }
-
- default:
- break;
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QGeometryRenderer *node = qobject_cast<const QGeometryRenderer *>(frontEnd);
+ if (!node)
+ return;
+
+ m_dirty |= m_instanceCount != node->instanceCount();
+ m_instanceCount = node->instanceCount();
+ m_dirty |= m_vertexCount != node->vertexCount();
+ m_vertexCount = node->vertexCount();
+ m_dirty |= m_indexOffset != node->indexOffset();
+ m_indexOffset = node->indexOffset();
+ m_dirty |= m_firstInstance != node->firstInstance();
+ m_firstInstance = node->firstInstance();
+ m_dirty |= m_firstVertex != node->firstVertex();
+ m_firstVertex = node->firstVertex();
+ m_dirty |= m_indexBufferByteOffset != node->indexBufferByteOffset();
+ m_indexBufferByteOffset = node->indexBufferByteOffset();
+ m_dirty |= m_restartIndexValue != node->restartIndexValue();
+ m_restartIndexValue = node->restartIndexValue();
+ m_dirty |= m_verticesPerPatch != node->verticesPerPatch();
+ m_verticesPerPatch = node->verticesPerPatch();
+ m_dirty |= m_primitiveRestartEnabled != node->primitiveRestartEnabled();
+ m_primitiveRestartEnabled = node->primitiveRestartEnabled();
+ m_dirty |= m_primitiveType != node->primitiveType();
+ m_primitiveType = node->primitiveType();
+ m_dirty |= (node->geometry() && m_geometryId != node->geometry()->id()) || (!node->geometry() && !m_geometryId.isNull());
+ m_geometryId = node->geometry() ? node->geometry()->id() : Qt3DCore::QNodeId();
+ QGeometryFactoryPtr newFunctor = node->geometryFactory();
+ const bool functorDirty = ((m_geometryFactory && !newFunctor)
+ || (!m_geometryFactory && newFunctor)
+ || (m_geometryFactory && newFunctor && !(*newFunctor == *m_geometryFactory)));
+ if (functorDirty) {
+ m_dirty = true;
+ m_geometryFactory = newFunctor;
+ if (m_geometryFactory && m_manager != nullptr)
+ m_manager->addDirtyGeometryRenderer(peerId());
}
markDirty(AbstractRenderer::GeometryDirty);
-
- BackendNode::sceneChangeEvent(e);
-
- // Add to dirty list in manager
}
-void GeometryRenderer::executeFunctor()
+GeometryFunctorResult GeometryRenderer::executeFunctor()
{
Q_ASSERT(m_geometryFactory);
@@ -217,7 +167,8 @@ void GeometryRenderer::executeFunctor()
}
// Load geometry
- std::unique_ptr<QGeometry> geometry((*m_geometryFactory)());
+ QGeometry *geometry = (*m_geometryFactory)();
+ QMesh::Status meshLoaderStatus = QMesh::None;
// If the geometry is null, then we were either unable to load it (Error)
// or the mesh is located at a remote url and needs to be downloaded first (Loading)
@@ -226,24 +177,15 @@ void GeometryRenderer::executeFunctor()
// corresponding QGeometryRenderer
const auto appThread = QCoreApplication::instance()->thread();
geometry->moveToThread(appThread);
-
- auto e = QGeometryChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- e->setPropertyName("geometry");
- e->data = std::move(geometry);
- notifyObservers(e);
}
// Send Status
if (isQMeshFunctor) {
QSharedPointer<MeshLoaderFunctor> meshLoader = qSharedPointerCast<MeshLoaderFunctor>(m_geometryFactory);
-
- auto e = QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- e->setPropertyName("status");
- e->setValue(meshLoader->status());
- notifyObservers(e);
+ meshLoaderStatus = meshLoader->status();
}
+
+ return { geometry, meshLoaderStatus };
}
void GeometryRenderer::unsetDirty()
diff --git a/src/render/geometry/geometryrenderer_p.h b/src/render/geometry/geometryrenderer_p.h
index 57d1ca0be..d2ddad4bb 100644
--- a/src/render/geometry/geometryrenderer_p.h
+++ b/src/render/geometry/geometryrenderer_p.h
@@ -54,6 +54,7 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/qgeometryfactory.h>
+#include <Qt3DRender/qmesh.h>
QT_BEGIN_NAMESPACE
@@ -66,6 +67,12 @@ namespace Render {
class GeometryRendererManager;
+struct GeometryFunctorResult
+{
+ QGeometry *geometry;
+ QMesh::Status status;
+};
+
class Q_AUTOTEST_EXPORT GeometryRenderer : public BackendNode
{
public:
@@ -74,8 +81,8 @@ public:
void cleanup();
void setManager(GeometryRendererManager *manager);
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
- void executeFunctor();
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+ GeometryFunctorResult executeFunctor();
inline Qt3DCore::QNodeId geometryId() const { return m_geometryId; }
inline int instanceCount() const { return m_instanceCount; }
@@ -98,8 +105,6 @@ public:
QVector<RayCasting::QBoundingVolume *> triangleData() const;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
Qt3DCore::QNodeId m_geometryId;
int m_instanceCount;
int m_vertexCount;
diff --git a/src/render/geometry/joint.cpp b/src/render/geometry/joint.cpp
index c770564f9..9791f6c52 100644
--- a/src/render/geometry/joint.cpp
+++ b/src/render/geometry/joint.cpp
@@ -39,10 +39,10 @@
#include "joint_p.h"
#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DCore/QJoint>
#include <Qt3DCore/private/qjoint_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
+
+#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -69,62 +69,52 @@ void Joint::cleanup()
setEnabled(false);
}
-void Joint::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void Joint::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- Q_ASSERT(m_jointManager);
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QJointData>>(change);
- const auto &data = typedChange->data;
- m_inverseBindMatrix = data.inverseBindMatrix;
- m_localPose.rotation = data.rotation;
- m_localPose.scale = data.scale;
- m_localPose.translation = data.translation;
- m_childJointIds = data.childJointIds;
- m_name = data.name;
- markDirty(AbstractRenderer::JointDirty);
- m_jointManager->addDirtyJoint(peerId());
-}
+ const Qt3DCore::QJoint *joint = qobject_cast<const Qt3DCore::QJoint *>(frontEnd);
+ if (!joint)
+ return;
+
+ bool jointDirty = firstTime;
+ if (m_localPose.scale != joint->scale()) {
+ m_localPose.scale = joint->scale();
+ jointDirty = true;
+ }
+ if (m_localPose.rotation != joint->rotation()) {
+ m_localPose.rotation = joint->rotation();
+ jointDirty = true;
+ }
+ if (m_localPose.translation != joint->translation()) {
+ m_localPose.translation = joint->translation();
+ jointDirty = true;
+ }
+ if (m_inverseBindMatrix != joint->inverseBindMatrix()) {
+ // Setting the inverse bind matrix should be a rare operation. Usually it is
+ // set once and then remains constant for the duration of the skeleton. So just
+ // trigger a rebuild of the skeleton's SkeletonData which will include obtaining
+ // the inverse bind matrix.
+ m_inverseBindMatrix = joint->inverseBindMatrix();
+ m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_owningSkeleton);
+ }
+ if (m_name != joint->name()) {
+ // Joint name doesn't affect anything in the render aspect so no need
+ // to mark anything as dirty.
+ m_name = joint->name();
-void Joint::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- if (e->type() == PropertyUpdated) {
- const QPropertyUpdatedChangePtr &propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("scale")) {
- m_localPose.scale = propertyChange->value().value<QVector3D>();
- markDirty(AbstractRenderer::JointDirty);
- m_jointManager->addDirtyJoint(peerId());
- } else if (propertyChange->propertyName() == QByteArrayLiteral("rotation")) {
- m_localPose.rotation = propertyChange->value().value<QQuaternion>();
- markDirty(AbstractRenderer::JointDirty);
- m_jointManager->addDirtyJoint(peerId());
- } else if (propertyChange->propertyName() == QByteArrayLiteral("translation")) {
- m_localPose.translation = propertyChange->value().value<QVector3D>();
- markDirty(AbstractRenderer::JointDirty);
- m_jointManager->addDirtyJoint(peerId());
- } else if (propertyChange->propertyName() == QByteArrayLiteral("inverseBindMatrix")) {
- // Setting the inverse bind matrix should be a rare operation. Usually it is
- // set once and then remains constant for the duration of the skeleton. So just
- // trigger a rebuild of the skeleton's SkeletonData which will include obtaining
- // the inverse bind matrix.
- m_inverseBindMatrix = propertyChange->value().value<QMatrix4x4>();
- m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_owningSkeleton);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("name")) {
- // Joint name doesn't affect anything in the render aspect so no need
- // to mark anything as dirty.
- m_name = propertyChange->value().toString();
-
- // TODO: Notify other aspects (animation) about the name change.
- }
- } else if (e->type() == PropertyValueAdded) {
- const auto addedChange = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (addedChange->propertyName() == QByteArrayLiteral("childJoint"))
- m_childJointIds.push_back(addedChange->addedNodeId());
- } else if (e->type() == PropertyValueRemoved) {
- const auto removedChange = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (removedChange->propertyName() == QByteArrayLiteral("childJoint"))
- m_childJointIds.removeOne(removedChange->removedNodeId());
+ // TODO: Notify other aspects (animation) about the name change.
+ }
+
+ Qt3DCore::QNodeIdVector childIds = qIdsForNodes(joint->childJoints());
+ std::sort(std::begin(childIds), std::end(childIds));
+ if (m_childJointIds != childIds)
+ m_childJointIds = childIds;
+
+ if (jointDirty) {
+ markDirty(AbstractRenderer::JointDirty);
+ m_jointManager->addDirtyJoint(peerId());
}
- BackendNode::sceneChangeEvent(e);
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
}
diff --git a/src/render/geometry/joint_p.h b/src/render/geometry/joint_p.h
index e144ac489..de875459e 100644
--- a/src/render/geometry/joint_p.h
+++ b/src/render/geometry/joint_p.h
@@ -69,7 +69,7 @@ public:
Joint();
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
Qt3DCore::Sqt localPose() const { return m_localPose; }
QMatrix4x4 inverseBindMatrix() const { return m_inverseBindMatrix; }
@@ -90,8 +90,6 @@ public:
SkeletonManager *skeletonManager() const { return m_skeletonManager; }
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QMatrix4x4 m_inverseBindMatrix;
Qt3DCore::Sqt m_localPose;
QVector<Qt3DCore::QNodeId> m_childJointIds;
diff --git a/src/render/geometry/qattribute.cpp b/src/render/geometry/qattribute.cpp
index ca467fda9..84d14cfe1 100644
--- a/src/render/geometry/qattribute.cpp
+++ b/src/render/geometry/qattribute.cpp
@@ -41,8 +41,6 @@
#include "qattribute_p.h"
#include <Qt3DRender/qbuffer.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
@@ -505,6 +503,19 @@ Qt3DCore::QNodeCreatedChangeBasePtr QAttribute::createNodeCreationChange() const
return creationChange;
}
+
+/*!
+\fn Qt3DRender::QAttribute::dataSizeChanged(uint vertexSize)
+
+The signal is emitted with \a vertexSize when the dataSize changes.
+*/
+/*!
+\fn Qt3DRender::QAttribute::dataTypeChanged(Qt3DRender::QAttribute::VertexBaseType vertexBaseType)
+
+The signal is emitted with \a vertexBaseType when the dataType changed.
+*/
+
+
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/geometry/qbuffer.cpp b/src/render/geometry/qbuffer.cpp
index e0574a4c5..f27005f2b 100644
--- a/src/render/geometry/qbuffer.cpp
+++ b/src/render/geometry/qbuffer.cpp
@@ -329,7 +329,7 @@ void QBuffer::setData(const QByteArray &bytes)
Q_D(QBuffer);
if (bytes != d->m_data) {
d->m_data = bytes;
- Qt3DCore::QNodePrivate::get(this)->notifyPropertyChange("data", QVariant::fromValue(d->m_data));
+ Qt3DCore::QNodePrivate::get(this)->update();
emit dataChanged(bytes);
}
}
@@ -351,11 +351,8 @@ void QBuffer::updateData(int offset, const QByteArray &bytes)
QBufferUpdate updateData;
updateData.offset = offset;
updateData.data = bytes;
-
- auto e = QPropertyUpdatedChangePtr::create(id());
- e->setPropertyName("updateData");
- e->setValue(QVariant::fromValue(updateData));
- notifyObservers(e);
+ setProperty("QT3D_updateData", QVariant::fromValue(updateData));
+ d->update();
}
/*!
@@ -409,12 +406,7 @@ void QBuffer::setDataGenerator(const QBufferDataGeneratorPtr &functor)
if (functor && d->m_functor && *functor == *d->m_functor)
return;
d->m_functor = functor;
- if (d->m_changeArbiter != nullptr) {
- auto change = QPropertyUpdatedChangePtr::create(d->m_id);
- change->setPropertyName("dataGenerator");
- change->setValue(QVariant::fromValue(d->m_functor));
- d->notifyObservers(change);
- }
+ d->update();
}
/*!
diff --git a/src/render/geometry/qgeometry.cpp b/src/render/geometry/qgeometry.cpp
index ec80e2657..48f054bce 100644
--- a/src/render/geometry/qgeometry.cpp
+++ b/src/render/geometry/qgeometry.cpp
@@ -43,8 +43,6 @@
#include <private/qnode_p.h>
#include <Qt3DRender/qattribute.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
QT_BEGIN_NAMESPACE
@@ -196,11 +194,7 @@ void QGeometry::addAttribute(QAttribute *attribute)
if (!attribute->parent())
attribute->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), attribute);
- change->setPropertyName("attribute");
- d->notifyObservers(change);
- }
+ d->updateNode(attribute, "attribute", Qt3DCore::PropertyValueAdded);
}
}
@@ -212,14 +206,10 @@ void QGeometry::removeAttribute(QAttribute *attribute)
{
Q_ASSERT(attribute);
Q_D(QGeometry);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), attribute);
- change->setPropertyName("attribute");
- d->notifyObservers(change);
- }
d->m_attributes.removeOne(attribute);
// Remove bookkeeping connection
d->unregisterDestructionHelper(attribute);
+ d->updateNode(attribute, "attribute", Qt3DCore::PropertyValueRemoved);
}
void QGeometry::setBoundingVolumePositionAttribute(QAttribute *boundingVolumePositionAttribute)
diff --git a/src/render/geometry/qgeometryrenderer.cpp b/src/render/geometry/qgeometryrenderer.cpp
index 6bff3462f..6e0a24f61 100644
--- a/src/render/geometry/qgeometryrenderer.cpp
+++ b/src/render/geometry/qgeometryrenderer.cpp
@@ -41,9 +41,6 @@
#include "qgeometryrenderer_p.h"
#include <private/qcomponent_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
QT_BEGIN_NAMESPACE
@@ -480,25 +477,7 @@ void QGeometryRenderer::setGeometryFactory(const QGeometryFactoryPtr &factory)
if (factory && d->m_geometryFactory && *factory == *d->m_geometryFactory)
return;
d->m_geometryFactory = factory;
- if (d->m_changeArbiter != nullptr) {
- auto change = QPropertyUpdatedChangePtr::create(d->m_id);
- change->setPropertyName("geometryFactory");
- change->setValue(QVariant::fromValue(d->m_geometryFactory));
- d->notifyObservers(change);
- }
-}
-
-/*!
- \internal
- */
-void QGeometryRenderer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- auto change = qSharedPointerCast<QStaticPropertyUpdatedChangeBase>(e);
- if (change->type() == PropertyUpdated && change->propertyName() == QByteArrayLiteral("geometry")) {
- auto typedChange = qSharedPointerCast<QGeometryChange>(e);
- auto geometry = std::move(typedChange->data);
- setGeometry(geometry.release());
- }
+ d->update();
}
Qt3DCore::QNodeCreatedChangeBasePtr QGeometryRenderer::createNodeCreationChange() const
diff --git a/src/render/geometry/qgeometryrenderer.h b/src/render/geometry/qgeometryrenderer.h
index 81bd1ff67..eceeb9173 100644
--- a/src/render/geometry/qgeometryrenderer.h
+++ b/src/render/geometry/qgeometryrenderer.h
@@ -134,7 +134,6 @@ Q_SIGNALS:
protected:
explicit QGeometryRenderer(QGeometryRendererPrivate &dd, Qt3DCore::QNode *parent = nullptr);
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
private:
Q_DECLARE_PRIVATE(QGeometryRenderer)
diff --git a/src/render/geometry/qmesh.cpp b/src/render/geometry/qmesh.cpp
index 66c4a69bc..1d7d33f9a 100644
--- a/src/render/geometry/qmesh.cpp
+++ b/src/render/geometry/qmesh.cpp
@@ -215,18 +215,6 @@ QMesh::QMesh(QMeshPrivate &dd, QNode *parent)
{
}
-/*! \internal */
-void QMesh::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
-{
- Q_D(QMesh);
- if (change->type() == Qt3DCore::PropertyUpdated) {
- const Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
- if (e->propertyName() == QByteArrayLiteral("status"))
- d->setStatus(e->value().value<QMesh::Status>());
- }
- Qt3DRender::QGeometryRenderer::sceneChangeEvent(change);
-}
-
void QMesh::setSource(const QUrl& source)
{
Q_D(QMesh);
diff --git a/src/render/geometry/qmesh.h b/src/render/geometry/qmesh.h
index 458a21fa4..04fdedc20 100644
--- a/src/render/geometry/qmesh.h
+++ b/src/render/geometry/qmesh.h
@@ -88,7 +88,6 @@ Q_SIGNALS:
protected:
explicit QMesh(QMeshPrivate &dd, Qt3DCore::QNode *parent = nullptr);
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
private:
Q_DECLARE_PRIVATE(QMesh)
diff --git a/src/render/geometry/skeleton.cpp b/src/render/geometry/skeleton.cpp
index 615b76c88..839a1a056 100644
--- a/src/render/geometry/skeleton.cpp
+++ b/src/render/geometry/skeleton.cpp
@@ -36,24 +36,19 @@
#include "skeleton_p.h"
-#include <Qt3DCore/qjoint.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
+#include <Qt3DCore/qjoint.h>
#include <Qt3DRender/private/abstractrenderer_p.h>
-#include <Qt3DRender/private/gltfskeletonloader_p.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/renderlogging_p.h>
-#include <Qt3DRender/private/qurlhelper_p.h>
#include <Qt3DCore/private/qskeletoncreatedchange_p.h>
#include <Qt3DCore/private/qskeleton_p.h>
#include <Qt3DCore/private/qskeletonloader_p.h>
#include <Qt3DCore/private/qmath3d_p.h>
-#include <Qt3DCore/private/qabstractnodefactory_p.h>
QT_BEGIN_NAMESPACE
@@ -80,61 +75,48 @@ void Skeleton::cleanup()
setEnabled(false);
}
-void Skeleton::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void Skeleton::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- Q_ASSERT(m_skeletonManager);
- m_skeletonHandle = m_skeletonManager->lookupHandle(peerId());
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QAbstractSkeleton *node = qobject_cast<const QAbstractSkeleton *>(frontEnd);
+ if (!node)
+ return;
+ const QSkeleton *skeletonNode = qobject_cast<const QSkeleton *>(frontEnd);
+ const QSkeletonLoader *loaderNode = qobject_cast<const QSkeletonLoader *>(frontEnd);
- const auto skeletonCreatedChange = qSharedPointerCast<QSkeletonCreatedChangeBase>(change);
- switch (skeletonCreatedChange->type()) {
- case QSkeletonCreatedChangeBase::SkeletonLoader: {
- const auto loaderTypedChange = qSharedPointerCast<QSkeletonCreatedChange<QSkeletonLoaderData>>(change);
- const auto &data = loaderTypedChange->data;
- m_dataType = File;
- m_source = data.source;
- m_createJoints = data.createJoints;
- if (!m_source.isEmpty()) {
- markDirty(AbstractRenderer::SkeletonDataDirty);
- m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
+ if (firstTime) {
+ m_skeletonHandle = m_skeletonManager->lookupHandle(peerId());
+
+ if (skeletonNode) {
+ m_dataType = Data;
+ m_rootJointId = skeletonNode->rootJoint()->id();
+ if (!m_rootJointId.isNull()) {
+ markDirty(AbstractRenderer::SkeletonDataDirty);
+ m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
+ }
+ }
+
+ if (loaderNode) {
+ m_dataType = File;
+ m_source = loaderNode->source();
+ if (!m_source.isEmpty()) {
+ markDirty(AbstractRenderer::SkeletonDataDirty);
+ m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
+ }
}
- break;
}
- case QSkeletonCreatedChangeBase::Skeleton:
- const auto typedChange = qSharedPointerCast<QSkeletonCreatedChange<QSkeletonData>>(change);
- const auto &data = typedChange->data;
- m_dataType = Data;
- m_rootJointId = data.rootJointId;
- if (!m_rootJointId.isNull()) {
+ if (loaderNode) {
+ if (loaderNode->source() != m_source) {
+ m_source = loaderNode->source();
markDirty(AbstractRenderer::SkeletonDataDirty);
m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
}
- break;
- }
-}
+ m_createJoints = loaderNode->isCreateJointsEnabled();
-void Skeleton::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case Qt3DCore::PropertyUpdated: {
- const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("localPoses")) {
- // When the animation aspect sends us a new set of local poses, all we
- // need to do is copy them into place. The existing jobs will then update
- // the skinning matrix palette.
- m_skeletonData.localPoses = change->value().value<QVector<Qt3DCore::Sqt>>();
- } else if (change->propertyName() == QByteArrayLiteral("source")) {
- Q_ASSERT(m_dataType == File);
- const auto source = change->value().toUrl();
- if (source != m_source) {
- m_source = source;
- markDirty(AbstractRenderer::SkeletonDataDirty);
- m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
- }
- } else if (change->propertyName() == QByteArrayLiteral("createJointsEnabled")) {
- m_createJoints = change->value().toBool();
- } else if (change->propertyName() == QByteArrayLiteral("rootJoint")) {
- m_rootJointId = change->value().value<QNodeId>();
+ auto newJointId = Qt3DCore::qIdForNode(loaderNode->rootJoint());
+ if (newJointId != m_rootJointId) {
+ m_rootJointId = newJointId;
// If using a QSkeletonLoader to create frontend QJoints, when those joints are
// set on the skeleton, we end up here. In order to allow the subsequent call
@@ -146,228 +128,21 @@ void Skeleton::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
// If the joint changes, we need to rebuild our internal SkeletonData and
// the relationships between joints and skeleton. Mark the skeleton data as
// dirty so that we get a loadSkeletonJob executed to process this skeleton.
- markDirty(AbstractRenderer::SkeletonDataDirty);
- m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
+ if (!m_rootJointId.isNull()) {
+ markDirty(AbstractRenderer::SkeletonDataDirty);
+ m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
+ }
}
-
- break;
}
- default:
- break;
- }
- QBackendNode::sceneChangeEvent(e);
+ auto d = Qt3DCore::QAbstractSkeletonPrivate::get(node);
+ m_skeletonData.localPoses = d->m_localPoses;
}
void Skeleton::setStatus(QSkeletonLoader::Status status)
{
- if (status != m_status) {
+ if (status != m_status)
m_status = status;
- Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("status");
- e->setValue(QVariant::fromValue(m_status));
- notifyObservers(e);
- }
-}
-
-void Skeleton::notifyJointCount()
-{
- Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("jointCount");
- e->setValue(jointCount());
- notifyObservers(e);
-}
-
-void Skeleton::notifyJointNamesAndPoses()
-{
- auto e = QPropertyUpdatedChangePtr::create(peerId());
- JointNamesAndLocalPoses payload{m_skeletonData.jointNames, m_skeletonData.localPoses};
- e->setDeliveryFlags(Qt3DCore::QSceneChange::BackendNodes);
- e->setPropertyName("jointNamesAndLocalPoses");
- e->setValue(QVariant::fromValue(payload));
- notifyObservers(e);
-}
-
-void Skeleton::loadSkeleton()
-{
- qCDebug(Jobs) << Q_FUNC_INFO << m_source;
- clearData();
-
- // Load the data
- switch (m_dataType) {
- case File:
- loadSkeletonFromUrl();
- break;
-
- case Data:
- loadSkeletonFromData();
- break;
-
- default:
- Q_UNREACHABLE();
- }
-
- // If using a loader inform the frontend of the status change.
- // Don't bother if asked to create frontend joints though. When
- // the backend gets notified of those joints we'll update the
- // status at that point.
- if (m_dataType == File && !m_createJoints) {
- if (jointCount() == 0)
- setStatus(QSkeletonLoader::Error);
- else
- setStatus(QSkeletonLoader::Ready);
- }
- notifyJointCount();
- notifyJointNamesAndPoses();
-
- qCDebug(Jobs) << "Loaded skeleton data:" << *this;
-}
-
-void Skeleton::loadSkeletonFromUrl()
-{
- // TODO: Handle remote files
- QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_source);
- QFileInfo info(filePath);
- if (!info.exists()) {
- qWarning() << "Could not open skeleton file:" << filePath;
- setStatus(Qt3DCore::QSkeletonLoader::Error);
- return;
- }
-
- QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly)) {
- qWarning() << "Could not open skeleton file:" << filePath;
- setStatus(Qt3DCore::QSkeletonLoader::Error);
- return;
- }
-
- // TODO: Make plugin based for more file type support. For now gltf or native
- const QString ext = info.suffix();
- if (ext == QLatin1String("gltf")) {
- GLTFSkeletonLoader loader;
- loader.load(&file);
- m_skeletonData = loader.createSkeleton(m_name);
-
- // If the user has requested it, create the frontend nodes for the joints
- // and send them to the (soon to be owning) QSkeletonLoader.
- if (m_createJoints) {
- std::unique_ptr<QJoint> rootJoint(createFrontendJoints(m_skeletonData));
- if (!rootJoint) {
- qWarning() << "Failed to create frontend joints";
- setStatus(Qt3DCore::QSkeletonLoader::Error);
- return;
- }
-
- // Move the QJoint tree to the main thread and notify the
- // corresponding QSkeletonLoader
- const auto appThread = QCoreApplication::instance()->thread();
- rootJoint->moveToThread(appThread);
-
- auto e = QJointChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- e->setPropertyName("rootJoint");
- e->data = std::move(rootJoint);
- notifyObservers(e);
-
- // Clear the skeleton data. It will be recreated from the
- // frontend joints. A little bit inefficient but ensures
- // that joints created this way and via QSkeleton go through
- // the same code path.
- m_skeletonData = SkeletonData();
- }
- } else if (ext == QLatin1String("json")) {
- // TODO: Support native skeleton type
- } else {
- qWarning() << "Unknown skeleton file type:" << ext;
- setStatus(Qt3DCore::QSkeletonLoader::Error);
- return;
- }
- m_skinningPalette.resize(m_skeletonData.joints.size());
-}
-
-void Skeleton::loadSkeletonFromData()
-{
- // Recurse down through the joint hierarchy and process it into
- // the vector of joints used within SkeletonData. The recursion
- // ensures that a parent always appears before its children in
- // the vector of JointInfo objects.
- //
- // In addition, we set up a mapping from the joint ids to the
- // index of the corresponding JointInfo object in the vector.
- // This will allow us to easily update entries in the vector of
- // JointInfos when a Joint node marks itself as dirty.
- const int rootParentIndex = -1;
- processJointHierarchy(m_rootJointId, rootParentIndex, m_skeletonData);
- m_skinningPalette.resize(m_skeletonData.joints.size());
-}
-
-Qt3DCore::QJoint *Skeleton::createFrontendJoints(const SkeletonData &skeletonData) const
-{
- if (skeletonData.joints.isEmpty())
- return nullptr;
-
- // Create frontend joints from the joint info objects
- QVector<QJoint *> frontendJoints;
- const int jointCount = skeletonData.joints.size();
- frontendJoints.reserve(jointCount);
- for (int i = 0; i < jointCount; ++i) {
- const QMatrix4x4 &inverseBindMatrix = skeletonData.joints[i].inverseBindPose;
- const QString &jointName = skeletonData.jointNames[i];
- const Qt3DCore::Sqt &localPose = skeletonData.localPoses[i];
- frontendJoints.push_back(createFrontendJoint(jointName, localPose, inverseBindMatrix));
- }
-
- // Now go through and resolve the parent for each joint
- for (int i = 0; i < frontendJoints.size(); ++i) {
- const auto parentIndex = skeletonData.joints[i].parentIndex;
- if (parentIndex == -1)
- continue;
-
- // It's not enough to just set up the QObject parent-child relationship.
- // We need to explicitly add the child to the parent's list of joints so
- // that information is then propagated to the backend.
- frontendJoints[parentIndex]->addChildJoint(frontendJoints[i]);
- }
-
- return frontendJoints[0];
-}
-
-Qt3DCore::QJoint *Skeleton::createFrontendJoint(const QString &jointName,
- const Qt3DCore::Sqt &localPose,
- const QMatrix4x4 &inverseBindMatrix) const
-{
- auto joint = QAbstractNodeFactory::createNode<QJoint>("QJoint");
- joint->setTranslation(localPose.translation);
- joint->setRotation(localPose.rotation);
- joint->setScale(localPose.scale);
- joint->setInverseBindMatrix(inverseBindMatrix);
- joint->setName(jointName);
- return joint;
-}
-
-void Skeleton::processJointHierarchy(Qt3DCore::QNodeId jointId,
- int parentJointIndex,
- SkeletonData &skeletonData)
-{
- // Lookup the joint, create a JointInfo, and add an entry to the index map
- Joint *joint = m_renderer->nodeManagers()->jointManager()->lookupResource(jointId);
- Q_ASSERT(joint);
- joint->setOwningSkeleton(m_skeletonHandle);
- const JointInfo jointInfo(joint, parentJointIndex);
- skeletonData.joints.push_back(jointInfo);
- skeletonData.localPoses.push_back(joint->localPose());
- skeletonData.jointNames.push_back(joint->name());
-
- const int jointIndex = skeletonData.joints.size() - 1;
- const HJoint jointHandle = m_jointManager->lookupHandle(jointId);
- skeletonData.jointIndices.insert(jointHandle, jointIndex);
-
- // Recurse to the children
- const auto childIds = joint->childJointIds();
- for (const auto childJointId : childIds)
- processJointHierarchy(childJointId, jointIndex, skeletonData);
}
void Skeleton::clearData()
@@ -379,6 +154,12 @@ void Skeleton::clearData()
m_skeletonData.jointIndices.clear();
}
+void Skeleton::setSkeletonData(const SkeletonData &data)
+{
+ m_skeletonData = data;
+ m_skinningPalette.resize(m_skeletonData.joints.size());
+}
+
// Called from UpdateSkinningPaletteJob
void Skeleton::setLocalPose(HJoint jointHandle, const Qt3DCore::Sqt &localPose)
{
diff --git a/src/render/geometry/skeleton_p.h b/src/render/geometry/skeleton_p.h
index 4a14e5c1c..eb9551f07 100644
--- a/src/render/geometry/skeleton_p.h
+++ b/src/render/geometry/skeleton_p.h
@@ -75,6 +75,12 @@ class SkeletonManager;
class Q_AUTOTEST_EXPORT Skeleton : public BackendNode
{
public:
+ enum SkeletonDataType {
+ Unknown,
+ File,
+ Data
+ };
+
Skeleton();
void setSkeletonManager(SkeletonManager *skeletonManager) { m_skeletonManager = skeletonManager; }
@@ -84,52 +90,40 @@ public:
JointManager *jointManager() const { return m_jointManager; }
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
void setStatus(Qt3DCore::QSkeletonLoader::Status status);
Qt3DCore::QSkeletonLoader::Status status() const { return m_status; }
QUrl source() const { return m_source; }
+ SkeletonDataType dataType() const { return m_dataType; }
+ bool createJoints() const { return m_createJoints; }
void setName(const QString &name) { m_name = name; }
QString name() const { return m_name; }
int jointCount() const { return m_skeletonData.joints.size(); }
- void notifyJointCount();
- void notifyJointNamesAndPoses();
QVector<JointInfo> joints() const { return m_skeletonData.joints; }
+ QVector<QString> jointNames() const { return m_skeletonData.jointNames; }
+ QVector<Qt3DCore::Sqt> localPoses() const { return m_skeletonData.localPoses; }
Qt3DCore::QNodeId rootJointId() const { return m_rootJointId; }
// Called from jobs
- void loadSkeleton();
void setLocalPose(HJoint jointHandle, const Qt3DCore::Sqt &localPose);
QVector<QMatrix4x4> calculateSkinningMatrixPalette();
+ void clearData();
+ void setSkeletonData(const SkeletonData &data);
+ const SkeletonData &skeletonData() const { return m_skeletonData; }
+ SkeletonData skeletonData() { return m_skeletonData; }
+
// Allow unit tests to set the data type
-#if !defined(QT_BUILD_INTERNAL)
-private:
-#endif
- enum SkeletonDataType {
- Unknown,
- File,
- Data
- };
#if defined(QT_BUILD_INTERNAL)
public:
void setDataType(SkeletonDataType dataType) { m_dataType = dataType; }
#endif
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
- void loadSkeletonFromUrl();
- void loadSkeletonFromData();
- Qt3DCore::QJoint *createFrontendJoints(const SkeletonData &skeletonData) const;
- Qt3DCore::QJoint *createFrontendJoint(const QString &jointName,
- const Qt3DCore::Sqt &localPose,
- const QMatrix4x4 &inverseBindMatrix) const;
- void processJointHierarchy(Qt3DCore::QNodeId jointId, int parentJointIndex, SkeletonData &skeletonData);
- void clearData();
-
QVector<QMatrix4x4> m_skinningPalette;
// QSkeletonLoader Properties
diff --git a/src/render/io/qsceneloader.cpp b/src/render/io/qsceneloader.cpp
index d66fe3080..cf1e45355 100644
--- a/src/render/io/qsceneloader.cpp
+++ b/src/render/io/qsceneloader.cpp
@@ -219,6 +219,27 @@ void QSceneLoaderPrivate::setStatus(QSceneLoader::Status status)
}
}
+void QSceneLoaderPrivate::setSceneRoot(QEntity *root)
+{
+ // If we already have a scene sub tree, delete it
+ if (m_subTreeRoot) {
+ delete m_subTreeRoot;
+ m_subTreeRoot = nullptr;
+ }
+
+ // If we have successfully loaded a scene, graft it in
+ if (root) {
+ // Get the entity to which this component is attached
+ const Qt3DCore::QNodeIdVector entities = m_scene->entitiesForComponent(m_id);
+ Q_ASSERT(entities.size() == 1);
+ Qt3DCore::QNodeId parentEntityId = entities.first();
+ QEntity *parentEntity = qobject_cast<QEntity *>(m_scene->lookupNode(parentEntityId));
+ root->setParent(parentEntity);
+ m_subTreeRoot = root;
+ populateEntityMap(m_subTreeRoot);
+ }
+}
+
/*!
The constructor creates an instance with the specified \a parent.
*/
@@ -238,38 +259,6 @@ QSceneLoader::QSceneLoader(QSceneLoaderPrivate &dd, QNode *parent)
{
}
-// Called in main thread
-/*! \internal */
-void QSceneLoader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
-{
- Q_D(QSceneLoader);
- QPropertyUpdatedChangePtr e = qSharedPointerCast<QPropertyUpdatedChange>(change);
- if (e->type() == PropertyUpdated) {
- if (e->propertyName() == QByteArrayLiteral("scene")) {
- // If we already have a scene sub tree, delete it
- if (d->m_subTreeRoot) {
- delete d->m_subTreeRoot;
- d->m_subTreeRoot = nullptr;
- }
-
- // If we have successfully loaded a scene, graft it in
- auto *subTreeRoot = e->value().value<Qt3DCore::QEntity *>();
- if (subTreeRoot) {
- // Get the entity to which this component is attached
- const Qt3DCore::QNodeIdVector entities = d->m_scene->entitiesForComponent(d->m_id);
- Q_ASSERT(entities.size() == 1);
- Qt3DCore::QNodeId parentEntityId = entities.first();
- QEntity *parentEntity = qobject_cast<QEntity *>(d->m_scene->lookupNode(parentEntityId));
- subTreeRoot->setParent(parentEntity);
- d->m_subTreeRoot = subTreeRoot;
- d->populateEntityMap(d->m_subTreeRoot);
- }
- } else if (e->propertyName() == QByteArrayLiteral("status")) {
- d->setStatus(e->value().value<QSceneLoader::Status>());
- }
- }
-}
-
QUrl QSceneLoader::source() const
{
Q_D(const QSceneLoader);
diff --git a/src/render/io/qsceneloader.h b/src/render/io/qsceneloader.h
index 4cb743333..6842a6926 100644
--- a/src/render/io/qsceneloader.h
+++ b/src/render/io/qsceneloader.h
@@ -60,7 +60,6 @@ public:
explicit QSceneLoader(Qt3DCore::QNode *parent = nullptr);
~QSceneLoader();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
enum Status {
None = 0,
Loading,
diff --git a/src/render/io/qsceneloader_p.h b/src/render/io/qsceneloader_p.h
index 50745c66f..213bc1104 100644
--- a/src/render/io/qsceneloader_p.h
+++ b/src/render/io/qsceneloader_p.h
@@ -67,6 +67,7 @@ public:
QSceneLoaderPrivate();
void setStatus(QSceneLoader::Status status);
+ void setSceneRoot(Qt3DCore::QEntity *root);
Q_DECLARE_PUBLIC(QSceneLoader)
diff --git a/src/render/io/scene.cpp b/src/render/io/scene.cpp
index d95f42a48..089091701 100644
--- a/src/render/io/scene.cpp
+++ b/src/render/io/scene.cpp
@@ -66,46 +66,20 @@ void Scene::cleanup()
m_source.clear();
}
-void Scene::setStatus(QSceneLoader::Status status)
+void Scene::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- // Send the new subtree to the frontend or notify failure
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("status");
- e->setValue(QVariant::fromValue(status));
- notifyObservers(e);
-}
-
-void Scene::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QSceneLoaderData>>(change);
- const auto &data = typedChange->data;
- m_source = data.source;
- Q_ASSERT(m_sceneManager);
- if (Qt3DCore::QDownloadHelperService::isLocal(m_source))
- m_sceneManager->addSceneData(m_source, peerId());
- else
- m_sceneManager->startSceneDownload(m_source, peerId());
-}
-
-void Scene::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("source")) {
- m_source = propertyChange->value().toUrl();
-
- // If the source is empty -> we need to unload anything that was
- // previously loaded and reset the status accordingly. This means
- // we need to call addSceneData with the empty source to send a
- // change to the frontend that will trigger the removal of the
- // previous scene. The reason this scheme is employed is because
- // the backend also takes care of updating the status.
- if (m_source.isEmpty() || Qt3DCore::QDownloadHelperService::isLocal(m_source))
- m_sceneManager->addSceneData(m_source, peerId());
- else
- m_sceneManager->startSceneDownload(m_source, peerId());
- }
+ const QSceneLoader *node = qobject_cast<const QSceneLoader *>(frontEnd);
+ if (!node)
+ return;
+
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (node->source() != m_source) {
+ m_source = node->source();
+ if (m_source.isEmpty() || Qt3DCore::QDownloadHelperService::isLocal(m_source))
+ m_sceneManager->addSceneData(m_source, peerId());
+ else
+ m_sceneManager->startSceneDownload(m_source, peerId());
}
markDirty(AbstractRenderer::AllDirty);
}
@@ -115,22 +89,6 @@ QUrl Scene::source() const
return m_source;
}
-void Scene::setSceneSubtree(Qt3DCore::QEntity *subTree)
-{
- if (subTree) {
- // Move scene sub tree to the application thread so that it can be grafted in.
- const auto appThread = QCoreApplication::instance()->thread();
- subTree->moveToThread(appThread);
- }
-
- // Send the new subtree to the frontend or notify failure
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("scene");
- e->setValue(QVariant::fromValue(subTree));
- notifyObservers(e);
-}
-
void Scene::setSceneManager(SceneManager *manager)
{
if (m_sceneManager != manager)
diff --git a/src/render/io/scene_p.h b/src/render/io/scene_p.h
index 631f23124..bf625b369 100644
--- a/src/render/io/scene_p.h
+++ b/src/render/io/scene_p.h
@@ -72,17 +72,14 @@ class Q_AUTOTEST_EXPORT Scene : public BackendNode
public:
Scene();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
QUrl source() const;
- void setSceneSubtree(Qt3DCore::QEntity *subTree);
void setSceneManager(SceneManager *manager);
void cleanup();
void setStatus(QSceneLoader::Status status);
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
SceneManager *m_sceneManager;
QUrl m_source;
};
diff --git a/src/render/jobs/abstractpickingjob.cpp b/src/render/jobs/abstractpickingjob.cpp
index 74e6a7f80..35e658535 100644
--- a/src/render/jobs/abstractpickingjob.cpp
+++ b/src/render/jobs/abstractpickingjob.cpp
@@ -58,13 +58,24 @@ namespace Qt3DRender {
namespace Render {
AbstractPickingJob::AbstractPickingJob()
- : m_manager(nullptr)
+ : Qt3DCore::QAspectJob()
+ , m_manager(nullptr)
, m_node(nullptr)
, m_frameGraphRoot(nullptr)
, m_renderSettings(nullptr)
{
}
+AbstractPickingJob::AbstractPickingJob(Qt3DCore::QAspectJobPrivate &dd)
+ : Qt3DCore::QAspectJob(dd)
+ , m_manager(nullptr)
+ , m_node(nullptr)
+ , m_frameGraphRoot(nullptr)
+ , m_renderSettings(nullptr)
+{
+
+}
+
void AbstractPickingJob::setRoot(Entity *root)
{
m_node = root;
diff --git a/src/render/jobs/abstractpickingjob_p.h b/src/render/jobs/abstractpickingjob_p.h
index 059c87aa7..c0c6ed7e9 100644
--- a/src/render/jobs/abstractpickingjob_p.h
+++ b/src/render/jobs/abstractpickingjob_p.h
@@ -90,6 +90,8 @@ public:
const QRect &viewport);
protected:
+ AbstractPickingJob(Qt3DCore::QAspectJobPrivate &dd);
+
void run() final;
NodeManagers *m_manager;
diff --git a/src/render/jobs/framecleanupjob.cpp b/src/render/jobs/framecleanupjob.cpp
index ed01e73b4..17ca60bff 100644
--- a/src/render/jobs/framecleanupjob.cpp
+++ b/src/render/jobs/framecleanupjob.cpp
@@ -43,7 +43,6 @@
#include <private/entity_p.h>
#include <private/shaderdata_p.h>
#include <private/managers_p.h>
-#include <private/texturedatamanager_p.h>
#include <private/sphere_p.h>
#include <Qt3DRender/private/job_common_p.h>
diff --git a/src/render/jobs/genericlambdajob_p.h b/src/render/jobs/genericlambdajob_p.h
index d72975761..4d93f0f8d 100644
--- a/src/render/jobs/genericlambdajob_p.h
+++ b/src/render/jobs/genericlambdajob_p.h
@@ -84,6 +84,49 @@ private:
template<typename T>
using GenericLambdaJobPtr = QSharedPointer<GenericLambdaJob<T>>;
+template<typename T, typename U>
+class GenericLambdaJobAndPostFramePrivate : public Qt3DCore::QAspectJobPrivate
+{
+public:
+ explicit GenericLambdaJobAndPostFramePrivate(U postFrameCallable)
+ : m_postFrameCallable(postFrameCallable)
+ {}
+
+ ~GenericLambdaJobAndPostFramePrivate() override {}
+
+ void postFrame(Qt3DCore::QAspectManager *manager) override
+ {
+ m_postFrameCallable(manager);
+ }
+
+private:
+ U m_postFrameCallable;
+};
+
+template<typename T, typename U>
+class GenericLambdaJobAndPostFrame : public Qt3DCore::QAspectJob
+{
+public:
+ explicit GenericLambdaJobAndPostFrame(T runCallable, U postFrameCallable, JobTypes::JobType type = JobTypes::GenericLambda)
+ : Qt3DCore::QAspectJob(*new GenericLambdaJobAndPostFramePrivate<T, U>(postFrameCallable))
+ , m_runCallable(runCallable)
+ {
+ SET_JOB_RUN_STAT_TYPE(this, type, 0);
+ }
+
+ // QAspectJob interface
+ void run() final
+ {
+ m_runCallable();
+ }
+
+private:
+ T m_runCallable;
+};
+
+template<typename T, typename U>
+using GenericLambdaJobAndPostFramePtr = QSharedPointer<GenericLambdaJobAndPostFrame<T, U>>;
+
} // Render
} // Qt3DRender
diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h
index 99bf99195..7aa6f64ba 100644
--- a/src/render/jobs/job_common_p.h
+++ b/src/render/jobs/job_common_p.h
@@ -100,7 +100,7 @@ namespace JobTypes {
UpdateMeshTriangleList,
FilterCompatibleTechniques,
UpdateLevelOfDetail,
- SyncTextureLoading,
+ SyncLoadingJobs,
LoadSkeleton,
UpdateSkinningPalette,
ProximityFiltering,
@@ -109,7 +109,7 @@ namespace JobTypes {
UpdateLayerEntity,
SendTextureChangesToFrontend,
SendSetFenceHandlesToFrontend,
- UpdateEntityHierarchy,
+ SendDisablesToFrontend
};
} // JobTypes
diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri
index 0c326c0b5..2181e4a95 100644
--- a/src/render/jobs/jobs.pri
+++ b/src/render/jobs/jobs.pri
@@ -4,7 +4,6 @@ HEADERS += \
$$PWD/updateworldtransformjob_p.h \
$$PWD/loadscenejob_p.h \
$$PWD/framecleanupjob_p.h \
- $$PWD/loadtexturedatajob_p.h \
$$PWD/loadbufferjob_p.h \
$$PWD/loadgeometryjob_p.h \
$$PWD/calcboundingvolumejob_p.h \
@@ -31,14 +30,12 @@ HEADERS += \
$$PWD/filterproximitydistancejob_p.h \
$$PWD/abstractpickingjob_p.h \
$$PWD/raycastingjob_p.h \
- $$PWD/updateentityhierarchyjob_p.h \
$$PWD/updateentitylayersjob_p.h
SOURCES += \
$$PWD/updateworldtransformjob.cpp \
$$PWD/loadscenejob.cpp \
$$PWD/framecleanupjob.cpp \
- $$PWD/loadtexturedatajob.cpp \
$$PWD/loadbufferjob.cpp \
$$PWD/loadgeometryjob.cpp \
$$PWD/calcboundingvolumejob.cpp \
@@ -62,6 +59,5 @@ SOURCES += \
$$PWD/filterproximitydistancejob.cpp \
$$PWD/abstractpickingjob.cpp \
$$PWD/raycastingjob.cpp \
- $$PWD/updateentityhierarchyjob.cpp \
$$PWD/updateentitylayersjob.cpp
diff --git a/src/render/jobs/loadgeometryjob.cpp b/src/render/jobs/loadgeometryjob.cpp
index d28b15a7c..88930038a 100644
--- a/src/render/jobs/loadgeometryjob.cpp
+++ b/src/render/jobs/loadgeometryjob.cpp
@@ -41,6 +41,8 @@
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/job_common_p.h>
+#include <Qt3DCore/private/qaspectmanager_p.h>
+#include <Qt3DRender/private/qmesh_p.h>
QT_BEGIN_NAMESPACE
@@ -48,8 +50,19 @@ namespace Qt3DRender {
namespace Render {
+class LoadGeometryJobPrivate : public Qt3DCore::QAspectJobPrivate
+{
+public:
+ LoadGeometryJobPrivate() {}
+ ~LoadGeometryJobPrivate() {}
+
+ void postFrame(Qt3DCore::QAspectManager *manager) override;
+
+ QVector<std::pair<Qt3DCore::QNodeId, GeometryFunctorResult>> m_updates;
+};
+
LoadGeometryJob::LoadGeometryJob(const HGeometryRenderer &handle)
- : QAspectJob()
+ : QAspectJob(*new LoadGeometryJobPrivate)
, m_handle(handle)
, m_nodeManagers(nullptr)
{
@@ -62,9 +75,27 @@ LoadGeometryJob::~LoadGeometryJob()
void LoadGeometryJob::run()
{
+ Q_D(LoadGeometryJob);
GeometryRenderer *geometryRenderer = m_nodeManagers->geometryRendererManager()->data(m_handle);
if (geometryRenderer != nullptr)
- geometryRenderer->executeFunctor();
+ d->m_updates.push_back({ geometryRenderer->peerId(), geometryRenderer->executeFunctor() });
+}
+
+void LoadGeometryJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
+{
+ const auto updates = std::move(m_updates);
+ for (const auto &update : updates) {
+ QGeometryRenderer *gR = static_cast<decltype(gR)>(manager->lookupNode(update.first));
+ const GeometryFunctorResult &result = update.second;
+ gR->setGeometry(result.geometry);
+
+ // Set status if gR is a QMesh instance
+ QMesh *mesh = qobject_cast<QMesh *>(gR);
+ if (mesh) {
+ QMeshPrivate *dMesh = static_cast<decltype(dMesh)>(Qt3DCore::QNodePrivate::get(mesh));
+ dMesh->setStatus(result.status);
+ }
+ }
}
} // namespace Render
diff --git a/src/render/jobs/loadgeometryjob_p.h b/src/render/jobs/loadgeometryjob_p.h
index c02739647..998d543ac 100644
--- a/src/render/jobs/loadgeometryjob_p.h
+++ b/src/render/jobs/loadgeometryjob_p.h
@@ -62,6 +62,7 @@ namespace Qt3DRender {
namespace Render {
class NodeManagers;
+class LoadGeometryJobPrivate;
class Q_AUTOTEST_EXPORT LoadGeometryJob : public Qt3DCore::QAspectJob
{
@@ -75,6 +76,9 @@ protected:
void run() override;
HGeometryRenderer m_handle;
NodeManagers *m_nodeManagers;
+
+private:
+ Q_DECLARE_PRIVATE(LoadGeometryJob)
};
typedef QSharedPointer<LoadGeometryJob> LoadGeometryJobPtr;
diff --git a/src/render/jobs/loadscenejob.cpp b/src/render/jobs/loadscenejob.cpp
index 9885d3225..f858f82e3 100644
--- a/src/render/jobs/loadscenejob.cpp
+++ b/src/render/jobs/loadscenejob.cpp
@@ -42,10 +42,12 @@
#include <private/nodemanagers_p.h>
#include <private/scenemanager_p.h>
#include <Qt3DCore/qentity.h>
+#include <Qt3DCore/private/qaspectmanager_p.h>
#include <Qt3DRender/private/job_common_p.h>
#include <Qt3DRender/private/qsceneimporter_p.h>
#include <Qt3DRender/private/qurlhelper_p.h>
#include <Qt3DRender/qsceneloader.h>
+#include <Qt3DRender/private/qsceneloader_p.h>
#include <Qt3DRender/private/renderlogging_p.h>
#include <QFileInfo>
#include <QMimeDatabase>
@@ -55,10 +57,10 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
-LoadSceneJob::LoadSceneJob(const QUrl &source, Qt3DCore::QNodeId m_sceneComponent)
- : QAspectJob()
+LoadSceneJob::LoadSceneJob(const QUrl &source, Qt3DCore::QNodeId sceneComponent)
+ : QAspectJob(*new LoadSceneJobPrivate(this))
, m_source(source)
- , m_sceneComponent(m_sceneComponent)
+ , m_sceneComponent(sceneComponent)
, m_managers(nullptr)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadScene, 0);
@@ -97,7 +99,6 @@ void LoadSceneJob::run()
Q_ASSERT(scene);
// Reset status
- scene->setStatus(QSceneLoader::None);
QSceneLoader::Status finalStatus = QSceneLoader::None;
// Perform the loading only if the source wasn't explicitly set to empty
@@ -110,8 +111,7 @@ void LoadSceneJob::run()
qCDebug(SceneLoaders) << Q_FUNC_INFO << "Attempting to load" << finfo.filePath();
if (finfo.exists()) {
const QStringList extensions(finfo.suffix());
- sceneSubTree = tryLoadScene(scene,
- finalStatus,
+ sceneSubTree = tryLoadScene(finalStatus,
extensions,
[this] (QSceneImporter *importer) {
importer->setSource(m_source);
@@ -131,8 +131,7 @@ void LoadSceneJob::run()
const QString basePath = m_source.adjusted(QUrl::RemoveFilename).toString();
- sceneSubTree = tryLoadScene(scene,
- finalStatus,
+ sceneSubTree = tryLoadScene(finalStatus,
extensions,
[this, basePath] (QSceneImporter *importer) {
importer->setData(m_data, basePath);
@@ -140,19 +139,18 @@ void LoadSceneJob::run()
}
}
- // If the sceneSubTree is null it will trigger the frontend to unload
- // any subtree it may hold
- // Set clone of sceneTree in sceneComponent. This will move the sceneSubTree
- // to the QCoreApplication thread which is where the frontend object tree lives.
- scene->setSceneSubtree(sceneSubTree);
+ Q_D(LoadSceneJob);
+ d->m_sceneSubtree = sceneSubTree;
+ d->m_status = finalStatus;
- // Note: the status is set after the subtree so that bindinds depending on the status
- // in the frontend will be consistent
- scene->setStatus(finalStatus);
+ if (d->m_sceneSubtree) {
+ // Move scene sub tree to the application thread so that it can be grafted in.
+ const auto appThread = QCoreApplication::instance()->thread();
+ d->m_sceneSubtree->moveToThread(appThread);
+ }
}
-Qt3DCore::QEntity *LoadSceneJob::tryLoadScene(Scene *scene,
- QSceneLoader::Status &finalStatus,
+Qt3DCore::QEntity *LoadSceneJob::tryLoadScene(QSceneLoader::Status &finalStatus,
const QStringList &extensions,
const std::function<void (QSceneImporter *)> &importerSetupFunc)
{
@@ -165,9 +163,6 @@ Qt3DCore::QEntity *LoadSceneJob::tryLoadScene(Scene *scene,
foundSuitableLoggerPlugin = true;
- // If the file type is supported -> enter Loading status
- scene->setStatus(QSceneLoader::Loading);
-
// Set source file or data on importer
importerSetupFunc(sceneImporter);
@@ -188,6 +183,27 @@ Qt3DCore::QEntity *LoadSceneJob::tryLoadScene(Scene *scene,
return sceneSubTree;
}
+void LoadSceneJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
+{
+ Q_Q(LoadSceneJob);
+ QSceneLoader *node =
+ qobject_cast<QSceneLoader *>(manager->lookupNode(q->sceneComponentId()));
+ if (!node)
+ return;
+ Qt3DRender::QSceneLoaderPrivate *dNode =
+ static_cast<decltype(dNode)>(Qt3DCore::QNodePrivate::get(node));
+
+ // If the sceneSubTree is null it will trigger the frontend to unload
+ // any subtree it may hold
+ // Set clone of sceneTree in sceneComponent. This will move the sceneSubTree
+ // to the QCoreApplication thread which is where the frontend object tree lives.
+ dNode->setSceneRoot(m_sceneSubtree);
+
+ // Note: the status is set after the subtree so that bindinds depending on the status
+ // in the frontend will be consistent
+ dNode->setStatus(m_status);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/jobs/loadscenejob_p.h b/src/render/jobs/loadscenejob_p.h
index 0c77dc6e8..3675d94c1 100644
--- a/src/render/jobs/loadscenejob_p.h
+++ b/src/render/jobs/loadscenejob_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DCore/private/qaspectjob_p.h>
#include <Qt3DCore/qnodeid.h>
#include <Qt3DRender/qsceneloader.h>
#include <QSharedPointer>
@@ -69,6 +70,24 @@ namespace Render {
class Scene;
class NodeManagers;
+class LoadSceneJob;
+
+class Q_AUTOTEST_EXPORT LoadSceneJobPrivate : public Qt3DCore::QAspectJobPrivate
+{
+public:
+ explicit LoadSceneJobPrivate(LoadSceneJob *q): q_ptr(q) {}
+ ~LoadSceneJobPrivate() override {}
+
+ void postFrame(Qt3DCore::QAspectManager *manager) override;
+
+ Qt3DCore::QEntity *m_sceneSubtree = nullptr;
+ QSceneLoader::Status m_status = QSceneLoader::None;
+
+ Q_DECLARE_PUBLIC(LoadSceneJob)
+private:
+ LoadSceneJob *q_ptr;
+};
+
class Q_AUTOTEST_EXPORT LoadSceneJob : public Qt3DCore::QAspectJob
{
public:
@@ -91,10 +110,10 @@ private:
NodeManagers *m_managers;
QList<QSceneImporter *> m_sceneImporters;
- Qt3DCore::QEntity *tryLoadScene(Scene *scene,
- QSceneLoader::Status &finalStatus,
+ Qt3DCore::QEntity *tryLoadScene(QSceneLoader::Status &finalStatus,
const QStringList &extensions,
const std::function<void (QSceneImporter *)> &importerSetupFunc);
+ Q_DECLARE_PRIVATE(LoadSceneJob)
};
typedef QSharedPointer<LoadSceneJob> LoadSceneJobPtr;
diff --git a/src/render/jobs/loadskeletonjob.cpp b/src/render/jobs/loadskeletonjob.cpp
index 413afc5b5..8d0d47fb9 100644
--- a/src/render/jobs/loadskeletonjob.cpp
+++ b/src/render/jobs/loadskeletonjob.cpp
@@ -35,32 +35,263 @@
****************************************************************************/
#include "loadskeletonjob_p.h"
-#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/qabstractskeleton.h>
+#include <Qt3DCore/qskeletonloader.h>
+#include <Qt3DCore/private/qabstractskeleton_p.h>
+#include <Qt3DCore/private/qabstractnodefactory_p.h>
+#include <Qt3DCore/private/qaspectmanager_p.h>
+#include <Qt3DCore/private/qskeletonloader_p.h>
#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/job_common_p.h>
+#include <Qt3DRender/private/qurlhelper_p.h>
+#include <Qt3DRender/private/gltfskeletonloader_p.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
+class LoadSkeletonJobPrivate : public Qt3DCore::QAspectJobPrivate
+{
+public:
+ LoadSkeletonJobPrivate() : m_backendSkeleton(nullptr), m_loadedRootJoint(nullptr) { }
+ ~LoadSkeletonJobPrivate() override { }
+
+ void postFrame(Qt3DCore::QAspectManager *manager) override;
+
+ Skeleton *m_backendSkeleton;
+ Qt3DCore::QJoint* m_loadedRootJoint;
+};
+
LoadSkeletonJob::LoadSkeletonJob(const HSkeleton &handle)
- : QAspectJob()
+ : QAspectJob(*new LoadSkeletonJobPrivate)
, m_handle(handle)
, m_nodeManagers(nullptr)
{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadSkeleton, 0);
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadSkeleton, 0)
}
-LoadSkeletonJob::~LoadSkeletonJob()
+void LoadSkeletonJob::run()
{
+ Q_D(LoadSkeletonJob);
+ d->m_backendSkeleton = nullptr;
+
+ Skeleton *skeleton = m_nodeManagers->skeletonManager()->data(m_handle);
+ if (skeleton != nullptr) {
+ d->m_backendSkeleton = skeleton;
+ loadSkeleton(skeleton);
+ }
}
-void LoadSkeletonJob::run()
+void LoadSkeletonJob::loadSkeleton(Skeleton *skeleton)
{
- Skeleton *skeleton = m_nodeManagers->skeletonManager()->data(m_handle);
- if (skeleton != nullptr)
- skeleton->loadSkeleton();
+ qCDebug(Jobs) << Q_FUNC_INFO << skeleton->source();
+ skeleton->clearData();
+
+ // Load the data
+ switch (skeleton->dataType()) {
+ case Skeleton::File:
+ loadSkeletonFromUrl(skeleton);
+ break;
+
+ case Skeleton::Data:
+ loadSkeletonFromData(skeleton);
+ break;
+
+ default:
+ Q_UNREACHABLE();
+ }
+
+ // If using a loader inform the frontend of the status change.
+ // Don't bother if asked to create frontend joints though. When
+ // the backend gets notified of those joints we'll update the
+ // status at that point.
+ if (skeleton->dataType() == Skeleton::File && !skeleton->createJoints()) {
+ if (skeleton->jointCount() == 0)
+ skeleton->setStatus(Qt3DCore::QSkeletonLoader::Error);
+ else
+ skeleton->setStatus(Qt3DCore::QSkeletonLoader::Ready);
+ }
+
+ qCDebug(Jobs) << "Loaded skeleton data:" << *skeleton;
+}
+
+void LoadSkeletonJob::loadSkeletonFromUrl(Skeleton *skeleton)
+{
+ Q_D(LoadSkeletonJob);
+
+ using namespace Qt3DCore;
+
+ // TODO: Handle remote files
+ QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(skeleton->source());
+ QFileInfo info(filePath);
+ if (!info.exists()) {
+ qWarning() << "Could not open skeleton file:" << filePath;
+ skeleton->setStatus(Qt3DCore::QSkeletonLoader::Error);
+ return;
+ }
+
+ QFile file(filePath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning() << "Could not open skeleton file:" << filePath;
+ skeleton->setStatus(QSkeletonLoader::Error);
+ return;
+ }
+
+ // TODO: Make plugin based for more file type support. For now gltf or native
+ const QString ext = info.suffix();
+ SkeletonData skeletonData;
+ if (ext == QLatin1String("gltf")) {
+ GLTFSkeletonLoader loader;
+ loader.load(&file);
+ skeletonData = loader.createSkeleton(skeleton->name());
+
+ // If the user has requested it, create the frontend nodes for the joints
+ // and send them to the (soon to be owning) QSkeletonLoader.
+ if (skeleton->createJoints()) {
+ QJoint *rootJoint = createFrontendJoints(skeletonData);
+ if (!rootJoint) {
+ qWarning() << "Failed to create frontend joints";
+ skeleton->setStatus(QSkeletonLoader::Error);
+ return;
+ }
+
+ // Move the QJoint tree to the main thread and notify the
+ // corresponding QSkeletonLoader
+ const auto appThread = QCoreApplication::instance()->thread();
+ rootJoint->moveToThread(appThread);
+
+ d->m_loadedRootJoint = rootJoint;
+
+ // Clear the skeleton data. It will be recreated from the
+ // frontend joints. A little bit inefficient but ensures
+ // that joints created this way and via QSkeleton go through
+ // the same code path.
+ skeletonData = SkeletonData();
+ }
+ } else if (ext == QLatin1String("json")) {
+ // TODO: Support native skeleton type
+ } else {
+ qWarning() << "Unknown skeleton file type:" << ext;
+ skeleton->setStatus(QSkeletonLoader::Error);
+ return;
+ }
+
+ skeleton->setSkeletonData(skeletonData);
+}
+
+void LoadSkeletonJob::loadSkeletonFromData(Skeleton *skeleton)
+{
+ // Recurse down through the joint hierarchy and process it into
+ // the vector of joints used within SkeletonData. The recursion
+ // ensures that a parent always appears before its children in
+ // the vector of JointInfo objects.
+ //
+ // In addition, we set up a mapping from the joint ids to the
+ // index of the corresponding JointInfo object in the vector.
+ // This will allow us to easily update entries in the vector of
+ // JointInfos when a Joint node marks itself as dirty.
+ const int rootParentIndex = -1;
+ auto skeletonData = skeleton->skeletonData();
+ processJointHierarchy(skeleton->rootJointId(), rootParentIndex, skeletonData);
+ skeleton->setSkeletonData(skeletonData);
+}
+
+Qt3DCore::QJoint *LoadSkeletonJob::createFrontendJoints(const SkeletonData &skeletonData) const
+{
+ if (skeletonData.joints.isEmpty())
+ return nullptr;
+
+ // Create frontend joints from the joint info objects
+ QVector<Qt3DCore::QJoint *> frontendJoints;
+ const int jointCount = skeletonData.joints.size();
+ frontendJoints.reserve(jointCount);
+ for (int i = 0; i < jointCount; ++i) {
+ const QMatrix4x4 &inverseBindMatrix = skeletonData.joints[i].inverseBindPose;
+ const QString &jointName = skeletonData.jointNames[i];
+ const Qt3DCore::Sqt &localPose = skeletonData.localPoses[i];
+ frontendJoints.push_back(createFrontendJoint(jointName, localPose, inverseBindMatrix));
+ }
+
+ // Now go through and resolve the parent for each joint
+ for (int i = 0; i < frontendJoints.size(); ++i) {
+ const auto parentIndex = skeletonData.joints[i].parentIndex;
+ if (parentIndex == -1)
+ continue;
+
+ // It's not enough to just set up the QObject parent-child relationship.
+ // We need to explicitly add the child to the parent's list of joints so
+ // that information is then propagated to the backend.
+ frontendJoints[parentIndex]->addChildJoint(frontendJoints[i]);
+ }
+
+ return frontendJoints[0];
+}
+
+Qt3DCore::QJoint *LoadSkeletonJob::createFrontendJoint(const QString &jointName,
+ const Qt3DCore::Sqt &localPose,
+ const QMatrix4x4 &inverseBindMatrix) const
+{
+ auto joint = Qt3DCore::QAbstractNodeFactory::createNode<Qt3DCore::QJoint>("QJoint");
+ joint->setTranslation(localPose.translation);
+ joint->setRotation(localPose.rotation);
+ joint->setScale(localPose.scale);
+ joint->setInverseBindMatrix(inverseBindMatrix);
+ joint->setName(jointName);
+ return joint;
+}
+
+void LoadSkeletonJob::processJointHierarchy(Qt3DCore::QNodeId jointId,
+ int parentJointIndex,
+ SkeletonData &skeletonData)
+{
+ // Lookup the joint, create a JointInfo, and add an entry to the index map
+ Joint *joint = m_nodeManagers->jointManager()->lookupResource(jointId);
+ Q_ASSERT(joint);
+ joint->setOwningSkeleton(m_handle);
+ const JointInfo jointInfo(joint, parentJointIndex);
+ skeletonData.joints.push_back(jointInfo);
+ skeletonData.localPoses.push_back(joint->localPose());
+ skeletonData.jointNames.push_back(joint->name());
+
+ const int jointIndex = skeletonData.joints.size() - 1;
+ const HJoint jointHandle = m_nodeManagers->jointManager()->lookupHandle(jointId);
+ skeletonData.jointIndices.insert(jointHandle, jointIndex);
+
+ // Recurse to the children
+ const auto childIds = joint->childJointIds();
+ for (const auto &childJointId : childIds)
+ processJointHierarchy(childJointId, jointIndex, skeletonData);
+}
+
+void LoadSkeletonJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
+{
+ if (!m_backendSkeleton)
+ return;
+
+ using namespace Qt3DCore;
+ QAbstractSkeleton *node = qobject_cast<QAbstractSkeleton *>(manager->lookupNode(m_backendSkeleton->peerId()));
+ if (!node)
+ return;
+
+ QAbstractSkeletonPrivate *dnode = QAbstractSkeletonPrivate::get(node);
+ dnode->m_jointCount = m_backendSkeleton->jointCount();
+ dnode->m_jointNames = m_backendSkeleton->jointNames();
+ dnode->m_localPoses = m_backendSkeleton->localPoses();
+ dnode->update();
+
+ QSkeletonLoader *loaderNode = qobject_cast<QSkeletonLoader *>(node);
+ if (loaderNode) {
+ QSkeletonLoaderPrivate *dloaderNode = static_cast<QSkeletonLoaderPrivate *>(QSkeletonLoaderPrivate::get(loaderNode));
+ dloaderNode->setStatus(m_backendSkeleton->status());
+
+ if (m_loadedRootJoint) {
+ dloaderNode->m_rootJoint = m_loadedRootJoint;
+ m_loadedRootJoint = nullptr;
+ }
+ }
}
} // namespace Render
diff --git a/src/render/jobs/loadskeletonjob_p.h b/src/render/jobs/loadskeletonjob_p.h
index 2cd9fa8bf..0cc09da3d 100644
--- a/src/render/jobs/loadskeletonjob_p.h
+++ b/src/render/jobs/loadskeletonjob_p.h
@@ -51,28 +51,46 @@
#include <Qt3DCore/qaspectjob.h>
#include <QtCore/qsharedpointer.h>
-
+#include <Qt3DRender/private/skeletondata_p.h>
#include <Qt3DRender/private/handle_types_p.h>
QT_BEGIN_NAMESPACE
+namespace Qt3DCore {
+class QJoint;
+}
+
namespace Qt3DRender {
namespace Render {
class NodeManagers;
+class LoadSkeletonJobPrivate;
class LoadSkeletonJob : public Qt3DCore::QAspectJob
{
public:
explicit LoadSkeletonJob(const HSkeleton &handle);
- ~LoadSkeletonJob();
void setNodeManagers(NodeManagers *nodeManagers) { m_nodeManagers = nodeManagers; }
protected:
void run() override;
+ void loadSkeleton(Skeleton *skeleton);
+ void loadSkeletonFromUrl(Skeleton *skeleton);
+ void loadSkeletonFromData(Skeleton *skeleton);
+ Qt3DCore::QJoint *createFrontendJoints(const SkeletonData &skeletonData) const;
+ Qt3DCore::QJoint *createFrontendJoint(const QString &jointName,
+ const Qt3DCore::Sqt &localPose,
+ const QMatrix4x4 &inverseBindMatrix) const;
+ void processJointHierarchy(Qt3DCore::QNodeId jointId,
+ int parentJointIndex,
+ SkeletonData &skeletonData);
+
HSkeleton m_handle;
NodeManagers *m_nodeManagers;
+
+private:
+ Q_DECLARE_PRIVATE(LoadSkeletonJob)
};
typedef QSharedPointer<LoadSkeletonJob> LoadSkeletonJobPtr;
diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index 1a6cd7ba4..2973ee100 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -41,7 +41,11 @@
#include "qpicktriangleevent.h"
#include "qpicklineevent.h"
#include "qpickpointevent.h"
+#include <Qt3DCore/private/qaspectmanager_p.h>
+#include <Qt3DRender/qobjectpicker.h>
+#include <Qt3DRender/qviewport.h>
#include <Qt3DRender/qgeometryrenderer.h>
+#include <Qt3DRender/private/qobjectpicker_p.h>
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/entity_p.h>
@@ -65,6 +69,82 @@ using namespace Qt3DRender::RayCasting;
namespace Render {
+class PickBoundingVolumeJobPrivate : public Qt3DCore::QAspectJobPrivate
+{
+public:
+ PickBoundingVolumeJobPrivate() = default;
+ ~PickBoundingVolumeJobPrivate() override = default;
+
+ void postFrame(Qt3DCore::QAspectManager *manager) override;
+
+ enum CustomEventType {
+ MouseButtonClick = QEvent::User,
+ };
+
+ struct EventDetails {
+ Qt3DCore::QNodeId pickerId;
+ int sourceEventType;
+ QPickEventPtr resultingEvent;
+ Qt3DCore::QNodeId viewportNodeId;
+ };
+
+ QVector<EventDetails> dispatches;
+};
+
+
+void PickBoundingVolumeJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
+{
+ using namespace Qt3DCore;
+ QNodeId previousId;
+ QObjectPicker *node = nullptr;
+
+ for (auto res: qAsConst(dispatches)) {
+ if (previousId != res.pickerId) {
+ node = qobject_cast<QObjectPicker *>(manager->lookupNode(res.pickerId));
+ previousId = res.pickerId;
+ }
+ if (!node)
+ continue;
+
+ QObjectPickerPrivate *dnode = static_cast<QObjectPickerPrivate *>(QObjectPickerPrivate::get(node));
+
+ // resolve front end details
+ QPickEvent *pickEvent = res.resultingEvent.data();
+ if (pickEvent) {
+ QPickEventPrivate *dpickEvent = QPickEventPrivate::get(pickEvent);
+ dpickEvent->m_viewport = static_cast<QViewport *>(manager->lookupNode(res.viewportNodeId));
+ dpickEvent->m_entityPtr = static_cast<QEntity *>(manager->lookupNode(dpickEvent->m_entity));
+ }
+
+ // dispatch event
+ switch (res.sourceEventType) {
+ case QEvent::MouseButtonPress:
+ dnode->pressedEvent(pickEvent);
+ break;
+ case QEvent::MouseButtonRelease:
+ dnode->releasedEvent(pickEvent);
+ break;
+ case MouseButtonClick:
+ dnode->clickedEvent(pickEvent);
+ break;
+ case QEvent::MouseMove:
+ dnode->movedEvent(pickEvent);
+ break;
+ case QEvent::Enter:
+ emit node->entered();
+ dnode->setContainsMouse(true);
+ break;
+ case QEvent::Leave:
+ dnode->setContainsMouse(false);
+ emit node->exited();
+ break;
+ default: Q_UNREACHABLE();
+ }
+ }
+
+ dispatches.clear();
+}
+
namespace {
void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers)
@@ -109,10 +189,10 @@ void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &e
} // anonymous
PickBoundingVolumeJob::PickBoundingVolumeJob()
- : AbstractPickingJob()
+ : AbstractPickingJob(*new PickBoundingVolumeJobPrivate)
, m_pickersDirty(true)
{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::PickBoundingVolume, 0);
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::PickBoundingVolume, 0)
}
void PickBoundingVolumeJob::setRoot(Entity *root)
@@ -236,7 +316,8 @@ bool PickBoundingVolumeJob::runHelper()
// has moved out of the viewport In case of a button released
// outside of the viewport, we still want to notify the
// lastCurrent entity about this.
- dispatchPickEvents(event.second, PickingUtils::HitList(), eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode());
+ dispatchPickEvents(event.second, PickingUtils::HitList(), eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode(),
+ vca.viewportNodeId);
continue;
}
@@ -278,7 +359,8 @@ bool PickBoundingVolumeJob::runHelper()
}
// Dispatch events based on hit results
- dispatchPickEvents(event.second, sphereHits, eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode());
+ dispatchPickEvents(event.second, sphereHits, eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode(),
+ vca.viewportNodeId);
}
}
@@ -295,8 +377,11 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
QPickEvent::Buttons eventButton,
int eventButtons,
int eventModifiers,
- bool allHitsRequested)
+ bool allHitsRequested,
+ Qt3DCore::QNodeId viewportNodeId)
{
+ Q_D(PickBoundingVolumeJob);
+
ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
// If we have hits
if (!sphereHits.isEmpty()) {
@@ -380,37 +465,43 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
// Store pressed object handle
m_currentPicker = objectPickerHandle;
// Send pressed event to m_currentPicker
- objectPicker->onPressed(pickEvent);
+ d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId});
+ objectPicker->setPressed(true);
break;
}
case QEvent::MouseButtonRelease: {
// Only send the release event if it was pressed
- if (objectPicker->isPressed())
- objectPicker->onReleased(pickEvent);
+ if (objectPicker->isPressed()) {
+ d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId});
+ objectPicker->setPressed(false);
+ }
if (lastCurrentPicker != nullptr && m_currentPicker == objectPickerHandle) {
- objectPicker->onClicked(pickEvent);
+ d->dispatches.push_back({objectPicker->peerId(),
+ PickBoundingVolumeJobPrivate::MouseButtonClick,
+ pickEvent, viewportNodeId});
m_currentPicker = HObjectPicker();
}
break;
}
#if QT_CONFIG(gestures)
case QEvent::Gesture: {
- objectPicker->onClicked(pickEvent);
+ d->dispatches.push_back({objectPicker->peerId(),
+ PickBoundingVolumeJobPrivate::MouseButtonClick,
+ pickEvent, viewportNodeId});
break;
}
#endif
case QEvent::MouseMove: {
- if ((objectPicker->isPressed() || objectPicker->isHoverEnabled()) && objectPicker->isDragEnabled()) {
- objectPicker->onMoved(pickEvent);
- }
+ if ((objectPicker->isPressed() || objectPicker->isHoverEnabled()) && objectPicker->isDragEnabled())
+ d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId});
Q_FALLTHROUGH(); // fallthrough
}
case QEvent::HoverMove: {
if (!m_hoveredPickers.contains(objectPickerHandle)) {
if (objectPicker->isHoverEnabled()) {
// Send entered event to objectPicker
- objectPicker->onEntered();
+ d->dispatches.push_back({objectPicker->peerId(), QEvent::Enter, pickEvent, viewportNodeId});
// and save it in the hoveredPickers
m_hoveredPickers.push_back(objectPickerHandle);
}
@@ -437,7 +528,8 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
if (lastCurrentPicker != nullptr) {
m_currentPicker = HObjectPicker();
QPickEventPtr pickEvent(new QPickEvent);
- lastCurrentPicker->onReleased(pickEvent);
+ lastCurrentPicker->setPressed(false);
+ d->dispatches.push_back({lastCurrentPicker->peerId(), event.type(), pickEvent, viewportNodeId});
}
break;
}
@@ -449,12 +541,15 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
void PickBoundingVolumeJob::clearPreviouslyHoveredPickers()
{
+ Q_D(PickBoundingVolumeJob);
+
for (const HObjectPicker &pickHandle : qAsConst(m_hoveredPickersToClear)) {
ObjectPicker *pick = m_manager->objectPickerManager()->data(pickHandle);
if (pick)
- pick->onExited();
+ d->dispatches.push_back({pick->peerId(), QEvent::Leave, {}, {}});
m_hoveredPickers.removeAll(pickHandle);
}
+
m_hoveredPickersToClear.clear();
}
diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h
index 2c38c400b..49b11b775 100644
--- a/src/render/jobs/pickboundingvolumejob_p.h
+++ b/src/render/jobs/pickboundingvolumejob_p.h
@@ -66,7 +66,11 @@
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
+
+class QViewport;
+
namespace Render {
+class PickBoundingVolumeJobPrivate;
namespace PickingUtils {
typedef QVector<RayCasting::QCollisionQueryResult::Hit> HitList;
@@ -94,9 +98,12 @@ protected:
QPickEvent::Buttons eventButton,
int eventButtons,
int eventModifiers,
- bool allHitsRequested);
+ bool allHitsRequested,
+ Qt3DCore::QNodeId viewportNodeId);
private:
+ Q_DECLARE_PRIVATE(PickBoundingVolumeJob)
+
void clearPreviouslyHoveredPickers();
QList<QPair<QObject*, QMouseEvent>> m_pendingMouseEvents;
diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp
index abc54482a..1d22e8645 100644
--- a/src/render/jobs/pickboundingvolumeutils.cpp
+++ b/src/render/jobs/pickboundingvolumeutils.cpp
@@ -86,15 +86,25 @@ ViewportCameraAreaDetails ViewportCameraAreaGatherer::gatherUpViewportCameraArea
case FrameGraphNode::CameraSelector:
vca.cameraId = static_cast<const CameraSelector *>(node)->cameraUuid();
break;
- case FrameGraphNode::Viewport:
- vca.viewport = ViewportNode::computeViewport(vca.viewport, static_cast<const ViewportNode *>(node));
+ case FrameGraphNode::Viewport: {
+ auto vnode = static_cast<const ViewportNode *>(node);
+ // we want the leaf viewport so if we have a viewport node already don't override it with its parent
+ if (!vca.viewportNodeId)
+ vca.viewportNodeId = vnode->peerId();
+ vca.viewport = ViewportNode::computeViewport(vca.viewport, vnode);
break;
+ }
case FrameGraphNode::Surface: {
auto selector = static_cast<const RenderSurfaceSelector *>(node);
vca.area = selector->renderTargetSize();
vca.surface = selector->surface();
break;
}
+ case FrameGraphNode::NoPicking: {
+ // Return an empty/invalid ViewportCameraAreaDetails which will
+ // prevent picking in the presence of a NoPicking node
+ return {};
+ }
default:
break;
}
diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h
index 923a49317..fa3e701c2 100644
--- a/src/render/jobs/pickboundingvolumeutils_p.h
+++ b/src/render/jobs/pickboundingvolumeutils_p.h
@@ -79,6 +79,7 @@ namespace PickingUtils {
struct Q_AUTOTEST_EXPORT ViewportCameraAreaDetails
{
Qt3DCore::QNodeId cameraId;
+ Qt3DCore::QNodeId viewportNodeId;
QRectF viewport;
QSize area;
QSurface *surface = nullptr;
diff --git a/src/render/jobs/raycastingjob.cpp b/src/render/jobs/raycastingjob.cpp
index f3571c210..380447873 100644
--- a/src/render/jobs/raycastingjob.cpp
+++ b/src/render/jobs/raycastingjob.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "raycastingjob_p.h"
+#include <Qt3DCore/private/qaspectmanager_p.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/geometryrenderer_p.h>
@@ -51,6 +52,7 @@
#include <Qt3DRender/private/rendersettings_p.h>
#include <Qt3DRender/private/trianglesvisitor_p.h>
#include <Qt3DRender/private/entityvisitor_p.h>
+#include <Qt3DRender/private/qabstractraycaster_p.h>
QT_BEGIN_NAMESPACE
@@ -82,11 +84,43 @@ public:
} // anonymous
+class Qt3DRender::Render::RayCastingJobPrivate : public Qt3DCore::QAspectJobPrivate
+{
+public:
+ RayCastingJobPrivate() { }
+ ~RayCastingJobPrivate() override { Q_ASSERT(dispatches.isEmpty()); }
+
+ void postFrame(Qt3DCore::QAspectManager *manager) override;
+
+ QVector<QPair<RayCaster *, QAbstractRayCaster::Hits>> dispatches;
+};
+
+
+void RayCastingJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
+{
+ for (auto res: qAsConst(dispatches)) {
+ QAbstractRayCaster *node = qobject_cast<QAbstractRayCaster *>(manager->lookupNode(res.first->peerId()));
+ if (!node)
+ continue;
+
+ QAbstractRayCasterPrivate *d = QAbstractRayCasterPrivate::get(node);
+ d->dispatchHits(res.second);
+
+ if (node->runMode() == QAbstractRayCaster::SingleShot) {
+ node->setEnabled(false);
+ res.first->setEnabled(false);
+ }
+ }
+
+ dispatches.clear();
+}
+
+
RayCastingJob::RayCastingJob()
- : AbstractPickingJob()
+ : AbstractPickingJob(*new RayCastingJobPrivate())
, m_castersDirty(true)
{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::RayCasting, 0);
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::RayCasting, 0)
}
void RayCastingJob::markCastersDirty()
@@ -239,7 +273,8 @@ void RayCastingJob::dispatchHits(RayCaster *rayCaster, const PickingUtils::HitLi
};
}
- rayCaster->dispatchHits(hits);
+ Q_D(RayCastingJob);
+ d->dispatches.push_back({rayCaster, hits});
}
QT_END_NAMESPACE
diff --git a/src/render/jobs/raycastingjob_p.h b/src/render/jobs/raycastingjob_p.h
index 0bd8d445a..4b8b91ad5 100644
--- a/src/render/jobs/raycastingjob_p.h
+++ b/src/render/jobs/raycastingjob_p.h
@@ -68,6 +68,8 @@ namespace PickingUtils {
typedef QVector<RayCasting::QCollisionQueryResult::Hit> HitList;
}
+class RayCastingJobPrivate;
+
class Q_AUTOTEST_EXPORT RayCastingJob : public AbstractPickingJob
{
public:
@@ -80,6 +82,8 @@ protected:
void dispatchHits(RayCaster *rayCaster, const PickingUtils::HitList &sphereHits);
private:
+ Q_DECLARE_PRIVATE(RayCastingJob)
+
bool m_castersDirty;
bool m_oneEnabledAtLeast;
};
diff --git a/src/render/jobs/updatelevelofdetailjob.cpp b/src/render/jobs/updatelevelofdetailjob.cpp
index b5349a2c1..0a28b7628 100644
--- a/src/render/jobs/updatelevelofdetailjob.cpp
+++ b/src/render/jobs/updatelevelofdetailjob.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "updatelevelofdetailjob_p.h"
+#include <Qt3DCore/private/qaspectmanager_p.h>
#include <Qt3DRender/QLevelOfDetail>
#include <Qt3DRender/private/entityvisitor_p.h>
#include <Qt3DRender/private/job_common_p.h>
@@ -66,9 +67,11 @@ public:
, m_filterValue(filterValue)
, m_frameGraphRoot(frameGraphRoot)
{
+ m_updatedIndices.reserve(manager->levelOfDetailManager()->count());
}
double filterValue() const { return m_filterValue; }
+ const QVector<QPair<Qt3DCore::QNodeId, int>> &updatedIndices() const { return m_updatedIndices; }
Operation visit(Qt3DRender::Render::Entity *entity = nullptr) override {
using namespace Qt3DRender;
@@ -102,6 +105,7 @@ public:
private:
double m_filterValue = 0.;
Qt3DRender::Render::FrameGraphNode *m_frameGraphRoot;
+ QVector<QPair<Qt3DCore::QNodeId, int>> m_updatedIndices;
void updateEntityLodByDistance(Qt3DRender::Render::Entity *entity, Qt3DRender::Render::LevelOfDetail *lod)
{
@@ -128,8 +132,10 @@ private:
if (dist <= thresholds[i] || i == n -1) {
m_filterValue = approxRollingAverage<30>(m_filterValue, i);
i = qBound(0, static_cast<int>(qRound(m_filterValue)), n - 1);
- if (lod->currentIndex() != i)
+ if (lod->currentIndex() != i) {
lod->setCurrentIndex(i);
+ m_updatedIndices.push_back({lod->peerId(), i});
+ }
break;
}
}
@@ -172,8 +178,10 @@ private:
if (thresholds[i] < area || i == n -1) {
m_filterValue = approxRollingAverage<30>(m_filterValue, i);
i = qBound(0, static_cast<int>(qRound(m_filterValue)), n - 1);
- if (lod->currentIndex() != i)
+ if (lod->currentIndex() != i) {
lod->setCurrentIndex(i);
+ m_updatedIndices.push_back({lod->peerId(), i});
+ }
break;
}
}
@@ -199,13 +207,24 @@ private:
namespace Qt3DRender {
namespace Render {
+class UpdateLevelOfDetailJobPrivate : public Qt3DCore::QAspectJobPrivate
+{
+public:
+ UpdateLevelOfDetailJobPrivate() { }
+
+ void postFrame(Qt3DCore::QAspectManager *manager) override;
+
+ QVector<QPair<Qt3DCore::QNodeId, int>> m_updatedIndices;
+};
+
UpdateLevelOfDetailJob::UpdateLevelOfDetailJob()
- : m_manager(nullptr)
+ : Qt3DCore::QAspectJob(*new UpdateLevelOfDetailJobPrivate)
+ , m_manager(nullptr)
, m_frameGraphRoot(nullptr)
, m_root(nullptr)
, m_filterValue(0.)
{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateLevelOfDetail, 0);
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateLevelOfDetail, 0)
}
UpdateLevelOfDetailJob::~UpdateLevelOfDetailJob()
@@ -229,23 +248,32 @@ void UpdateLevelOfDetailJob::setFrameGraphRoot(FrameGraphNode *frameGraphRoot)
void UpdateLevelOfDetailJob::run()
{
+ Q_D(UpdateLevelOfDetailJob);
+
Q_ASSERT(m_frameGraphRoot && m_root && m_manager);
// short-circuit if no LoDs exist
if (m_manager->levelOfDetailManager()->count() == 0)
return;
-
- if (m_manager->levelOfDetailManager()->count() == 0)
- return; // no LODs, lets bail out early
-
LODUpdateVisitor visitor(m_filterValue, m_frameGraphRoot, m_manager);
visitor.apply(m_root);
m_filterValue = visitor.filterValue();
+ d->m_updatedIndices = visitor.updatedIndices();
}
-} // Render
+void UpdateLevelOfDetailJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
+{
+ for (const auto &updatedNode: qAsConst(m_updatedIndices)) {
+ QLevelOfDetail *node = qobject_cast<QLevelOfDetail *>(manager->lookupNode(updatedNode.first));
+ if (!node)
+ continue;
+ node->setCurrentIndex(updatedNode.second);
+ }
+}
+
+} // Render
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/jobs/updatelevelofdetailjob_p.h b/src/render/jobs/updatelevelofdetailjob_p.h
index 3c7d00d2c..9ac5cf0e9 100644
--- a/src/render/jobs/updatelevelofdetailjob_p.h
+++ b/src/render/jobs/updatelevelofdetailjob_p.h
@@ -65,6 +65,7 @@ class Entity;
class NodeManagers;
class LevelOfDetail;
class FrameGraphNode;
+class UpdateLevelOfDetailJobPrivate;
class Q_3DRENDERSHARED_PRIVATE_EXPORT UpdateLevelOfDetailJob : public Qt3DCore::QAspectJob
{
@@ -81,6 +82,8 @@ public:
Entity *root() const { return m_root; }
private:
+ Q_DECLARE_PRIVATE(UpdateLevelOfDetailJob)
+
NodeManagers *m_manager;
FrameGraphNode *m_frameGraphRoot;
Entity *m_root;
diff --git a/src/render/jobs/updateworldtransformjob.cpp b/src/render/jobs/updateworldtransformjob.cpp
index 1a9697843..13e14442f 100644
--- a/src/render/jobs/updateworldtransformjob.cpp
+++ b/src/render/jobs/updateworldtransformjob.cpp
@@ -39,6 +39,9 @@
#include "updateworldtransformjob_p.h"
+#include <Qt3DCore/qtransform.h>
+#include <Qt3DCore/private/qtransform_p.h>
+#include <Qt3DCore/private/qaspectmanager_p.h>
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/transform_p.h>
@@ -56,28 +59,52 @@ namespace Render {
namespace {
-void updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Matrix4x4 &parentTransform)
+struct TransformUpdate
+{
+ Qt3DCore::QNodeId peerId;
+ QMatrix4x4 worldTransformMatrix;
+};
+
+QVector<TransformUpdate> updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Matrix4x4 &parentTransform)
{
Matrix4x4 worldTransform(parentTransform);
Transform *nodeTransform = node->renderComponent<Transform>();
+ QVector<TransformUpdate> updatedTransforms;
- if (nodeTransform != nullptr && nodeTransform->isEnabled())
+ const bool hasTransformComponent = nodeTransform != nullptr && nodeTransform->isEnabled();
+ if (hasTransformComponent)
worldTransform = worldTransform * nodeTransform->transformMatrix();
- *(node->worldTransform()) = worldTransform;
+ if (*(node->worldTransform()) != worldTransform) {
+ *(node->worldTransform()) = worldTransform;
+ if (hasTransformComponent)
+ updatedTransforms.push_back({nodeTransform->peerId(), convertToQMatrix4x4(worldTransform)});
+ }
const auto childrenHandles = node->childrenHandles();
for (const HEntity &handle : childrenHandles) {
Entity *child = manager->renderNodesManager()->data(handle);
if (child)
- updateWorldTransformAndBounds(manager, child, worldTransform);
+ updatedTransforms += updateWorldTransformAndBounds(manager, child, worldTransform);
}
+ return updatedTransforms;
}
}
+class Q_3DRENDERSHARED_PRIVATE_EXPORT UpdateWorldTransformJobPrivate : public Qt3DCore::QAspectJobPrivate
+{
+public:
+ UpdateWorldTransformJobPrivate() {}
+ ~UpdateWorldTransformJobPrivate() override {}
+
+ void postFrame(Qt3DCore::QAspectManager *manager) override;
+
+ QVector<TransformUpdate> m_updatedTransforms;
+};
+
UpdateWorldTransformJob::UpdateWorldTransformJob()
- : Qt3DCore::QAspectJob()
+ : Qt3DCore::QAspectJob(*new UpdateWorldTransformJobPrivate())
, m_node(nullptr)
, m_manager(nullptr)
{
@@ -103,17 +130,32 @@ void UpdateWorldTransformJob::run()
// TODO: Parallelise this on each level using a parallel_for
// implementation.
+ Q_D(UpdateWorldTransformJob);
qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread();
Matrix4x4 parentTransform;
Entity *parent = m_node->parent();
if (parent != nullptr)
parentTransform = *(parent->worldTransform());
- updateWorldTransformAndBounds(m_manager, m_node, parentTransform);
+ d->m_updatedTransforms = updateWorldTransformAndBounds(m_manager, m_node, parentTransform);
qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread();
}
+void UpdateWorldTransformJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
+{
+ const QVector<TransformUpdate> updatedTransforms = std::move(m_updatedTransforms);
+ for (const TransformUpdate &t : updatedTransforms) {
+ Qt3DCore::QTransform *node =
+ qobject_cast<Qt3DCore::QTransform *>(manager->lookupNode(t.peerId));
+ if (!node)
+ continue;
+ Qt3DCore::QTransformPrivate *dNode =
+ static_cast<Qt3DCore::QTransformPrivate *>(Qt3DCore::QNodePrivate::get(node));
+ dNode->setWorldMatrix(t.worldTransformMatrix);
+ }
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/jobs/updateworldtransformjob_p.h b/src/render/jobs/updateworldtransformjob_p.h
index 2689fe45a..e7ff592de 100644
--- a/src/render/jobs/updateworldtransformjob_p.h
+++ b/src/render/jobs/updateworldtransformjob_p.h
@@ -63,6 +63,7 @@ namespace Render {
class Entity;
class NodeManagers;
+class UpdateWorldTransformJobPrivate;
class Q_3DRENDERSHARED_PRIVATE_EXPORT UpdateWorldTransformJob : public Qt3DCore::QAspectJob
{
@@ -77,6 +78,7 @@ public:
private:
Entity *m_node;
NodeManagers *m_manager;
+ Q_DECLARE_PRIVATE(UpdateWorldTransformJob)
};
typedef QSharedPointer<UpdateWorldTransformJob> UpdateWorldTransformJobPtr;
diff --git a/src/render/lights/environmentlight.cpp b/src/render/lights/environmentlight.cpp
index d4245fb6e..20364fdfa 100644
--- a/src/render/lights/environmentlight.cpp
+++ b/src/render/lights/environmentlight.cpp
@@ -53,11 +53,17 @@ QNodeId EnvironmentLight::shaderData() const
return m_shaderDataId;
}
-void EnvironmentLight::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
+void EnvironmentLight::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QEnvironmentLightData>>(change);
- const auto &data = typedChange->data;
- m_shaderDataId = data.shaderDataId;
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QEnvironmentLight *node = qobject_cast<const QEnvironmentLight *>(frontEnd);
+ if (!node)
+ return;
+
+ if (firstTime) {
+ QEnvironmentLightPrivate *d = static_cast<QEnvironmentLightPrivate *>(QEnvironmentLightPrivate::get(const_cast<Qt3DCore::QNode *>(frontEnd)));
+ m_shaderDataId = d->m_shaderData ? d->m_shaderData->id() : QNodeId{};
+ }
}
} // namespace Render
diff --git a/src/render/lights/environmentlight_p.h b/src/render/lights/environmentlight_p.h
index 00d49d298..92f6ce100 100644
--- a/src/render/lights/environmentlight_p.h
+++ b/src/render/lights/environmentlight_p.h
@@ -63,10 +63,9 @@ class Q_AUTOTEST_EXPORT EnvironmentLight : public BackendNode
{
public:
Qt3DCore::QNodeId shaderData() const;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
Qt3DCore::QNodeId m_shaderDataId;
};
diff --git a/src/render/lights/light.cpp b/src/render/lights/light.cpp
index e8474b728..3bdab0457 100644
--- a/src/render/lights/light.cpp
+++ b/src/render/lights/light.cpp
@@ -40,7 +40,6 @@
#include "light_p.h"
#include "qabstractlight.h"
#include "qabstractlight_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <private/abstractrenderer_p.h>
#include <private/nodemanagers_p.h>
#include <private/qbackendnode_p.h>
@@ -58,14 +57,18 @@ QNodeId Light::shaderData() const
return m_shaderDataId;
}
-void Light::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
+void Light::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAbstractLightData>>(change);
- const auto &data = typedChange->data;
- m_shaderDataId = data.shaderDataId;
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QAbstractLight *node = qobject_cast<const QAbstractLight *>(frontEnd);
+ if (!node)
+ return;
- Q_ASSERT(m_renderer);
- BackendNode::markDirty(AbstractRenderer::LightsDirty);
+ if (firstTime) {
+ QAbstractLightPrivate *d = static_cast<QAbstractLightPrivate *>(QAbstractLightPrivate::get(const_cast<Qt3DCore::QNode *>(frontEnd)));
+ m_shaderDataId = d->m_shaderData ? d->m_shaderData->id() : QNodeId{};
+ BackendNode::markDirty(AbstractRenderer::LightsDirty);
+ }
}
RenderLightFunctor::RenderLightFunctor(AbstractRenderer *renderer, NodeManagers *managers)
diff --git a/src/render/lights/light_p.h b/src/render/lights/light_p.h
index 8ecc87585..5f5f8140e 100644
--- a/src/render/lights/light_p.h
+++ b/src/render/lights/light_p.h
@@ -66,9 +66,9 @@ class Q_AUTOTEST_EXPORT Light : public BackendNode
public:
Qt3DCore::QNodeId shaderData() const;
-private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+private:
Qt3DCore::QNodeId m_shaderDataId;
};
diff --git a/src/render/lights/qdirectionallight.cpp b/src/render/lights/qdirectionallight.cpp
index 9b6e580de..13fb78843 100644
--- a/src/render/lights/qdirectionallight.cpp
+++ b/src/render/lights/qdirectionallight.cpp
@@ -39,7 +39,6 @@
#include "qdirectionallight.h"
#include "qdirectionallight_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/lights/qspotlight.cpp b/src/render/lights/qspotlight.cpp
index c4deaf817..eddafbe61 100644
--- a/src/render/lights/qspotlight.cpp
+++ b/src/render/lights/qspotlight.cpp
@@ -40,7 +40,6 @@
#include "qspotlight.h"
#include "qspotlight_p.h"
#include "shaderdata_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/materialsystem/effect.cpp b/src/render/materialsystem/effect.cpp
index 29d05ed01..035cf4746 100644
--- a/src/render/materialsystem/effect.cpp
+++ b/src/render/materialsystem/effect.cpp
@@ -43,11 +43,8 @@
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/private/qeffect_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
-
#include <QVariant>
+#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -73,41 +70,25 @@ void Effect::cleanup()
m_techniques.clear();
}
-void Effect::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QEffectData>>(change);
- const auto &data = typedChange->data;
- m_techniques = data.techniqueIds;
- m_parameterPack.setParameters(data.parameterIds);
-}
-
-void Effect::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void Effect::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- switch (e->type()) {
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("technique"))
- appendRenderTechnique(change->addedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("parameter"))
- m_parameterPack.appendParameter(change->addedNodeId());
- break;
- }
-
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("technique"))
- m_techniques.removeOne(change->removedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("parameter"))
- m_parameterPack.removeParameter(change->removedNodeId());
- break;
- }
-
- default:
- break;
- }
-
- markDirty(AbstractRenderer::AllDirty);
- BackendNode::sceneChangeEvent(e);
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QEffect *node = qobject_cast<const QEffect *>(frontEnd);
+ if (!node)
+ return;
+
+ auto parameters = qIdsForNodes(node->parameters());
+ std::sort(std::begin(parameters), std::end(parameters));
+ if (m_parameterPack.parameters() != parameters)
+ m_parameterPack.setParameters(parameters);
+
+ auto techniques = qIdsForNodes(node->techniques());
+ std::sort(std::begin(techniques), std::end(techniques));
+ if (m_techniques != techniques)
+ m_techniques = techniques;
+
+ if (!firstTime)
+ markDirty(AbstractRenderer::AllDirty);
}
void Effect::appendRenderTechnique(Qt3DCore::QNodeId technique)
diff --git a/src/render/materialsystem/effect_p.h b/src/render/materialsystem/effect_p.h
index 87ff4a803..e81be2b8d 100644
--- a/src/render/materialsystem/effect_p.h
+++ b/src/render/materialsystem/effect_p.h
@@ -70,15 +70,13 @@ public:
~Effect();
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
void appendRenderTechnique(Qt3DCore::QNodeId t);
QVector<Qt3DCore::QNodeId> techniques() const;
QVector<Qt3DCore::QNodeId> parameters() const;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QVector<Qt3DCore::QNodeId> m_techniques;
ParameterPack m_parameterPack;
};
diff --git a/src/render/materialsystem/filterkey.cpp b/src/render/materialsystem/filterkey.cpp
index 167413451..e6c37b241 100644
--- a/src/render/materialsystem/filterkey.cpp
+++ b/src/render/materialsystem/filterkey.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "filterkey_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/qfilterkey_p.h>
QT_BEGIN_NAMESPACE
@@ -65,31 +64,23 @@ void FilterKey::cleanup()
m_value.clear();
}
-void FilterKey::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void FilterKey::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QFilterKeyData>>(change);
- const auto &data = typedChange->data;
- m_name = data.name;
- m_value = data.value;
-}
+ const QFilterKey *node = qobject_cast<const QFilterKey *>(frontEnd);
+ if (!node)
+ return;
-void FilterKey::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyUpdated: {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("value"))
- m_value = propertyChange->value();
- else if (propertyChange->propertyName() == QByteArrayLiteral("name"))
- m_name = propertyChange->value().toString();
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ if (node->name() != m_name) {
+ m_name = node->name();
markDirty(AbstractRenderer::AllDirty);
}
- default:
- break;
+ if (node->value() != m_value) {
+ m_value = node->value();
+ markDirty(AbstractRenderer::AllDirty);
}
- BackendNode::sceneChangeEvent(e);
}
bool FilterKey::operator ==(const FilterKey &other)
diff --git a/src/render/materialsystem/filterkey_p.h b/src/render/materialsystem/filterkey_p.h
index 69d298503..f4fb2c3d0 100644
--- a/src/render/materialsystem/filterkey_p.h
+++ b/src/render/materialsystem/filterkey_p.h
@@ -71,13 +71,11 @@ public:
const QVariant &value() const { return m_value; }
const QString &name() const { return m_name; }
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
bool operator ==(const FilterKey &other);
bool operator !=(const FilterKey &other);
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QVariant m_value;
QString m_name;
};
diff --git a/src/render/materialsystem/material.cpp b/src/render/materialsystem/material.cpp
index 723dbfd31..6fda17ccd 100644
--- a/src/render/materialsystem/material.cpp
+++ b/src/render/materialsystem/material.cpp
@@ -46,10 +46,6 @@
#include "qeffect.h"
#include <Qt3DRender/private/qmaterial_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
-
using namespace Qt3DCore;
QT_BEGIN_NAMESPACE
@@ -73,45 +69,26 @@ void Material::cleanup()
m_parameterPack.clear();
}
-void Material::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void Material::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QMaterialData>>(change);
- const auto &data = typedChange->data;
- m_effectUuid = data.effectId;
- m_parameterPack.setParameters(data.parameterIds);
-}
-
-void Material::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
-
- switch (e->type()) {
- case PropertyUpdated: {
- const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("effect"))
- m_effectUuid = change->value().value<QNodeId>();
- break;
- }
-
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("parameter"))
- m_parameterPack.appendParameter(change->addedNodeId());
- break;
- }
-
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("parameter"))
- m_parameterPack.removeParameter(change->removedNodeId());
- break;
- }
-
- default:
- break;
- }
- markDirty(AbstractRenderer::AllDirty);
-
- BackendNode::sceneChangeEvent(e);
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QMaterial *node = qobject_cast<const QMaterial *>(frontEnd);
+ if (!node)
+ return;
+
+ auto parameters = qIdsForNodes(node->parameters());
+ std::sort(std::begin(parameters), std::end(parameters));
+ if (m_parameterPack.parameters() != parameters)
+ m_parameterPack.setParameters(parameters);
+
+ const auto effectId = node->effect() ? node->effect()->id() : QNodeId{};
+ if (effectId != m_effectUuid)
+ m_effectUuid = effectId;
+
+ if (firstTime)
+ markDirty(AbstractRenderer::MaterialDirty);
+ else
+ markDirty(AbstractRenderer::AllDirty);
}
QVector<Qt3DCore::QNodeId> Material::parameters() const
diff --git a/src/render/materialsystem/material_p.h b/src/render/materialsystem/material_p.h
index 3b55dc657..7a02c6691 100644
--- a/src/render/materialsystem/material_p.h
+++ b/src/render/materialsystem/material_p.h
@@ -79,14 +79,12 @@ public:
~Material();
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
QVector<Qt3DCore::QNodeId> parameters() const;
Qt3DCore::QNodeId effect() const;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
ParameterPack m_parameterPack;
Qt3DCore::QNodeId m_effectUuid;
};
diff --git a/src/render/materialsystem/materialsystem.pri b/src/render/materialsystem/materialsystem.pri
index c464d6b99..ae3d2f78c 100644
--- a/src/render/materialsystem/materialsystem.pri
+++ b/src/render/materialsystem/materialsystem.pri
@@ -17,6 +17,8 @@ HEADERS += \
$$PWD/qrenderpass.h \
$$PWD/qshaderdata.h \
$$PWD/qshaderdata_p.h \
+ $$PWD/qshaderimage.h \
+ $$PWD/qshaderimage_p.h \
$$PWD/qshaderprogram.h \
$$PWD/qshaderprogram_p.h \
$$PWD/qshaderprogrambuilder.h \
@@ -27,6 +29,7 @@ HEADERS += \
$$PWD/shader_p.h \
$$PWD/shaderbuilder_p.h \
$$PWD/shaderdata_p.h \
+ $$PWD/shaderimage_p.h \
$$PWD/technique_p.h \
$$PWD/qgraphicsapifilter.h \
$$PWD/qgraphicsapifilter_p.h \
@@ -44,6 +47,7 @@ SOURCES += \
$$PWD/qparameter.cpp \
$$PWD/qrenderpass.cpp \
$$PWD/qshaderdata.cpp \
+ $$PWD/qshaderimage.cpp \
$$PWD/qshaderprogram.cpp \
$$PWD/qshaderprogrambuilder.cpp \
$$PWD/qtechnique.cpp \
@@ -51,6 +55,7 @@ SOURCES += \
$$PWD/shader.cpp \
$$PWD/shaderbuilder.cpp \
$$PWD/shaderdata.cpp \
+ $$PWD/shaderimage.cpp \
$$PWD/technique.cpp \
$$PWD/qgraphicsapifilter.cpp \
$$PWD/shadercache.cpp \
diff --git a/src/render/materialsystem/parameter.cpp b/src/render/materialsystem/parameter.cpp
index f00df3c90..3360aebef 100644
--- a/src/render/materialsystem/parameter.cpp
+++ b/src/render/materialsystem/parameter.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "parameter_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/private/qparameter_p.h>
#include <Qt3DRender/qtexture.h>
@@ -68,35 +67,36 @@ void Parameter::cleanup()
m_nameId = -1;
m_name.clear();
m_uniformValue = UniformValue();
+ m_backendValue = {};
}
-void Parameter::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void Parameter::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QParameterData>>(change);
- const auto &data = typedChange->data;
- m_name = data.name;
- m_nameId = StringToInt::lookupId(m_name);
- m_uniformValue = UniformValue::fromVariant(data.backendValue);
-}
+ const QParameter *node = qobject_cast<const QParameter *>(frontEnd);
+ if (!node)
+ return;
-void Parameter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
-
- if (e->type() == PropertyUpdated) {
- if (propertyChange->propertyName() == QByteArrayLiteral("name")) {
- m_name = propertyChange->value().toString();
- m_nameId = StringToInt::lookupId(m_name);
- markDirty(AbstractRenderer::MaterialDirty | AbstractRenderer::ParameterDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("value")) {
- m_uniformValue = UniformValue::fromVariant(propertyChange->value());
- markDirty(AbstractRenderer::ParameterDirty);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) {
- markDirty(AbstractRenderer::MaterialDirty | AbstractRenderer::ParameterDirty);
- }
+ AbstractRenderer::BackendNodeDirtySet dirty = firstTime ? AbstractRenderer::ParameterDirty : static_cast<AbstractRenderer::BackendNodeDirtyFlag>(0);
+ if (node->isEnabled() != isEnabled())
+ dirty |= (AbstractRenderer::MaterialDirty | AbstractRenderer::ParameterDirty);
+
+ if (node->name() != m_name) {
+ m_name = node->name();
+ m_nameId = StringToInt::lookupId(m_name);
+ dirty |= (AbstractRenderer::MaterialDirty | AbstractRenderer::ParameterDirty);
}
- BackendNode::sceneChangeEvent(e);
+ QParameterPrivate* d = static_cast<QParameterPrivate *>(QParameterPrivate::get(const_cast<QParameter *>(node)));
+ if (d->m_backendValue != m_backendValue) {
+ m_backendValue = d->m_backendValue;
+ m_uniformValue = UniformValue::fromVariant(m_backendValue);
+ dirty |= (AbstractRenderer::ParameterDirty);
+ }
+
+ if (dirty)
+ markDirty(dirty);
+
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
}
QString Parameter::name() const
diff --git a/src/render/materialsystem/parameter_p.h b/src/render/materialsystem/parameter_p.h
index 4ab04bc8e..258834ff3 100644
--- a/src/render/materialsystem/parameter_p.h
+++ b/src/render/materialsystem/parameter_p.h
@@ -71,16 +71,16 @@ public:
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
QString name() const;
int nameId() const Q_DECL_NOTHROW { return m_nameId; }
const UniformValue &uniformValue() const { return m_uniformValue; }
+ QVariant backendValue() const { return m_backendValue; }
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QString m_name;
+ QVariant m_backendValue;
UniformValue m_uniformValue;
int m_nameId;
};
diff --git a/src/render/materialsystem/qeffect.cpp b/src/render/materialsystem/qeffect.cpp
index ba19154fd..8637a92d4 100644
--- a/src/render/materialsystem/qeffect.cpp
+++ b/src/render/materialsystem/qeffect.cpp
@@ -42,10 +42,6 @@
#include "qtechnique.h"
#include "qparameter.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
-
QT_BEGIN_NAMESPACE
using namespace Qt3DCore;
@@ -176,7 +172,7 @@ QEffect::QEffect(QEffectPrivate &dd, QNode *parent)
*/
/*!
- * Adds \a parameter to the effect. It sends a QPropertyNodeAddedChange to the backend.
+ * Adds \a parameter to the effect. It sends an update to the backend.
* The \a parameter will be used to set a corresponding uniform value in the shader used
* by this effect.
*/
@@ -196,11 +192,7 @@ void QEffect::addParameter(QParameter *parameter)
if (!parameter->parent())
parameter->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueAdded);
}
}
@@ -211,14 +203,10 @@ void QEffect::removeParameter(QParameter *parameter)
{
Q_D(QEffect);
- if (parameter && d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
d->m_parameters.removeOne(parameter);
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
}
/*!
@@ -231,7 +219,7 @@ QVector<QParameter *> QEffect::parameters() const
}
/*!
- * Adds a new technique \a t to the effect. It sends a QPropertyNodeAddedChange to the backend.
+ * Adds a new technique \a t to the effect. It sends an update to the backend.
*/
void QEffect::addTechnique(QTechnique *t)
{
@@ -250,11 +238,7 @@ void QEffect::addTechnique(QTechnique *t)
if (!t->parent())
t->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), t);
- change->setPropertyName("technique");
- d->notifyObservers(change);
- }
+ d->updateNode(t, "technique", Qt3DCore::PropertyValueAdded);
}
}
@@ -264,11 +248,8 @@ void QEffect::addTechnique(QTechnique *t)
void QEffect::removeTechnique(QTechnique *t)
{
Q_D(QEffect);
- if (t && d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), t);
- change->setPropertyName("technique");
- d->notifyObservers(change);
- }
+ if (t)
+ d->updateNode(t, "technique", Qt3DCore::PropertyValueRemoved);
d->m_techniques.removeOne(t);
// Remove bookkeeping connection
d->unregisterDestructionHelper(t);
diff --git a/src/render/materialsystem/qfilterkey.cpp b/src/render/materialsystem/qfilterkey.cpp
index 0cffde7c1..2105da987 100644
--- a/src/render/materialsystem/qfilterkey.cpp
+++ b/src/render/materialsystem/qfilterkey.cpp
@@ -40,7 +40,6 @@
#include "qfilterkey.h"
#include "qfilterkey_p.h"
#include <private/qnode_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/materialsystem/qgraphicsapifilter.cpp b/src/render/materialsystem/qgraphicsapifilter.cpp
index 70f329172..9b5557930 100644
--- a/src/render/materialsystem/qgraphicsapifilter.cpp
+++ b/src/render/materialsystem/qgraphicsapifilter.cpp
@@ -107,6 +107,11 @@ QGraphicsApiFilterPrivate *QGraphicsApiFilterPrivate::get(QGraphicsApiFilter *q)
return q->d_func();
}
+const QGraphicsApiFilterPrivate *QGraphicsApiFilterPrivate::get(const QGraphicsApiFilter *q)
+{
+ return q->d_func();
+}
+
/*!
\class Qt3DRender::QGraphicsApiFilter
\inmodule Qt3DRender
diff --git a/src/render/materialsystem/qgraphicsapifilter_p.h b/src/render/materialsystem/qgraphicsapifilter_p.h
index 3961d4f93..435451c27 100644
--- a/src/render/materialsystem/qgraphicsapifilter_p.h
+++ b/src/render/materialsystem/qgraphicsapifilter_p.h
@@ -84,6 +84,7 @@ public:
}
static QGraphicsApiFilterPrivate *get(QGraphicsApiFilter *q);
+ static const QGraphicsApiFilterPrivate *get(const QGraphicsApiFilter *q);
Q_DECLARE_PUBLIC(QGraphicsApiFilter)
GraphicsApiFilterData m_data;
diff --git a/src/render/materialsystem/qmaterial.cpp b/src/render/materialsystem/qmaterial.cpp
index c6913441e..edd227500 100644
--- a/src/render/materialsystem/qmaterial.cpp
+++ b/src/render/materialsystem/qmaterial.cpp
@@ -43,9 +43,6 @@
#include "qeffect.h"
#include <Qt3DRender/private/renderlogging_p.h>
#include "qparameter.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
/*!
\qmltype Material
@@ -275,11 +272,7 @@ void QMaterial::addParameter(QParameter *parameter)
if (!parameter->parent())
parameter->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueAdded);
}
}
@@ -290,11 +283,7 @@ void QMaterial::removeParameter(QParameter *parameter)
{
Q_ASSERT(parameter);
Q_D(QMaterial);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
d->m_parameters.removeOne(parameter);
}
diff --git a/src/render/materialsystem/qparameter.cpp b/src/render/materialsystem/qparameter.cpp
index 92f3cf0c2..969882564 100644
--- a/src/render/materialsystem/qparameter.cpp
+++ b/src/render/materialsystem/qparameter.cpp
@@ -40,7 +40,6 @@
#include "qparameter.h"
#include "qparameter_p.h"
#include <Qt3DRender/private/renderlogging_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qtexture.h>
diff --git a/src/render/materialsystem/qrenderpass.cpp b/src/render/materialsystem/qrenderpass.cpp
index 111bb7b5f..dcb831b13 100644
--- a/src/render/materialsystem/qrenderpass.cpp
+++ b/src/render/materialsystem/qrenderpass.cpp
@@ -43,9 +43,6 @@
#include "qparameter.h"
#include "qfilterkey.h"
#include "qrenderstate.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
#include <Qt3DCore/private/qnode_p.h>
QT_BEGIN_NAMESPACE
@@ -231,12 +228,6 @@ void QRenderPass::setShaderProgram(QShaderProgram *shaderProgram)
Q_D(QRenderPass);
if (d->m_shader != shaderProgram) {
- if (d->m_shader != nullptr && d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), d->m_shader);
- change->setPropertyName("shaderProgram");
- d->notifyObservers(change);
- }
-
if (d->m_shader)
d->unregisterDestructionHelper(d->m_shader);
@@ -283,11 +274,7 @@ void QRenderPass::addFilterKey(QFilterKey *filterKey)
if (!filterKey->parent())
filterKey->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), filterKey);
- change->setPropertyName("filterKeys");
- d->notifyObservers(change);
- }
+ d->updateNode(filterKey, "filterKeys", Qt3DCore::PropertyValueAdded);
}
}
@@ -298,11 +285,7 @@ void QRenderPass::removeFilterKey(QFilterKey *filterKey)
{
Q_ASSERT(filterKey);
Q_D(QRenderPass);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), filterKey);
- change->setPropertyName("filterKeys");
- d->notifyObservers(change);
- }
+ d->updateNode(filterKey, "filterKeys", Qt3DCore::PropertyValueRemoved);
d->m_filterKeyList.removeOne(filterKey);
// Remove bookkeeping connection
d->unregisterDestructionHelper(filterKey);
@@ -339,11 +322,7 @@ void QRenderPass::addRenderState(QRenderState *state)
if (!state->parent())
state->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), state);
- change->setPropertyName("renderState");
- d->notifyObservers(change);
- }
+ d->updateNode(state, "renderState", Qt3DCore::PropertyValueAdded);
}
}
@@ -354,11 +333,7 @@ void QRenderPass::removeRenderState(QRenderState *state)
{
Q_ASSERT(state);
Q_D(QRenderPass);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), state);
- change->setPropertyName("renderState");
- d->notifyObservers(change);
- }
+ d->updateNode(state, "renderState", Qt3DCore::PropertyValueRemoved);
d->m_renderStates.removeOne(state);
// Remove bookkeeping connection
d->unregisterDestructionHelper(state);
@@ -394,11 +369,7 @@ void QRenderPass::addParameter(QParameter *parameter)
if (!parameter->parent())
parameter->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueAdded);
}
}
@@ -409,11 +380,7 @@ void QRenderPass::removeParameter(QParameter *parameter)
{
Q_ASSERT(parameter);
Q_D(QRenderPass);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
d->m_parameters.removeOne(parameter);
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
diff --git a/src/render/materialsystem/qshaderimage.cpp b/src/render/materialsystem/qshaderimage.cpp
new file mode 100644
index 000000000..f2ce04c3d
--- /dev/null
+++ b/src/render/materialsystem/qshaderimage.cpp
@@ -0,0 +1,984 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qshaderimage.h"
+#include "qshaderimage_p.h"
+#include <Qt3DRender/qabstracttexture.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QShaderImagePrivate::QShaderImagePrivate()
+ : Qt3DCore::QNodePrivate()
+ , m_texture(nullptr)
+ , m_mipLevel(0)
+ , m_layer(0)
+ , m_access(QShaderImage::ReadWrite)
+ , m_format(QShaderImage::Automatic)
+ , m_layered(false)
+{
+}
+
+QShaderImagePrivate::~QShaderImagePrivate()
+{
+}
+
+/*!
+ \qmltype ShaderImage
+ \instantiates Qt3DRender::QShaderImage
+ \inqmlmodule Qt3D.Render
+ \since 5.14
+ \brief Provides Image access to shader programs.
+
+ To make the content of textures available for read and write operations in
+ a shader, they need to exposed as ShaderImage. Textures can be composed of
+ several mip levels, layers and faces. Additionally declaring a ShaderImage
+ allows specifying which level, layer or face of the texture content we want
+ to access.
+
+ ShaderImage has to be assigned as a Parameter's value and reference a valid
+ Qt3D.Render.AbstractTexture to work properly.
+
+ If the referenced texture is a one-dimensional array, two-dimensional array,
+ three-dimensional, cube map, cube map array, or two-dimensional multisample
+ array texture, it is possible to bind either the entire texture level or a
+ single layer or face of the texture level. This can be controlled with the
+ \l layered property.
+
+ Support for ShaderImage is only supported with OpenGL 4 and partially with
+ OpenGL ES 3.1 and 3.2.
+
+ OpenGL 4 supports the following image types:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li image1D
+ \li GL_IMAGE_1D
+ \li Texture1D
+ \row
+ \li image2D
+ \li GL_IMAGE_2D
+ \li Texture2D
+ \row
+ \li image3D
+ \li GL_IMAGE_3D
+ \li Texture3D
+ \row
+ \li image2DRect
+ \li GL_IMAGE_2D_RECT
+ \li TextureRectangle
+ \row
+ \li imageCube
+ \li GL_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li imageBuffer
+ \li GL_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li image1DArray
+ \li GL_IMAGE_1D_ARRAY
+ \li Texture1DArray
+ \row
+ \li image2DArray
+ \li GL_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li imageCubeArray
+ \li GL_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li image2DMS
+ \li GL_IMAGE_2D_MULTISAMPLE
+ \li Texture2DMultisample
+ \row
+ \li image2DMSArray
+ \li GL_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li Texture2DMultisampleArray
+ \row
+ \li iimage1D
+ \li GL_INT_IMAGE_1D
+ \li Texture1D
+ \row
+ \li iimage2D
+ \li GL_INT_IMAGE_2D
+ \li Texture2D
+ \row
+ \li iimage3D
+ \li GL_INT_IMAGE_3D
+ \li Texture3D
+ \row
+ \li iimage2DRect
+ \li GL_INT_IMAGE_2D_RECT
+ \li TextureRectangle
+ \row
+ \li iimageCube
+ \li GL_INT_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li iimageBuffer
+ \li GL_INT_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li iimage1DArray
+ \li GL_INT_IMAGE_1D_ARRAY
+ \li Texture1DArray
+ \row
+ \li iimage2DArray
+ \li GL_INT_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li iimageCubeArray
+ \li GL_INT_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li iimage2DMS
+ \li GL_INT_IMAGE_2D_MULTISAMPLE
+ \li Texture2DMultisample
+ \row
+ \li iimage2DMSArray
+ \li GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li Texture2DMultisampleArray
+ \row
+ \li uimage1D
+ \li GL_UNSIGNED_INT_IMAGE_1D
+ \li Texture1D
+ \row
+ \li uimage2D
+ \li GL_UNSIGNED_INT_IMAGE_2D
+ \li Texture2D
+ \row
+ \li uimage3D
+ \li GL_UNSIGNED_INT_IMAGE_3D
+ \li Texture3D
+ \row
+ \li uimage2DRect
+ \li GL_UNSIGNED_INT_IMAGE_2D_RECT
+ \li TextureRectangle
+ \row
+ \li uimageCube
+ \li GL_UNSIGNED_INT_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li uimageBuffer
+ \li GL_UNSIGNED_INT_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li uimage1DArray
+ \li GL_UNSIGNED_INT_IMAGE_1D_ARRAY
+ \li Texture1DArray
+ \row
+ \li uimage2DArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li uimageCubeArray
+ \li GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li uimage2DMS
+ \li GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE
+ \li Texture2DMultisample
+ \row
+ \li uimage2DMSArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li Texture2DMultisampleArray
+ \endtable
+
+ OpenGL ES 3.1 supports the following image types:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li image2D
+ \li GL_IMAGE_2D
+ \li Texture2D
+ \row
+ \li image3D
+ \li GL_IMAGE_3D
+ \li Texture3D
+ \row
+ \li imageCube
+ \li GL_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li image2DArray
+ \li GL_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li iimage2D
+ \li GL_INT_IMAGE_2D
+ \li Texture2D
+ \row
+ \li iimage3D
+ \li GL_INT_IMAGE_3D
+ \li Texture3D
+ \row
+ \li iimageCube
+ \li GL_INT_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li iimage2DArray
+ \li GL_INT_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li uimage2D
+ \li GL_UNSIGNED_INT_IMAGE_2D
+ \li Texture2D
+ \row
+ \li uimage3D
+ \li GL_UNSIGNED_INT_IMAGE_3D
+ \li Texture3D
+ \row
+ \li uimageCube
+ \li GL_UNSIGNED_INT_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li uimage2DArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \endtable
+
+ OpenGL ES 3.2 supports all of the OpenGL ES 3.1 image types as well as the
+ following:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li imageBuffer
+ \li GL_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li imageCubeArray
+ \li GL_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li iimageBuffer
+ \li GL_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li iimageCubeArray
+ \li GL_INT_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li uimageBuffer
+ \li GL_UNSIGNED_INT_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li uimageCubeArray
+ \li GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \endtable
+
+ Expected use would look like:
+
+ \badcode
+
+ import Qt3D.Render 2.14
+
+ Entity {
+ ...
+ Texture2D {
+ id: tex2D
+ ...
+ }
+
+ Material {
+ parameters: Parameter {
+ name: "imageUniformName"
+ value: ShaderImage {
+ texture: tex2D
+ }
+ }
+ ...
+ }
+ ...
+ }
+ \endcode
+ */
+
+/*!
+ \qmlproperty Qt3DRender::QShaderImage::mipLevel
+
+ Holds which mipLevel out of the referenced texture should be used for the
+ ShaderImage.
+
+ \default 0
+ */
+
+/*!
+ \qmlproperty Qt3DRender::QShaderImage::layer
+
+ Holds which layer out of the referenced texture should be used for the
+ ShaderImage. This property does nothing if \a layered is set to true or if
+ the reference texture's type isn't compatible with layers.
+
+ \note When the referenced texture is of type cube map or cube map array and
+ \a ĺayered is set to false, the face and layer are retrieved in the
+ following manner:
+ \badcode
+ cubeMapLayer = layer / 6
+ cubeMapFace = layer - (cubeMapLayer * 6)
+ \endcode
+
+ \default 0
+ */
+
+/*!
+ * \qmlproperty Qt3DRender::QShaderImage::layered
+
+ If set to true, if the referenced texture is a one-dimensional array,
+ two-dimensional array, three-dimensional, cube map, cube map array, or
+ two-dimensional multisample array texture, the entire level will be bound
+ for all layers. If set to false, only the single layer specified by the \a
+ layer property will be bound.
+
+ \default false
+ */
+
+/*!
+ \qmlproperty Qt3DRender::QShaderImage::access
+
+ Specifies the type of access we want to allow from our shader instances to
+ the image. If a shader tries to write or read from an image that has
+ incompatible access, the behavior is undefined.
+
+ \default ShaderImage.ReadWrite
+ */
+
+/*!
+ \qmlproperty Qt3DRender::QShaderImage::format
+
+ Specifies the image format, which is essentially important when storing values
+ in the ShaderImage from a shader.
+
+ The format doesn't have to be the same as the referenced texture's format.
+ It however has to be compatible (matching in size but not necessarily by
+ class type). For instance a texture of format R32F (size 32bits, class
+ 1x32) could be used with an image of format RGBA8I (size 32bits, class
+ 4x8). Table 8.27 of the
+ \l{https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf}{OpenGL specifications}
+ shows the size and class for all supported image formats.
+
+ By default Qt3D will try to set the image format to match that of the
+ referenced texture.
+
+ \default ShaderImage.Automatic
+ */
+
+/*!
+ \class Qt3DRender::QShaderImage
+ \inmodule Qt3DRender
+ \since 5.14
+ \brief Provides Image access to shader programs.
+
+ To make the content of textures available for read and write operations in
+ a shader, they need to exposed as QShaderImage. Textures can be composed of
+ several mip levels, layers and faces. Additionally declaring a QShaderImage
+ allows specifying which level, layer or face of the texture content we want
+ to access.
+
+ QShaderImage has to be assigned as a QParameter's value and reference a valid
+ Qt3DRender::QAbstractTexture to work properly.
+
+ If the referenced texture is a one-dimensional array, two-dimensional array,
+ three-dimensional, cube map, cube map array, or two-dimensional multisample
+ array texture, it is possible to bind either the entire texture level or a
+ single layer or face of the texture level. This can be controlled with the
+ \l layered property.
+
+ Support for QShaderImage is only supported with OpenGL 4 and partially with
+ OpenGL ES 3.1 and 3.2.
+
+ OpenGL 4 supports the following image types:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li image1D
+ \li GL_IMAGE_1D
+ \li QTexture1D
+ \row
+ \li image2D
+ \li GL_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li image3D
+ \li GL_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li image2DRect
+ \li GL_IMAGE_2D_RECT
+ \li QTextureRectangle
+ \row
+ \li imageCube
+ \li GL_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li imageBuffer
+ \li GL_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li image1DArray
+ \li GL_IMAGE_1D_ARRAY
+ \li QTexture1DArray
+ \row
+ \li image2DArray
+ \li GL_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li imageCubeArray
+ \li GL_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li image2DMS
+ \li GL_IMAGE_2D_MULTISAMPLE
+ \li QTexture2DMultisample
+ \row
+ \li image2DMSArray
+ \li GL_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li QTexture2DMultisampleArray
+ \row
+ \li iimage1D
+ \li GL_INT_IMAGE_1D
+ \li QTexture1D
+ \row
+ \li iimage2D
+ \li GL_INT_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li iimage3D
+ \li GL_INT_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li iimage2DRect
+ \li GL_INT_IMAGE_2D_RECT
+ \li QTextureRectangle
+ \row
+ \li iimageCube
+ \li GL_INT_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li iimageBuffer
+ \li GL_INT_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li iimage1DArray
+ \li GL_INT_IMAGE_1D_ARRAY
+ \li QTexture1DArray
+ \row
+ \li iimage2DArray
+ \li GL_INT_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li iimageCubeArray
+ \li GL_INT_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li iimage2DMS
+ \li GL_INT_IMAGE_2D_MULTISAMPLE
+ \li QTexture2DMultisample
+ \row
+ \li iimage2DMSArray
+ \li GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li QTexture2DMultisampleArray
+ \row
+ \li uimage1D
+ \li GL_UNSIGNED_INT_IMAGE_1D
+ \li QTexture1D
+ \row
+ \li uimage2D
+ \li GL_UNSIGNED_INT_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li uimage3D
+ \li GL_UNSIGNED_INT_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li uimage2DRect
+ \li GL_UNSIGNED_INT_IMAGE_2D_RECT
+ \li QTextureRectangle
+ \row
+ \li uimageCube
+ \li GL_UNSIGNED_INT_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li uimageBuffer
+ \li GL_UNSIGNED_INT_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li uimage1DArray
+ \li GL_UNSIGNED_INT_IMAGE_1D_ARRAY
+ \li QTexture1DArray
+ \row
+ \li uimage2DArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li uimageCubeArray
+ \li GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li uimage2DMS
+ \li GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE
+ \li QTexture2DMultisample
+ \row
+ \li uimage2DMSArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li QTexture2DMultisampleArray
+ \endtable
+
+ OpenGL ES 3.1 supports the following image types:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li image2D
+ \li GL_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li image3D
+ \li GL_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li imageCube
+ \li GL_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li image2DArray
+ \li GL_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li iimage2D
+ \li GL_INT_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li iimage3D
+ \li GL_INT_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li iimageCube
+ \li GL_INT_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li iimage2DArray
+ \li GL_INT_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li uimage2D
+ \li GL_UNSIGNED_INT_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li uimage3D
+ \li GL_UNSIGNED_INT_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li uimageCube
+ \li GL_UNSIGNED_INT_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li uimage2DArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \endtable
+
+ OpenGL ES 3.2 supports all of the OpenGL ES 3.1 image types as well as the
+ following:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li imageBuffer
+ \li GL_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li imageCubeArray
+ \li GL_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li iimageBuffer
+ \li GL_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li iimageCubeArray
+ \li GL_INT_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li uimageBuffer
+ \li GL_UNSIGNED_INT_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li uimageCubeArray
+ \li GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \endtable
+
+ Expected use would look like:
+
+ \badcode
+ Qt3DRender::QTexture2D *tex2D = new Qt3DRender::QTexture2D();
+ ...
+ Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial();
+ ...
+ Qt3DRender::QParameter *imageParameter = new Qt3DRender::QParameter();
+ Qt3DRender::QShaderImage *shaderImage = new Qt3DRender::QShaderImage();
+
+ shaderImage->setTexture(tex2D);
+
+ imageParameter->setName("imageUniformName");
+ imageParameter->setValue(QVariant::fromValue(shaderImage));
+
+ material->addParameter(imageParamenter);
+ \endcode
+ */
+
+/*!
+ \property Qt3DRender::QShaderImage::mipLevel
+
+ Holds which mipLevel out of the referenced texture should be used for the
+ QShaderImage.
+
+ \default 0
+ */
+
+/*!
+ \property Qt3DRender::QShaderImage::layer
+
+ Holds which layer out of the referenced texture should be used for the
+ QShaderImage. This property does nothing if \a layered is set to true or if the
+ reference texture's type isn't compatible with layers.
+
+ \note When the referenced texture is of type cube map or cube map array and
+ \a ĺayered is set to false, the face and layer are retrieved in the
+ following manner:
+ \badcode
+ cubeMapLayer = layer / 6
+ cubeMapFace = layer - (cubeMapLayer * 6)
+ \endcode
+
+ \default 0
+ */
+
+/*!
+ * \property Qt3DRender::QShaderImage::layered
+
+ If set to true, if the referenced texture is a one-dimensional array,
+ two-dimensional array, three-dimensional, cube map, cube map array, or
+ two-dimensional multisample array texture, the entire level will be bound
+ for all layers. If set to false, only the single layer specified by the \a
+ layer property will be bound.
+
+ \default false
+ */
+
+/*!
+ \property Qt3DRender::QShaderImage::access
+
+ Specifies the type of access we want to allow from our shader instances to
+ the image. If a shader tries to write or read from an image that has
+ incompatible access, the behavior is undefined.
+
+ \default QShaderImage::ReadWrite
+ */
+
+/*!
+ \property Qt3DRender::QShaderImage::format
+
+ Specifies the image format, which is essentially important when storing values
+ in the Image from a shader.
+
+ The format doesn't have to be the same as the referenced texture's format.
+ It however has to be compatible (matching in size but not necessarily by
+ class type). For instance a texture of format R32F (size 32bits, class
+ 1x32) could be used with an image of format RGBA8I (size 32bits, class
+ 4x8). Table 8.27 of the
+ \l{https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf}{OpenGL specifications}
+ shows the size and class for all supported Image formats.
+
+ By default Qt3D will try to set the image format to match that of the
+ referenced texture.
+
+ \default QShaderImage::Automatic
+ */
+
+/*!
+ \enum Qt3DRender::QShaderImage::Access
+
+ \value ReadOnly
+ Image will only be read from in shaders
+ \value WriteOnly
+ Image will only be written into from shaders
+ \value ReadWrite
+ Image will only be read and written into from shaders
+*/
+
+/*!
+ \enum Qt3DRender::QShaderImage::ImageFormat
+
+ This list describes all possible image formats
+
+ \value NoFormat
+ GL_NONE
+ \value Automatic
+ Qt 3D will try to determine the format automatically based on
+ the referenced texture.
+ \value R8_UNorm
+ GL_R8 (GLSL type r8, supported by OpenGL 4.2+)
+ \value RG8_UNorm
+ GL_RG8 (GLSL type rg8, supported by OpenGL 4.2+)
+ \value RGBA8_UNorm
+ GL_RGBA8 (GLSL type rgba8, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16_UNorm
+ GL_R16 (GLSL type r16, supported by OpenGL 4.2+)
+ \value RG16_UNorm
+ GL_RG16 (GLSL type rg16, supported by OpenGL 4.2+)
+ \value RGBA16_UNorm
+ GL_RGBA16 (GLSL type rgba16, supported by OpenGL 4.2+)
+ \value R8_SNorm
+ GL_R8_SNORM (GLSL type r8_snorm, supported by OpenGL 4.2+)
+ \value RG8_SNorm
+ GL_RG8_SNORM (GLSL type rg8_snorm, supported by OpenGL 4.2+)
+ \value RGBA8_SNorm
+ GL_RGBA8_SNORM (GLSL type rgba8_snorm, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16_SNorm
+ GL_R16_SNORM (GLSL type r16_snorm, supported by OpenGL 4.2+)
+ \value RG16_SNorm
+ GL_RG16_SNORM (GLSL type rg16_snorm, supported by OpenGL 4.2+)
+ \value RGBA16_SNorm
+ GL_RGBA16_SNORM (GLSL type rgba16_snorm, supported by OpenGL 4.2+)
+ \value R8U
+ GL_R8UI (GLSL type r8ui, supported by OpenGL 4.2+)
+ \value RG8U
+ GL_RG8UI (GLSL type rg8ui, supported by OpenGL 4.2+)
+ \value RGBA8U
+ GL_RGBA8UI (GLSL type rgba8ui, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16U
+ GL_R16UI (GLSL type r16ui, supported by OpenGL 4.2+)
+ \value RG16U
+ GL_RG16UI (GLSL type rg16ui, supported by OpenGL 4.2+)
+ \value RGBA16U
+ GL_RGBA16UI (GLSL type rgba16ui, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R32U
+ GL_R32UI (GLSL type r32ui, supported by OpenGL 4.2+, OpenGL ES 3.1)
+ \value RG32U
+ GL_RG32UI (GLSL type rg32ui, supported by OpenGL 4.2+)
+ \value RGBA32U
+ GL_RGBA32UI (GLSL type rgba32ui, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R8I
+ GL_R8I (GLSL type r8i, supported by OpenGL 4.2+)
+ \value RG8I
+ GL_RG8I (GLSL type rg8i, supported by OpenGL 4.2+)
+ \value RGBA8I
+ GL_RGBA8I (GLSL type rgba8i, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16I
+ GL_R16I (GLSL type r16i, supported by OpenGL 4.2+)
+ \value RG16I
+ GL_RG16I (GLSL type rg16i, supported by OpenGL 4.2+)
+ \value RGBA16I
+ GL_RGBA16I (GLSL type rgba16i, supported by OpenGL 4.2+, OpenGL ES 3.1)
+ \value R32I
+ GL_R32I (GLSL type r32i, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value RG32I
+ GL_RG32I (GLSL type rg32i, supported by OpenGL 4.2+)
+ \value RGBA32I
+ GL_RGBA32I (GLSL type rgba32i, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16F
+ GL_R16F (GLSL type r16f, supported by OpenGL 4.2+)
+ \value RG16F
+ GL_RG16F (GLSL type rg16f, supported by OpenGL 4.2+)
+ \value RGBA16F
+ GL_RGBA16F (GLSL type rgba16f, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R32F
+ GL_R32F (GLSL type r32f, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value RG32F
+ GL_RG32F (GLSL type rg32f, supported by OpenGL 4.2+)
+ \value RGBA32F
+ GL_RGBA32F (GLSL type rgba32f, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value RG11B10F
+ GL_R11F_G11F_B10F (GLSL type r11f_g11f_b10f, supported by OpenGL 4.2+)
+ \value RGB10A2
+ GL_RGB10_A2 (GLSL type rgb10_a2, supported by OpenGL 4.2+)
+ \value RGB10A2U
+ GL_RGB10_A2UI (GLSL type rgb10_a2ui, supported by OpenGL 4.2+)
+*/
+
+
+QShaderImage::QShaderImage(Qt3DCore::QNode *parent)
+ : Qt3DCore::QNode(*new QShaderImagePrivate, parent)
+{
+}
+
+QShaderImage::~QShaderImage()
+{
+
+}
+
+QAbstractTexture *QShaderImage::texture() const
+{
+ Q_D(const QShaderImage);
+ return d->m_texture;
+}
+
+bool QShaderImage::layered() const
+{
+ Q_D(const QShaderImage);
+ return d->m_layered;
+}
+
+int QShaderImage::mipLevel() const
+{
+ Q_D(const QShaderImage);
+ return d->m_mipLevel;
+}
+
+int QShaderImage::layer() const
+{
+ Q_D(const QShaderImage);
+ return d->m_layer;
+}
+
+QShaderImage::Access QShaderImage::access() const
+{
+ Q_D(const QShaderImage);
+ return d->m_access;
+}
+
+QShaderImage::ImageFormat QShaderImage::format() const
+{
+ Q_D(const QShaderImage);
+ return d->m_format;
+}
+
+void QShaderImage::setTexture(QAbstractTexture *texture)
+{
+ Q_D(QShaderImage);
+ if (texture == d->m_texture)
+ return;
+
+ if (d->m_texture)
+ d->unregisterDestructionHelper(d->m_texture);
+
+ if (texture && !texture->parent())
+ texture->setParent(this);
+
+ d->m_texture = texture;
+
+ if (d->m_texture)
+ d->registerDestructionHelper(d->m_texture, &QShaderImage::setTexture, d->m_texture);
+
+ Q_EMIT textureChanged(texture);
+}
+
+void QShaderImage::setLayered(bool layered)
+{
+ Q_D(QShaderImage);
+ if (layered == d->m_layered)
+ return;
+ d->m_layered = layered;
+ Q_EMIT layeredChanged(layered);
+}
+
+void QShaderImage::setMipLevel(int mipLevel)
+{
+ Q_D(QShaderImage);
+ if (mipLevel == d->m_mipLevel)
+ return;
+ d->m_mipLevel = mipLevel;
+ Q_EMIT mipLevelChanged(mipLevel);
+}
+
+void QShaderImage::setLayer(int layer)
+{
+ Q_D(QShaderImage);
+ if (layer == d->m_layer)
+ return;
+ d->m_layer = layer;
+ Q_EMIT layerChanged(layer);
+}
+
+void QShaderImage::setAccess(QShaderImage::Access access)
+{
+ Q_D(QShaderImage);
+ if (access == d->m_access)
+ return;
+ d->m_access = access;
+ Q_EMIT accessChanged(access);
+}
+
+void QShaderImage::setFormat(QShaderImage::ImageFormat format)
+{
+ Q_D(QShaderImage);
+ if (format == d->m_format)
+ return;
+ d->m_format = format;
+ Q_EMIT formatChanged(format);
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr Qt3DRender::QShaderImage::createNodeCreationChange() const
+{
+ auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QShaderImageData>::create(this);
+ QShaderImageData &data = creationChange->data;
+ Q_D(const QShaderImage);
+ data.textureId = Qt3DCore::qIdForNode(d->m_texture);
+ data.layer = d->m_layer;
+ data.mipLevel = d->m_mipLevel;
+ data.access = d->m_access;
+ data.format = d->m_format;
+ data.layered = d->m_layered;
+ return creationChange;
+
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/materialsystem/qshaderimage.h b/src/render/materialsystem/qshaderimage.h
new file mode 100644
index 000000000..e1f5459d2
--- /dev/null
+++ b/src/render/materialsystem/qshaderimage.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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_QSHADERIMAGE_H
+#define QT3DRENDER_QSHADERIMAGE_H
+
+#include <Qt3DCore/qnode.h>
+#include <Qt3DRender/qt3drender_global.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QAbstractTexture;
+class QShaderImagePrivate;
+
+class Q_3DRENDERSHARED_EXPORT QShaderImage : public Qt3DCore::QNode
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged)
+ Q_PROPERTY(bool layered READ layered WRITE setLayered NOTIFY layeredChanged)
+ Q_PROPERTY(int mipLevel READ mipLevel WRITE setMipLevel NOTIFY mipLevelChanged)
+ Q_PROPERTY(int layer READ layer WRITE setLayer NOTIFY layerChanged)
+ Q_PROPERTY(Access access READ access WRITE setAccess NOTIFY accessChanged)
+ Q_PROPERTY(ImageFormat format READ format WRITE setFormat NOTIFY formatChanged)
+
+public:
+ enum Access {
+ ReadOnly = 0,
+ WriteOnly,
+ ReadWrite
+ };
+ Q_ENUM(Access)
+
+ enum ImageFormat {
+ NoFormat = 0, // GL_NONE
+ Automatic = 1, // The Qt3D engine automatically determines the best format
+
+ // Unsigned normalized formats
+ R8_UNorm = 0x8229, // GL_R8
+ RG8_UNorm = 0x822B, // GL_RG8
+ RGBA8_UNorm = 0x8058, // GL_RGBA8
+
+ R16_UNorm = 0x822A, // GL_R16
+ RG16_UNorm = 0x822C, // GL_RG16
+ RGBA16_UNorm = 0x805B, // GL_RGBA16
+
+ // Signed normalized formats
+ R8_SNorm = 0x8F94, // GL_R8_SNORM
+ RG8_SNorm = 0x8F95, // GL_RG8_SNORM
+ RGBA8_SNorm = 0x8F97, // GL_RGBA8_SNORM
+
+ R16_SNorm = 0x8F98, // GL_R16_SNORM
+ RG16_SNorm = 0x8F99, // GL_RG16_SNORM
+ RGBA16_SNorm = 0x8F9B, // GL_RGBA16_SNORM
+
+ // Unsigned integer formats
+ R8U = 0x8232, // GL_R8UI
+ RG8U = 0x8238, // GL_RG8UI
+ RGBA8U = 0x8D7C, // GL_RGBA8UI
+
+ R16U = 0x8234, // GL_R16UI
+ RG16U = 0x823A, // GL_RG16UI
+ RGBA16U = 0x8D76, // GL_RGBA16UI
+
+ R32U = 0x8236, // GL_R32UI
+ RG32U = 0x823C, // GL_RG32UI
+ RGBA32U = 0x8D70, // GL_RGBA32UI
+
+ // Signed integer formats
+ R8I = 0x8231, // GL_R8I
+ RG8I = 0x8237, // GL_RG8I
+ RGBA8I = 0x8D8E, // GL_RGBA8I
+
+ R16I = 0x8233, // GL_R16I
+ RG16I = 0x8239, // GL_RG16I
+ RGBA16I = 0x8D88, // GL_RGBA16I
+
+ R32I = 0x8235, // GL_R32I
+ RG32I = 0x823B, // GL_RG32I
+ RGBA32I = 0x8D82, // GL_RGBA32I
+
+ // Floating point formats
+ R16F = 0x822D, // GL_R16F
+ RG16F = 0x822F, // GL_RG16F
+ RGBA16F = 0x881A, // GL_RGBA16F
+
+ R32F = 0x822E, // GL_R32F
+ RG32F = 0x8230, // GL_RG32F
+ RGBA32F = 0x8814, // GL_RGBA32F
+
+ // Packed formats
+ RG11B10F = 0x8C3A, // GL_R11F_G11F_B10F
+ RGB10A2 = 0x8059, // GL_RGB10_A2
+ RGB10A2U = 0x906F, // GL_RGB10_A2_UI
+ };
+ Q_ENUM(ImageFormat)
+
+ explicit QShaderImage(Qt3DCore::QNode *parent = nullptr);
+ ~QShaderImage();
+
+ Qt3DRender::QAbstractTexture *texture() const;
+ bool layered() const;
+ int mipLevel() const;
+ int layer() const;
+ Access access() const;
+ ImageFormat format() const;
+
+public Q_SLOTS:
+ void setTexture(Qt3DRender::QAbstractTexture *texture);
+ void setLayered(bool layered);
+ void setMipLevel(int mipLevel);
+ void setLayer(int layer);
+ void setAccess(Access access);
+ void setFormat(ImageFormat format);
+
+Q_SIGNALS:
+ void textureChanged(Qt3DRender::QAbstractTexture *texture);
+ void layeredChanged(bool layered);
+ void mipLevelChanged(int mipLevel);
+ void layerChanged(int layer);
+ void accessChanged(Access access);
+ void formatChanged(ImageFormat format);
+
+private:
+ Q_DECLARE_PRIVATE(QShaderImage)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSHADERIMAGE_H
diff --git a/src/render/materialsystem/qshaderimage_p.h b/src/render/materialsystem/qshaderimage_p.h
new file mode 100644
index 000000000..33cffb84a
--- /dev/null
+++ b/src/render/materialsystem/qshaderimage_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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_QSHADERIMAGE_P_H
+#define QT3DRENDER_QSHADERIMAGE_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/private/qnode_p.h>
+#include <Qt3DRender/qshaderimage.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QAbstractTexture;
+
+class QShaderImagePrivate : public Qt3DCore::QNodePrivate
+{
+public:
+ QShaderImagePrivate();
+ ~QShaderImagePrivate();
+
+ Q_DECLARE_PUBLIC(QShaderImage)
+
+ Qt3DRender::QAbstractTexture *m_texture;
+ int m_mipLevel;
+ int m_layer;
+ QShaderImage::Access m_access;
+ QShaderImage::ImageFormat m_format;
+ bool m_layered;
+};
+
+struct QShaderImageData
+{
+ Qt3DCore::QNodeId textureId;
+ int mipLevel;
+ int layer;
+ QShaderImage::Access access;
+ QShaderImage::ImageFormat format;
+ bool layered;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSHADERIMAGE_P_H
diff --git a/src/render/materialsystem/qshaderprogrambuilder.cpp b/src/render/materialsystem/qshaderprogrambuilder.cpp
index 84dd33372..6613661d1 100644
--- a/src/render/materialsystem/qshaderprogrambuilder.cpp
+++ b/src/render/materialsystem/qshaderprogrambuilder.cpp
@@ -79,6 +79,47 @@ QShaderProgramBuilderPrivate::QShaderProgramBuilderPrivate()
{
}
+void QShaderProgramBuilderPrivate::setShaderCode(const QByteArray &code, QShaderProgram::ShaderType type)
+{
+ Q_Q(QShaderProgramBuilder);
+ const bool blocked = q->blockNotifications(true);
+
+ switch (type) {
+ case QShaderProgram::Vertex: {
+ m_vertexShaderCode = code;
+ emit q->vertexShaderCodeChanged(m_vertexShaderCode);
+ break;
+ }
+ case QShaderProgram::Fragment:{
+ m_fragmentShaderCode = code;
+ emit q->fragmentShaderCodeChanged(m_fragmentShaderCode);
+ break;
+ }
+ case QShaderProgram::Geometry: {
+ m_geometryShaderCode = code;
+ emit q->geometryShaderCodeChanged(m_geometryShaderCode);
+ break;
+ }
+ case QShaderProgram::Compute: {
+ m_computeShaderCode = code;
+ emit q->computeShaderCodeChanged(m_computeShaderCode);
+ break;
+ }
+ case QShaderProgram::TessellationControl: {
+ m_tessControlShaderCode = code;
+ emit q->tessellationControlShaderCodeChanged(m_tessControlShaderCode);
+ break;
+ }
+ case QShaderProgram::TessellationEvaluation: {
+ m_tessEvalShaderCode = code;
+ emit q->tessellationEvaluationShaderCodeChanged(m_tessEvalShaderCode);
+ break;
+ }
+ }
+
+ q->blockNotifications(blocked);
+}
+
QShaderProgramBuilder::QShaderProgramBuilder(QNode *parent)
: QNode(*new QShaderProgramBuilderPrivate, parent)
{
@@ -94,53 +135,6 @@ QShaderProgramBuilder::QShaderProgramBuilder(QShaderProgramBuilderPrivate &dd, Q
{
}
-void QShaderProgramBuilder::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
-{
- Q_D(QShaderProgramBuilder);
- if (change->type() == Qt3DCore::PropertyUpdated) {
- const Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
- if (e->propertyName() == QByteArrayLiteral("generatedShaderCode")) {
- const bool blocked = blockNotifications(true);
- const QPair<int, QByteArray> data = e->value().value<QPair<int, QByteArray>>();
-
- switch (data.first) {
- case QShaderProgram::Vertex: {
- d->m_vertexShaderCode = data.second;
- emit vertexShaderCodeChanged(d->m_vertexShaderCode);
- break;
- }
- case QShaderProgram::Fragment:{
- d->m_fragmentShaderCode = data.second;
- emit fragmentShaderCodeChanged(d->m_fragmentShaderCode);
- break;
- }
- case QShaderProgram::Geometry: {
- d->m_geometryShaderCode = data.second;
- emit geometryShaderCodeChanged(d->m_geometryShaderCode);
- break;
- }
- case QShaderProgram::Compute: {
- d->m_computeShaderCode = data.second;
- emit computeShaderCodeChanged(d->m_computeShaderCode);
- break;
- }
- case QShaderProgram::TessellationControl: {
- d->m_tessControlShaderCode = data.second;
- emit tessellationControlShaderCodeChanged(d->m_tessControlShaderCode);
- break;
- }
- case QShaderProgram::TessellationEvaluation: {
- d->m_tessEvalShaderCode = data.second;
- emit tessellationEvaluationShaderCodeChanged(d->m_tessEvalShaderCode);
- break;
- }
- }
-
- blockNotifications(blocked);
- }
- }
-}
-
/*!
\qmlproperty string ShaderProgramBuilder::shaderProgram
@@ -359,13 +353,13 @@ QUrl QShaderProgramBuilder::computeShaderGraph() const
}
/*!
- \qmlproperty string ShaderProgramBuilder:vertexShaderCode
+ \qmlproperty string ShaderProgramBuilder::vertexShaderCode
Holds the generated vertex shader code
\since 2.13
*/
/*!
- \property QShaderProgram:Builder:vertexShaderCode
+ \property QShaderProgramBuilder::vertexShaderCode
Holds the generate vertex shader code.
\since 5.13
@@ -377,13 +371,13 @@ QByteArray QShaderProgramBuilder::vertexShaderCode() const
}
/*!
- \qmlproperty string ShaderProgramBuilder:tessellationControlShaderCode
+ \qmlproperty string ShaderProgramBuilder::tessellationControlShaderCode
Holds the generated tessellation control shader code
\since 2.13
*/
/*!
- \property QShaderProgram:Builder:tessellationControlShaderCode
+ \property QShaderProgramBuilder::tessellationControlShaderCode
Holds the generate tessellation control shader code.
\since 5.13
@@ -395,13 +389,13 @@ QByteArray QShaderProgramBuilder::tessellationControlShaderCode() const
}
/*!
- \qmlproperty string ShaderProgramBuilder:tessellationEvaluationShaderCode
+ \qmlproperty string ShaderProgramBuilder::tessellationEvaluationShaderCode
Holds the generated tessellation evaluation shader code
\since 2.13
*/
/*!
- \property QShaderProgram:Builder:tessellationEvaluationShaderCode
+ \property QShaderProgramBuilder::tessellationEvaluationShaderCode
Holds the generate tessellation evaluation shader code.
\since 5.13
@@ -413,13 +407,13 @@ QByteArray QShaderProgramBuilder::tessellationEvaluationShaderCode() const
}
/*!
- \qmlproperty string ShaderProgramBuilder:geometryShaderCode
+ \qmlproperty string ShaderProgramBuilder::geometryShaderCode
Holds the generated geometry shader code
\since 2.13
*/
/*!
- \property QShaderProgram:Builder:geometryShaderCode
+ \property QShaderProgramBuilder::geometryShaderCode
Holds the generate geometry shader code.
\since 5.13
@@ -437,7 +431,7 @@ QByteArray QShaderProgramBuilder::geometryShaderCode() const
\since 2.13
*/
/*!
- \property QShaderProgram:Builder:fragmentShaderCode
+ \property QShaderProgramBuilder::fragmentShaderCode
Holds the generate fragment shader code.
\since 5.13
@@ -455,7 +449,7 @@ QByteArray QShaderProgramBuilder::fragmentShaderCode() const
\since 2.13
*/
/*!
- \property QShaderProgram:Builder:computeShaderCode
+ \property QShaderProgramBuilder::computeShaderCode
Holds the generate compute shader code.
\since 5.13
diff --git a/src/render/materialsystem/qshaderprogrambuilder.h b/src/render/materialsystem/qshaderprogrambuilder.h
index 184093730..5dc6b54ff 100644
--- a/src/render/materialsystem/qshaderprogrambuilder.h
+++ b/src/render/materialsystem/qshaderprogrambuilder.h
@@ -117,7 +117,6 @@ Q_SIGNALS:
protected:
explicit QShaderProgramBuilder(QShaderProgramBuilderPrivate &dd, Qt3DCore::QNode *parent = nullptr);
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
private:
Q_DECLARE_PRIVATE(QShaderProgramBuilder)
diff --git a/src/render/materialsystem/qshaderprogrambuilder_p.h b/src/render/materialsystem/qshaderprogrambuilder_p.h
index 2ac765a1d..22f8e6e58 100644
--- a/src/render/materialsystem/qshaderprogrambuilder_p.h
+++ b/src/render/materialsystem/qshaderprogrambuilder_p.h
@@ -52,6 +52,8 @@
//
#include <private/qnode_p.h>
+#include <Qt3DRender/private/qt3drender_global_p.h>
+#include <Qt3DRender/qshaderprogram.h>
#include <Qt3DRender/qshaderprogrambuilder.h>
#include <QtCore/qurl.h>
@@ -60,7 +62,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QShaderProgramBuilderPrivate : public Qt3DCore::QNodePrivate
+class Q_3DRENDERSHARED_PRIVATE_EXPORT QShaderProgramBuilderPrivate : public Qt3DCore::QNodePrivate
{
public:
QShaderProgramBuilderPrivate();
@@ -80,6 +82,8 @@ public:
QByteArray m_geometryShaderCode;
QByteArray m_fragmentShaderCode;
QByteArray m_computeShaderCode;
+
+ void setShaderCode(const QByteArray &code, QShaderProgram::ShaderType type);
};
struct QShaderProgramBuilderData
diff --git a/src/render/materialsystem/qtechnique.cpp b/src/render/materialsystem/qtechnique.cpp
index e5f109d46..a9b7ca82b 100644
--- a/src/render/materialsystem/qtechnique.cpp
+++ b/src/render/materialsystem/qtechnique.cpp
@@ -41,9 +41,6 @@
#include "qtechnique_p.h"
#include "qparameter.h"
#include "qgraphicsapifilter.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
QT_BEGIN_NAMESPACE
@@ -238,12 +235,7 @@ QTechnique::QTechnique(QTechniquePrivate &dd, QNode *parent)
/*! \internal */
void QTechniquePrivate::_q_graphicsApiFilterChanged()
{
- if (m_changeArbiter != nullptr) {
- auto change = QPropertyUpdatedChangePtr::create(m_id);
- change->setPropertyName("graphicsApiFilterData");
- change->setValue(QVariant::fromValue(QGraphicsApiFilterPrivate::get(const_cast<QGraphicsApiFilter *>(&m_graphicsApiFilter))->m_data));
- notifyObservers(change);
- }
+ update();
}
/*!
@@ -266,11 +258,7 @@ void QTechnique::addFilterKey(QFilterKey *filterKey)
if (!filterKey->parent())
filterKey->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), filterKey);
- change->setPropertyName("filterKeys");
- d->notifyObservers(change);
- }
+ d->updateNode(filterKey, "filterKeys", Qt3DCore::PropertyValueAdded);
}
}
@@ -281,11 +269,7 @@ void QTechnique::removeFilterKey(QFilterKey *filterKey)
{
Q_ASSERT(filterKey);
Q_D(QTechnique);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), filterKey);
- change->setPropertyName("filterKeys");
- d->notifyObservers(change);
- }
+ d->updateNode(filterKey, "filterKeys", Qt3DCore::PropertyValueRemoved);
d->m_filterKeys.removeOne(filterKey);
// Remove bookkeeping connection
d->unregisterDestructionHelper(filterKey);
@@ -321,11 +305,7 @@ void QTechnique::addParameter(QParameter *parameter)
if (!parameter->parent())
parameter->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueAdded);
}
}
@@ -336,11 +316,7 @@ void QTechnique::removeParameter(QParameter *parameter)
{
Q_ASSERT(parameter);
Q_D(QTechnique);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
- change->setPropertyName("parameter");
- d->notifyObservers(change);
- }
+ d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
d->m_parameters.removeOne(parameter);
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
@@ -366,11 +342,7 @@ void QTechnique::addRenderPass(QRenderPass *pass)
if (!pass->parent())
pass->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), pass);
- change->setPropertyName("pass");
- d->notifyObservers(change);
- }
+ d->updateNode(pass, "pass", Qt3DCore::PropertyValueAdded);
}
}
@@ -381,11 +353,7 @@ void QTechnique::removeRenderPass(QRenderPass *pass)
{
Q_ASSERT(pass);
Q_D(QTechnique);
- if (d->m_changeArbiter) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), pass);
- change->setPropertyName("pass");
- d->notifyObservers(change);
- }
+ d->updateNode(pass, "pass", Qt3DCore::PropertyValueAdded);
d->m_renderPasses.removeOne(pass);
// Remove bookkeeping connection
d->unregisterDestructionHelper(pass);
@@ -415,6 +383,12 @@ QGraphicsApiFilter *QTechnique::graphicsApiFilter()
return &d->m_graphicsApiFilter;
}
+const QGraphicsApiFilter *QTechnique::graphicsApiFilter() const
+{
+ Q_D(const QTechnique);
+ return &d->m_graphicsApiFilter;
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QTechnique::createNodeCreationChange() const
{
auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QTechniqueData>::create(this);
diff --git a/src/render/materialsystem/qtechnique.h b/src/render/materialsystem/qtechnique.h
index 7711cd67f..b9887b6a2 100644
--- a/src/render/materialsystem/qtechnique.h
+++ b/src/render/materialsystem/qtechnique.h
@@ -77,6 +77,7 @@ public:
QVector<QRenderPass *> renderPasses() const;
QGraphicsApiFilter *graphicsApiFilter();
+ const QGraphicsApiFilter *graphicsApiFilter() const;
protected:
explicit QTechnique(QTechniquePrivate &dd, Qt3DCore::QNode *parent = nullptr);
diff --git a/src/render/materialsystem/renderpass.cpp b/src/render/materialsystem/renderpass.cpp
index e0fadddd9..19e2a427e 100644
--- a/src/render/materialsystem/renderpass.cpp
+++ b/src/render/materialsystem/renderpass.cpp
@@ -48,9 +48,7 @@
#include <Qt3DRender/private/renderstates_p.h>
#include <Qt3DRender/private/renderstateset_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -77,58 +75,33 @@ void RenderPass::cleanup()
m_shaderUuid = Qt3DCore::QNodeId();
}
-void RenderPass::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void RenderPass::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QRenderPassData>>(change);
- const auto &data = typedChange->data;
- m_filterKeyList = data.filterKeyIds;
- m_parameterPack.setParameters(data.parameterIds);
- for (const auto &renderStateId : qAsConst(data.renderStateIds))
- addRenderState(renderStateId);
- m_shaderUuid = data.shaderId;
-}
-
-void RenderPass::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("filterKeys"))
- appendFilterKey(change->addedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("shaderProgram"))
- m_shaderUuid = change->addedNodeId();
- else if (change->propertyName() == QByteArrayLiteral("renderState"))
- addRenderState(change->addedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("parameter"))
- m_parameterPack.appendParameter(change->addedNodeId());
- break;
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QRenderPass *node = qobject_cast<const QRenderPass *>(frontEnd);
+ if (!node)
+ return;
+
+ if ((node->shaderProgram() && node->shaderProgram()->id() != m_shaderUuid) ||
+ (!node->shaderProgram() && !m_shaderUuid.isNull())) {
+ m_shaderUuid = node->shaderProgram() ? node->shaderProgram()->id() : QNodeId{};
}
- case PropertyUpdated: {
- const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("shaderProgram"))
- m_shaderUuid = change->value().value<Qt3DCore::QNodeId>();
- break;
- }
+ auto filterList = qIdsForNodes(node->filterKeys());
+ std::sort(std::begin(filterList), std::end(filterList));
+ if (m_filterKeyList != filterList)
+ m_filterKeyList = filterList;
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("filterKeys"))
- removeFilterKey(change->removedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("shaderProgram"))
- m_shaderUuid = QNodeId();
- else if (change->propertyName() == QByteArrayLiteral("renderState"))
- removeRenderState(change->removedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("parameter"))
- m_parameterPack.removeParameter(change->removedNodeId());
- break;
- }
+ auto parameters = qIdsForNodes(node->parameters());
+ std::sort(std::begin(parameters), std::end(parameters));
+ if (m_parameterPack.parameters() != parameters)
+ m_parameterPack.setParameters(parameters);
- default:
- break;
- }
+ auto renderStates = qIdsForNodes(node->renderStates());
+ std::sort(std::begin(renderStates), std::end(renderStates));
+ if (m_renderStates != renderStates)
+ m_renderStates = renderStates;
- BackendNode::sceneChangeEvent(e);
markDirty(AbstractRenderer::AllDirty);
}
diff --git a/src/render/materialsystem/renderpass_p.h b/src/render/materialsystem/renderpass_p.h
index 1ca02b1ad..314386ad1 100644
--- a/src/render/materialsystem/renderpass_p.h
+++ b/src/render/materialsystem/renderpass_p.h
@@ -79,7 +79,7 @@ public:
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
Qt3DCore::QNodeId shaderProgram() const;
QVector<Qt3DCore::QNodeId> filterKeys() const;
@@ -95,8 +95,6 @@ private:
void addRenderState(Qt3DCore::QNodeId renderStateId);
void removeRenderState(Qt3DCore::QNodeId renderStateId);
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
Qt3DCore::QNodeId m_shaderUuid;
QVector<Qt3DCore::QNodeId> m_filterKeyList;
ParameterPack m_parameterPack;
diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp
index d42b0dda7..58709b37e 100644
--- a/src/render/materialsystem/shader.cpp
+++ b/src/render/materialsystem/shader.cpp
@@ -64,6 +64,7 @@ Shader::Shader()
, m_dna(0)
, m_graphicsContext(nullptr)
, m_status(QShaderProgram::NotReady)
+ , m_requiresFrontendSync(false)
{
m_shaderCode.resize(static_cast<int>(QShaderProgram::Compute) + 1);
}
@@ -101,23 +102,24 @@ void Shader::cleanup()
m_status = QShaderProgram::NotReady;
}
-void Shader::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void Shader::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QShaderProgramData>>(change);
- const auto &data = typedChange->data;
-
- for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i)
- m_shaderCode[i].clear();
-
- m_shaderCode[QShaderProgram::Vertex] = data.vertexShaderCode;
- m_shaderCode[QShaderProgram::TessellationControl] = data.tessellationControlShaderCode;
- m_shaderCode[QShaderProgram::TessellationEvaluation] = data.tessellationEvaluationShaderCode;
- m_shaderCode[QShaderProgram::Geometry] = data.geometryShaderCode;
- m_shaderCode[QShaderProgram::Fragment] = data.fragmentShaderCode;
- m_shaderCode[QShaderProgram::Compute] = data.computeShaderCode;
- m_isLoaded = false;
- updateDNA();
- markDirty(AbstractRenderer::ShadersDirty);
+ const QShaderProgram *node = qobject_cast<const QShaderProgram *>(frontEnd);
+ if (!node)
+ return;
+
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (firstTime)
+ for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i)
+ m_shaderCode[i].clear();
+
+ for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i) {
+ const QShaderProgram::ShaderType shaderType = static_cast<QShaderProgram::ShaderType>(i);
+ const QByteArray code = node->shaderCode(shaderType);
+ if (code != m_shaderCode.value(shaderType))
+ setShaderCode(shaderType, code);
+ }
}
void Shader::setGraphicsContext(GraphicsContext *context)
@@ -169,34 +171,12 @@ void Shader::setShaderCode(QShaderProgram::ShaderType type, const QByteArray &co
m_shaderCode[type] = code;
m_isLoaded = false;
- setStatus(QShaderProgram::NotReady);
+ m_status = QShaderProgram::NotReady;
updateDNA();
+ m_requiresFrontendSync = true;
markDirty(AbstractRenderer::ShadersDirty);
}
-void Shader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = e.staticCast<QPropertyUpdatedChange>();
- QVariant propertyValue = propertyChange->value();
-
- if (propertyChange->propertyName() == QByteArrayLiteral("vertexShaderCode"))
- setShaderCode(QShaderProgram::Vertex, propertyValue.toByteArray());
- else if (propertyChange->propertyName() == QByteArrayLiteral("fragmentShaderCode"))
- setShaderCode(QShaderProgram::Fragment, propertyValue.toByteArray());
- else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationControlShaderCode"))
- setShaderCode(QShaderProgram::TessellationControl, propertyValue.toByteArray());
- else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationEvaluationShaderCode"))
- setShaderCode(QShaderProgram::TessellationEvaluation, propertyValue.toByteArray());
- else if (propertyChange->propertyName() == QByteArrayLiteral("geometryShaderCode"))
- setShaderCode(QShaderProgram::Geometry, propertyValue.toByteArray());
- else if (propertyChange->propertyName() == QByteArrayLiteral("computeShaderCode"))
- setShaderCode(QShaderProgram::Compute, propertyValue.toByteArray());
- }
-
- BackendNode::sceneChangeEvent(e);
-}
-
QHash<QString, ShaderUniform> Shader::activeUniformsForUniformBlock(int blockIndex) const
{
return m_uniformBlockIndexToShaderUniforms.value(blockIndex);
@@ -259,20 +239,13 @@ ShaderStorageBlock Shader::storageBlockForBlockName(const QString &blockName)
return ShaderStorageBlock();
}
-// To be called from a worker thread
-void Shader::submitPendingNotifications()
-{
- const QVector<Qt3DCore::QPropertyUpdatedChangePtr> notifications = std::move(m_pendingNotifications);
- for (const Qt3DCore::QPropertyUpdatedChangePtr &notification : notifications)
- notifyObservers(notification);
-}
-
void Shader::prepareUniforms(ShaderParameterPack &pack)
{
const PackUniformHash &values = pack.uniforms();
auto it = values.cbegin();
const auto end = values.cend();
+
while (it != end) {
// Find if there's a uniform with the same name id
for (const ShaderUniform &uniform : qAsConst(m_uniforms)) {
@@ -434,32 +407,21 @@ void Shader::initializeFromReference(const Shader &other)
m_shaderStorageBlockNames = other.m_shaderStorageBlockNames;
m_shaderStorageBlocks = other.m_shaderStorageBlocks;
m_isLoaded = other.m_isLoaded;
- setStatus(other.status());
- setLog(other.log());
+ m_status = other.m_status;
+ m_log = other.m_log;
+ m_requiresFrontendSync = true;
}
void Shader::setLog(const QString &log)
{
- if (log != m_log) {
- m_log = log;
- Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("log");
- e->setValue(QVariant::fromValue(m_log));
- m_pendingNotifications.push_back(e);
- }
+ m_log = log;
+ m_requiresFrontendSync = true;
}
void Shader::setStatus(QShaderProgram::Status status)
{
- if (status != m_status) {
- m_status = status;
- Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("status");
- e->setValue(QVariant::fromValue(m_status));
- m_pendingNotifications.push_back(e);
- }
+ m_status = status;
+ m_requiresFrontendSync = true;
}
} // namespace Render
diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h
index 9eb24904c..fe1a401d9 100644
--- a/src/render/materialsystem/shader_p.h
+++ b/src/render/materialsystem/shader_p.h
@@ -99,7 +99,7 @@ public:
QVector<QByteArray> shaderCode() const;
void setShaderCode(QShaderProgram::ShaderType type, const QByteArray &code);
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
bool isLoaded() const { QMutexLocker lock(&m_mutex); return m_isLoaded; }
void setLoaded(bool loaded) { QMutexLocker lock(&m_mutex); m_isLoaded = loaded; }
ProgramDNA dna() const Q_DECL_NOTHROW { return m_dna; }
@@ -122,12 +122,10 @@ public:
inline QString log() const { return m_log; }
inline QShaderProgram::Status status() const { return m_status; }
- void submitPendingNotifications();
- inline bool hasPendingNotifications() const { return !m_pendingNotifications.empty(); }
+ inline bool requiresFrontendSync() const { return m_requiresFrontendSync; }
+ inline void unsetRequiresFrontendSync() { m_requiresFrontendSync = false; }
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
QVector<QString> m_uniformsNames;
QVector<int> m_uniformsNamesIds;
QVector<ShaderUniform> m_uniforms;
@@ -157,8 +155,7 @@ private:
QMetaObject::Connection m_contextConnection;
QString m_log;
QShaderProgram::Status m_status;
-
- QVector<Qt3DCore::QPropertyUpdatedChangePtr> m_pendingNotifications;
+ bool m_requiresFrontendSync;
void updateDNA();
diff --git a/src/render/materialsystem/shaderbuilder.cpp b/src/render/materialsystem/shaderbuilder.cpp
index c1ec7f75a..23f1400c9 100644
--- a/src/render/materialsystem/shaderbuilder.cpp
+++ b/src/render/materialsystem/shaderbuilder.cpp
@@ -39,6 +39,8 @@
#include "shaderbuilder_p.h"
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
#include <Qt3DRender/private/qshaderprogrambuilder_p.h>
#include <Qt3DRender/qshaderprogram.h>
#include <Qt3DRender/private/qshaderprogram_p.h>
@@ -113,31 +115,6 @@ using namespace Qt3DCore;
namespace Qt3DRender {
namespace Render {
-
-namespace {
-
-QShaderProgram::ShaderType toQShaderProgramType(ShaderBuilder::ShaderType type)
-{
- switch (type) {
- case ShaderBuilder::ShaderType::Vertex:
- return QShaderProgram::Vertex;
- case ShaderBuilder::ShaderType::TessellationControl:
- return QShaderProgram::TessellationControl;
- case ShaderBuilder::ShaderType::TessellationEvaluation:
- return QShaderProgram::TessellationEvaluation;
- case ShaderBuilder::ShaderType::Geometry:
- return QShaderProgram::Geometry;
- case ShaderBuilder::ShaderType::Fragment:
- return QShaderProgram::Fragment;
- case ShaderBuilder::ShaderType::Compute:
- return QShaderProgram::Compute;
- default:
- Q_UNREACHABLE();
- }
-}
-
-} // anonymous
-
QString ShaderBuilder::getPrototypesFile()
{
return qt3dGlobalShaderPrototypes->prototypesFile();
@@ -168,6 +145,7 @@ void ShaderBuilder::cleanup()
m_enabledLayers.clear();
m_graphs.clear();
m_dirtyTypes.clear();
+ m_pendingUpdates.clear();
QBackendNode::setEnabled(false);
}
@@ -189,7 +167,7 @@ void ShaderBuilder::setEnabledLayers(const QStringList &layers)
m_enabledLayers = layers;
- for (QHash<ShaderType, QUrl>::const_iterator it = m_graphs.cbegin(); it != m_graphs.cend(); ++it) {
+ for (auto it = m_graphs.cbegin(); it != m_graphs.cend(); ++it) {
if (!it.value().isEmpty())
m_dirtyTypes.insert(it.key());
}
@@ -206,18 +184,18 @@ void ShaderBuilder::setGraphicsApi(const GraphicsApiFilterData &graphicsApi)
return;
m_graphicsApi = graphicsApi;
- for (QHash<ShaderType, QUrl>::const_iterator it = m_graphs.cbegin(); it != m_graphs.cend(); ++it) {
+ for (auto it = m_graphs.cbegin(); it != m_graphs.cend(); ++it) {
if (!it.value().isEmpty())
m_dirtyTypes.insert(it.key());
}
}
-QUrl ShaderBuilder::shaderGraph(ShaderBuilder::ShaderType type) const
+QUrl ShaderBuilder::shaderGraph(QShaderProgram::ShaderType type) const
{
return m_graphs.value(type);
}
-void ShaderBuilder::setShaderGraph(ShaderBuilder::ShaderType type, const QUrl &url)
+void ShaderBuilder::setShaderGraph(QShaderProgram::ShaderType type, const QUrl &url)
{
if (url != m_graphs.value(type)) {
m_graphs.insert(type, url);
@@ -225,17 +203,17 @@ void ShaderBuilder::setShaderGraph(ShaderBuilder::ShaderType type, const QUrl &u
}
}
-QByteArray ShaderBuilder::shaderCode(ShaderBuilder::ShaderType type) const
+QByteArray ShaderBuilder::shaderCode(QShaderProgram::ShaderType type) const
{
return m_codes.value(type);
}
-bool ShaderBuilder::isShaderCodeDirty(ShaderBuilder::ShaderType type) const
+bool ShaderBuilder::isShaderCodeDirty(QShaderProgram::ShaderType type) const
{
return m_dirtyTypes.contains(type);
}
-void ShaderBuilder::generateCode(ShaderBuilder::ShaderType type)
+void ShaderBuilder::generateCode(QShaderProgram::ShaderType type)
{
const auto graphPath = QUrlHelper::urlToLocalFileOrQrc(shaderGraph(type));
QFile file(graphPath);
@@ -271,55 +249,51 @@ void ShaderBuilder::generateCode(ShaderBuilder::ShaderType type)
m_codes.insert(type, QShaderProgramPrivate::deincludify(code, graphPath + QStringLiteral(".glsl")));
m_dirtyTypes.remove(type);
- // Send notification to the frontend
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- propertyChange->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- propertyChange->setPropertyName("generatedShaderCode");
- propertyChange->setValue(QVariant::fromValue(qMakePair(int(toQShaderProgramType(type)), m_codes.value(type))));
- notifyObservers(propertyChange);
+ m_pendingUpdates.push_back({ peerId(),
+ type,
+ m_codes.value(type) });
}
-void ShaderBuilder::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void ShaderBuilder::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- if (e->type() == PropertyUpdated) {
- QPropertyUpdatedChangePtr propertyChange = e.staticCast<QPropertyUpdatedChange>();
- QVariant propertyValue = propertyChange->value();
-
- if (propertyChange->propertyName() == QByteArrayLiteral("shaderProgram"))
- m_shaderProgramId = propertyValue.value<Qt3DCore::QNodeId>();
- else if (propertyChange->propertyName() == QByteArrayLiteral("enabledLayers"))
- setEnabledLayers(propertyValue.toStringList());
- else if (propertyChange->propertyName() == QByteArrayLiteral("vertexShaderGraph"))
- setShaderGraph(Vertex, propertyValue.toUrl());
- else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationControlShaderGraph"))
- setShaderGraph(TessellationControl, propertyValue.toUrl());
- else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationEvaluationShaderGraph"))
- setShaderGraph(TessellationEvaluation, propertyValue.toUrl());
- else if (propertyChange->propertyName() == QByteArrayLiteral("geometryShaderGraph"))
- setShaderGraph(Geometry, propertyValue.toUrl());
- else if (propertyChange->propertyName() == QByteArrayLiteral("fragmentShaderGraph"))
- setShaderGraph(Fragment, propertyValue.toUrl());
- else if (propertyChange->propertyName() == QByteArrayLiteral("computeShaderGraph"))
- setShaderGraph(Compute, propertyValue.toUrl());
+ const QShaderProgramBuilder *node = qobject_cast<const QShaderProgramBuilder *>(frontEnd);
+ if (!node)
+ return;
+
+ const bool oldEnabled = isEnabled();
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ if (oldEnabled != isEnabled()) {
markDirty(AbstractRenderer::ShadersDirty);
}
- BackendNode::sceneChangeEvent(e);
-}
-void ShaderBuilder::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QShaderProgramBuilderData>>(change);
- const auto &data = typedChange->data;
-
- m_shaderProgramId = data.shaderProgramId;
- m_enabledLayers = data.enabledLayers;
- setShaderGraph(Vertex, data.vertexShaderGraph);
- setShaderGraph(TessellationControl, data.tessellationControlShaderGraph);
- setShaderGraph(TessellationEvaluation, data.tessellationEvaluationShaderGraph);
- setShaderGraph(Geometry, data.geometryShaderGraph);
- setShaderGraph(Fragment, data.fragmentShaderGraph);
- setShaderGraph(Compute, data.computeShaderGraph);
+ const Qt3DCore::QNodeId shaderProgramId = Qt3DCore::qIdForNode(node->shaderProgram());
+ if (shaderProgramId != m_shaderProgramId) {
+ m_shaderProgramId = shaderProgramId;
+ markDirty(AbstractRenderer::ShadersDirty);
+ }
+
+ if (node->enabledLayers() != m_enabledLayers) {
+ setEnabledLayers(node->enabledLayers());
+ markDirty(AbstractRenderer::ShadersDirty);
+ }
+
+ static const std::pair<QShaderProgram::ShaderType, QUrl (QShaderProgramBuilder::*)() const> shaderTypesToGetters[] = {
+ {QShaderProgram::Vertex, &QShaderProgramBuilder::vertexShaderGraph},
+ {QShaderProgram::TessellationControl, &QShaderProgramBuilder::tessellationControlShaderGraph},
+ {QShaderProgram::TessellationEvaluation, &QShaderProgramBuilder::tessellationEvaluationShaderGraph},
+ {QShaderProgram::Geometry, &QShaderProgramBuilder::geometryShaderGraph},
+ {QShaderProgram::Fragment, &QShaderProgramBuilder::fragmentShaderGraph},
+ {QShaderProgram::Compute, &QShaderProgramBuilder::computeShaderGraph},
+ };
+
+ for (auto it = std::cbegin(shaderTypesToGetters), end = std::cend(shaderTypesToGetters); it != end; ++it) {
+ const QUrl url = (node->*(it->second))();
+ if (url != m_graphs.value(it->first)) {
+ setShaderGraph(it->first, url);
+ markDirty(AbstractRenderer::ShadersDirty);
+ }
+ }
}
} // namespace Render
diff --git a/src/render/materialsystem/shaderbuilder_p.h b/src/render/materialsystem/shaderbuilder_p.h
index 00c4e1c28..0a799afaa 100644
--- a/src/render/materialsystem/shaderbuilder_p.h
+++ b/src/render/materialsystem/shaderbuilder_p.h
@@ -51,9 +51,9 @@
// We mean it.
//
+#include <Qt3DRender/qshaderprogram.h>
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/qgraphicsapifilter_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -61,18 +61,16 @@ namespace Qt3DRender {
namespace Render {
+struct ShaderBuilderUpdate
+{
+ Qt3DCore::QNodeId builderId;
+ Qt3DRender::QShaderProgram::ShaderType shaderType;
+ QByteArray shaderCode;
+};
+
class Q_3DRENDERSHARED_PRIVATE_EXPORT ShaderBuilder : public BackendNode
{
public:
- enum ShaderType {
- Vertex = 0,
- TessellationControl,
- TessellationEvaluation,
- Geometry,
- Fragment,
- Compute
- };
-
static QString getPrototypesFile();
static void setPrototypesFile(const QString &file);
static QStringList getPrototypeNames();
@@ -87,26 +85,28 @@ public:
GraphicsApiFilterData graphicsApi() const;
void setGraphicsApi(const GraphicsApiFilterData &graphicsApi);
- QUrl shaderGraph(ShaderType type) const;
- void setShaderGraph(ShaderType type, const QUrl &url);
+ QUrl shaderGraph(QShaderProgram::ShaderType type) const;
+ void setShaderGraph(QShaderProgram::ShaderType type, const QUrl &url);
+
+ QByteArray shaderCode(QShaderProgram::ShaderType type) const;
+ bool isShaderCodeDirty(QShaderProgram::ShaderType type) const;
- QByteArray shaderCode(ShaderType type) const;
- bool isShaderCodeDirty(ShaderType type) const;
+ void generateCode(QShaderProgram::ShaderType type);
- void generateCode(ShaderType type);
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ QVector<ShaderBuilderUpdate> takePendingUpdates() { return std::move(m_pendingUpdates); }
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
void setEnabledLayers(const QStringList &layers);
GraphicsApiFilterData m_graphicsApi;
Qt3DCore::QNodeId m_shaderProgramId;
QStringList m_enabledLayers;
- QHash<ShaderType, QUrl> m_graphs;
- QHash<ShaderType, QByteArray> m_codes;
- QSet<ShaderType> m_dirtyTypes;
+ QHash<QShaderProgram::ShaderType, QUrl> m_graphs;
+ QHash<QShaderProgram::ShaderType, QByteArray> m_codes;
+ QSet<QShaderProgram::ShaderType> m_dirtyTypes;
+ QVector<ShaderBuilderUpdate> m_pendingUpdates;
};
} // namespace Render
diff --git a/src/render/materialsystem/shaderdata.cpp b/src/render/materialsystem/shaderdata.cpp
index 130333898..34d4641e9 100644
--- a/src/render/materialsystem/shaderdata.cpp
+++ b/src/render/materialsystem/shaderdata.cpp
@@ -64,8 +64,6 @@ const int qNodeIdTypeId = qMetaTypeId<Qt3DCore::QNodeId>();
}
-QVector<Qt3DCore::QNodeId> ShaderData::m_updatedShaderData;
-
ShaderData::ShaderData()
: m_managers(nullptr)
{
@@ -80,51 +78,82 @@ void ShaderData::setManagers(NodeManagers *managers)
m_managers = managers;
}
-void ShaderData::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
+void ShaderData::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QShaderDataData>>(change);
- const QShaderDataData &data = typedChange->data;
-
- m_propertyReader = data.propertyReader;
-
- for (const QPair<QByteArray, QVariant> &entry : data.properties) {
- if (entry.first == QByteArrayLiteral("data") ||
- entry.first == QByteArrayLiteral("childNodes")) // We don't handle default Node properties
- continue;
- const QVariant &propertyValue = entry.second;
- const QString propertyName = QString::fromLatin1(entry.first);
-
- m_originalProperties.insert(propertyName, propertyValue);
-
- // We check if the property is a QNodeId or QVector<QNodeId> so that we can
- // check nested QShaderData for update
- if (propertyValue.userType() == qNodeIdTypeId) {
- m_nestedShaderDataProperties.insert(propertyName, propertyValue);
- } else if (propertyValue.userType() == QMetaType::QVariantList) {
- QVariantList list = propertyValue.value<QVariantList>();
- if (list.count() > 0 && list.at(0).userType() == qNodeIdTypeId)
- m_nestedShaderDataProperties.insert(propertyName, propertyValue);
- }
- }
+ const QShaderData *node = qobject_cast<const QShaderData *>(frontEnd);
+ if (!node)
+ return;
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (firstTime) {
+ m_propertyReader = node->propertyReader();
+
+ const QMetaObject *metaObj = node->metaObject();
+ const int propertyOffset = QShaderData::staticMetaObject.propertyOffset();
+ const int propertyCount = metaObj->propertyCount();
+ // Dynamic properties names
+ const auto dynamicPropertyNames = node->dynamicPropertyNames();
- // We look for transformed properties once the complete hash of
- // originalProperties is available
- QHash<QString, QVariant>::iterator it = m_originalProperties.begin();
- const QHash<QString, QVariant>::iterator end = m_originalProperties.end();
-
- while (it != end) {
- if (it.value().type() == QVariant::Vector3D) {
- // if there is a matching QShaderData::TransformType propertyTransformed
- QVariant value = m_originalProperties.value(it.key() + QLatin1String("Transformed"));
- // if that's the case, we apply a space transformation to the property
- if (value.isValid() && value.type() == QVariant::Int)
- m_transformedProperties.insert(it.key(), static_cast<TransformType>(value.toInt()));
+ QVector<QString> propertyNames;
+ propertyNames.reserve(propertyCount - propertyOffset + dynamicPropertyNames.size());
+
+ // Statiically defined properties
+ for (int i = propertyOffset; i < propertyCount; ++i) {
+ const QMetaProperty pro = metaObj->property(i);
+ if (pro.isWritable())
+ propertyNames.push_back(QString::fromLatin1(pro.name()));
+ }
+ // Dynamic properties
+ for (const QByteArray &propertyName : dynamicPropertyNames)
+ propertyNames.push_back(QString::fromLatin1(propertyName));
+
+ for (const QString &propertyName : propertyNames) {
+ if (propertyName == QStringLiteral("data") ||
+ propertyName == QStringLiteral("childNodes")) // We don't handle default Node properties
+ continue;
+
+ const QVariant &propertyValue = m_propertyReader->readProperty(node->property(propertyName.toLatin1()));
+ bool isNested = false;
+ bool isTransformed = false;
+
+ // We check if the property is a QNodeId
+ isNested = (propertyValue.userType() == qNodeIdTypeId);
+ // We check if QVector<QNodeId>
+ if (propertyValue.userType() == QMetaType::QVariantList) {
+ QVariantList list = propertyValue.value<QVariantList>();
+ if (list.count() > 0 && list.at(0).userType() == qNodeIdTypeId)
+ isNested = true;
+ }
+
+ // We check if property is a Transformed property
+ if (propertyValue.userType() == QVariant::Vector3D) {
+ // if there is a matching QShaderData::TransformType propertyTransformed
+ isTransformed = propertyNames.contains(propertyName + QLatin1String("Transformed"));
+ }
+ m_originalProperties.insert(propertyName, { propertyValue, isNested, isTransformed });
+ }
+ BackendNode::markDirty(AbstractRenderer::ParameterDirty);
+ } else {
+ // Updates
+ if (!m_propertyReader.isNull()) {
+ auto it = m_originalProperties.begin();
+ const auto end = m_originalProperties.end();
+
+ while (it != end) {
+ const QVariant newValue = m_propertyReader->readProperty(node->property(it.key().toLatin1()));
+ PropertyValue &propValue = it.value();
+ if (propValue.value != newValue) {
+ // Note we aren't notified about nested QShaderData in this call
+ // only scalar / vec properties
+ propValue.value = newValue;
+ BackendNode::markDirty(AbstractRenderer::ParameterDirty);
+ }
+ ++it;
+ }
}
- ++it;
}
}
-
ShaderData *ShaderData::lookupResource(NodeManagers *managers, QNodeId id)
{
return managers->shaderDataManager()->lookupResource(id);
@@ -135,120 +164,62 @@ ShaderData *ShaderData::lookupResource(QNodeId id)
return ShaderData::lookupResource(m_managers, id);
}
-// Call by cleanup job (single thread)
-void ShaderData::clearUpdatedProperties()
-{
- // DISABLED: Is only useful when building UBO from a ShaderData, which is disable since 5.7
- // const QHash<QString, QVariant>::const_iterator end = m_nestedShaderDataProperties.end();
- // QHash<QString, QVariant>::const_iterator it = m_nestedShaderDataProperties.begin();
-
- // while (it != end) {
- // if (it.value().userType() == QMetaType::QVariantList) {
- // const auto values = it.value().value<QVariantList>();
- // for (const QVariant &v : values) {
- // ShaderData *nested = lookupResource(v.value<QNodeId>());
- // if (nested != nullptr)
- // nested->clearUpdatedProperties();
- // }
- // } else {
- // ShaderData *nested = lookupResource(it.value().value<QNodeId>());
- // if (nested != nullptr)
- // nested->clearUpdatedProperties();
- // }
- // ++it;
- // }
-}
-
void ShaderData::cleanup(NodeManagers *managers)
{
Q_UNUSED(managers)
- // DISABLED: Is only useful when building UBO from a ShaderData, which is disable since 5.7
- // for (Qt3DCore::QNodeId id : qAsConst(m_updatedShaderData)) {
- // ShaderData *shaderData = ShaderData::lookupResource(managers, id);
- // if (shaderData)
- // shaderData->clearUpdatedProperties();
- // }
- m_updatedShaderData.clear();
}
+// RenderCommand updater jobs
QVariant ShaderData::getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix)
{
// Note protecting m_worldMatrix at this point as we assume all world updates
// have been performed when reaching this point
- auto it = m_transformedProperties.find(name);
- if (it != m_transformedProperties.end()) {
- const TransformType transformType = it.value();
- switch (transformType) {
- case ModelToEye:
- return QVariant::fromValue(viewMatrix * m_worldMatrix * Vector3D(m_originalProperties.value(name).value<QVector3D>()));
- case ModelToWorld:
- return QVariant::fromValue(m_worldMatrix * Vector3D(m_originalProperties.value(it.key()).value<QVector3D>()));
- case ModelToWorldDirection:
- return QVariant::fromValue(Vector3D(m_worldMatrix * Vector4D(m_originalProperties.value(it.key()).value<QVector3D>(), 0.0f)));
- case NoTransform:
- break;
+ const auto it = m_originalProperties.constFind(name);
+ if (it != m_originalProperties.constEnd()) {
+ const PropertyValue &propertyValue = it.value();
+ if (propertyValue.isTransformed) {
+ const auto transformedIt = m_originalProperties.constFind(name + QLatin1String("Transformed"));
+ if (transformedIt != m_originalProperties.constEnd()) {
+ const PropertyValue &transformedValue = transformedIt.value();
+ const TransformType transformType = static_cast<TransformType>(transformedValue.value.toInt());
+ switch (transformType) {
+ case ModelToEye:
+ return QVariant::fromValue(viewMatrix * m_worldMatrix * Vector3D(propertyValue.value.value<QVector3D>()));
+ case ModelToWorld:
+ return QVariant::fromValue(m_worldMatrix * Vector3D(propertyValue.value.value<QVector3D>()));
+ case ModelToWorldDirection:
+ return QVariant::fromValue(Vector3D(m_worldMatrix * Vector4D(propertyValue.value.value<QVector3D>(), 0.0f)));
+ case NoTransform:
+ break;
+ }
+ }
}
+ return propertyValue.value;
}
return QVariant();
}
-// Called by FramePreparationJob or by RenderView when dealing with lights
-void ShaderData::updateWorldTransform(const Matrix4x4 &worldMatrix)
-{
- QMutexLocker lock(&m_mutex);
- if (m_worldMatrix != worldMatrix) {
- m_worldMatrix = worldMatrix;
- }
-}
-
-// This will add the ShaderData to be cleared from updates at the end of the frame
-// by the cleanup job
-// Called by renderview jobs (several concurrent threads)
-void ShaderData::markDirty()
-{
- QMutexLocker lock(&m_mutex);
- if (!ShaderData::m_updatedShaderData.contains(peerId()))
- ShaderData::m_updatedShaderData.append(peerId());
-}
-
-/*!
- \internal
- Lookup if the current ShaderData or a nested ShaderData has updated properties.
- UpdateProperties contains either the value of the propertie of a QNodeId if it's another ShaderData.
- Transformed properties are updated for all of ShaderData that have ones at the point.
-
- \note This needs to be performed for every top level ShaderData every time it is used.
- As we don't know if the transformed properties use the same viewMatrix for all RenderViews.
- */
-
+// Unit tests only
ShaderData::TransformType ShaderData::propertyTransformType(const QString &name) const
{
- return m_transformedProperties.value(name, TransformType::NoTransform);
+ const auto it = m_originalProperties.constFind(name);
+ if (it != m_originalProperties.constEnd()) {
+ const PropertyValue &propertyValue = it.value();
+ if (propertyValue.isTransformed) {
+ auto transformedIt = m_originalProperties.constFind(name + QLatin1String("Transformed"));
+ if (transformedIt != m_originalProperties.end())
+ return static_cast<TransformType>(transformedIt.value().value.toInt());
+ }
+ }
+ return NoTransform;
}
-void ShaderData::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+// Called by FramePreparationJob or by RenderView when dealing with lights
+void ShaderData::updateWorldTransform(const Matrix4x4 &worldMatrix)
{
- if (!m_propertyReader.isNull() && e->type() == PropertyUpdated) {
- QString propertyName;
- QVariant propertyValue;
-
- if (auto propertyChange = qSharedPointerDynamicCast<QPropertyUpdatedChange>(e)) {
- propertyName = QString::fromLatin1(propertyChange->propertyName());
- propertyValue = m_propertyReader->readProperty(propertyChange->value());
- } else if (auto propertyChange = qSharedPointerDynamicCast<QDynamicPropertyUpdatedChange>(e)) {
- propertyName = QString::fromLatin1(propertyChange->propertyName());
- propertyValue = m_propertyReader->readProperty(propertyChange->value());
- } else {
- Q_UNREACHABLE();
- }
-
- // Note we aren't notified about nested QShaderData in this call
- // only scalar / vec properties
- m_originalProperties.insert(propertyName, propertyValue);
- BackendNode::markDirty(AbstractRenderer::ParameterDirty);
+ if (m_worldMatrix != worldMatrix) {
+ m_worldMatrix = worldMatrix;
}
-
- BackendNode::sceneChangeEvent(e);
}
RenderShaderDataFunctor::RenderShaderDataFunctor(AbstractRenderer *renderer, NodeManagers *managers)
diff --git a/src/render/materialsystem/shaderdata_p.h b/src/render/materialsystem/shaderdata_p.h
index f9c3ecc79..c9cc22939 100644
--- a/src/render/materialsystem/shaderdata_p.h
+++ b/src/render/materialsystem/shaderdata_p.h
@@ -76,49 +76,42 @@ public:
ModelToWorld,
ModelToWorldDirection
};
+ struct PropertyValue {
+ QVariant value;
+ bool isNested;
+ bool isTransformed;
+ };
ShaderData();
~ShaderData();
- QHash<QString, QVariant> properties() const { return m_originalProperties; }
+ QHash<QString, PropertyValue> properties() const { return m_originalProperties; }
// Called by FramePreparationJob
void updateWorldTransform(const Matrix4x4 &worldMatrix);
- // Call by RenderViewJob
- void markDirty();
+ QVariant getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix);
+ // Unit tests purposes only
TransformType propertyTransformType(const QString &name) const;
- QVariant getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix);
// Called by FrameCleanupJob
static void cleanup(NodeManagers *managers);
void setManagers(NodeManagers *managers);
-protected:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) override;
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+protected:
PropertyReaderInterfacePtr m_propertyReader;
- // 1 to 1 match with frontend properties, modified only by sceneChangeEvent
- QHash<QString, QVariant> m_originalProperties;
-
- // Contains properties thar are of type ShaderData
- QHash<QString, QVariant> m_nestedShaderDataProperties;
-
- // Contains property that are defined like: postionTransformed: ModelToEye
- QHash<QString, TransformType> m_transformedProperties;
+ // 1 to 1 match with frontend properties
+ QHash<QString, PropertyValue> m_originalProperties;
- QMutex m_mutex;
- static QVector<Qt3DCore::QNodeId> m_updatedShaderData;
Matrix4x4 m_worldMatrix;
- Matrix4x4 m_viewMatrix;
NodeManagers *m_managers;
- void clearUpdatedProperties();
static ShaderData *lookupResource(NodeManagers *managers, Qt3DCore::QNodeId id);
ShaderData *lookupResource(Qt3DCore::QNodeId id);
diff --git a/src/render/materialsystem/shaderimage.cpp b/src/render/materialsystem/shaderimage.cpp
new file mode 100644
index 000000000..65a4cf761
--- /dev/null
+++ b/src/render/materialsystem/shaderimage.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "shaderimage_p.h"
+#include <Qt3DRender/private/qshaderimage_p.h>
+#include <Qt3DRender/qabstracttexture.h>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+ShaderImage::ShaderImage()
+ : BackendNode(BackendNode::ReadOnly)
+ , m_textureId()
+ , m_mipLevel(0)
+ , m_layer(0)
+ , m_layered(false)
+ , m_access(QShaderImage::ReadWrite)
+ , m_format(QShaderImage::NoFormat)
+{
+}
+
+void ShaderImage::cleanup()
+{
+ QBackendNode::setEnabled(false);
+ m_textureId = Qt3DCore::QNodeId();
+ m_mipLevel = 0;
+ m_layer = 0;
+ m_layered = false;
+ m_access = QShaderImage::ReadWrite;
+ m_format = QShaderImage::NoFormat;
+}
+
+void ShaderImage::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
+{
+ const QShaderImage *node = qobject_cast<const QShaderImage *>(frontEnd);
+ if (!node)
+ return;
+
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ const Qt3DCore::QNodeId textureNodeId = Qt3DCore::qIdForNode(node->texture());
+ if (textureNodeId != m_textureId) {
+ m_textureId = textureNodeId;
+ markDirty(AbstractRenderer::ParameterDirty);
+ }
+
+ if (node->mipLevel() != m_mipLevel) {
+ m_mipLevel = node->mipLevel();
+ markDirty(AbstractRenderer::ParameterDirty);
+ }
+
+ if (node->layer() != m_layer) {
+ m_layer = node->layer();
+ markDirty(AbstractRenderer::ParameterDirty);
+ }
+
+ if (node->layered() != m_layered) {
+ m_layered = node->layered();
+ markDirty(AbstractRenderer::ParameterDirty);
+ }
+
+ if (node->format() != m_format) {
+ m_format = node->format();
+ markDirty(AbstractRenderer::ParameterDirty);
+ }
+
+ if (node->access() != m_access) {
+ m_access = node->access();
+ markDirty(AbstractRenderer::ParameterDirty);
+ }
+
+}
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/renderers/opengl/renderer/commandthread_p.h b/src/render/materialsystem/shaderimage_p.h
index 0508675c4..1a1294a21 100644
--- a/src/render/renderers/opengl/renderer/commandthread_p.h
+++ b/src/render/materialsystem/shaderimage_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QT3DRENDER_RENDER_COMMANDTHREAD_P_H
-#define QT3DRENDER_RENDER_COMMANDTHREAD_P_H
+#ifndef QT3DRENDER_RENDER_SHADERIMAGE_P_H
+#define QT3DRENDER_RENDER_SHADERIMAGE_P_H
//
// W A R N I N G
@@ -51,65 +51,53 @@
// We mean it.
//
-#include <QtCore/QThread>
-#include <QtCore/QSemaphore>
-#include <QtCore/QMutex>
+#include <Qt3DRender/private/backendnode_p.h>
+#include <Qt3DRender/qshaderimage.h>
QT_BEGIN_NAMESPACE
-class QOpenGLContext;
-
namespace Qt3DRender {
namespace Render {
-class Renderer;
-class GLCommand;
-class OffscreenSurfaceHelper;
-class GraphicsContext;
-class ShaderCache;
-
-class CommandThread : public QThread
+class Q_AUTOTEST_EXPORT ShaderImage : public BackendNode
{
- Q_OBJECT
public:
- explicit CommandThread(Renderer *renderer);
- ~CommandThread();
-
- Render::Renderer* renderer() const { return m_renderer; }
-
- void setShaderCache(ShaderCache *shaderCache);
- ShaderCache *shaderCache() const { return m_shaderCache; }
-
- void initialize(QOpenGLContext *mainContext, OffscreenSurfaceHelper *offsreenSurfaceHelper);
- void shutdown();
-
- void executeCommand(GLCommand *command);
-
-private:
- void run() override;
- void executeCommandInternal(Qt3DRender::Render::GLCommand *command);
+ ShaderImage();
+
+ void cleanup();
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+
+ Qt3DCore::QNodeId textureId() const { return m_textureId; }
+ int mipLevel() const { return m_mipLevel; }
+ int layer() const { return m_layer; }
+ bool layered() const { return m_layered; }
+ QShaderImage::Access access() const { return m_access; }
+ QShaderImage::ImageFormat format() const { return m_format; }
+
+ // For Unit Test purposes only
+#ifdef QT_BUILD_INTERNAL
+ void setTextureId(Qt3DCore::QNodeId id) { m_textureId = id; }
+ void setMipLevel(int level) { m_mipLevel = level; }
+ void setLayer(int layer) { m_layer = layer; }
+ void setLayered(bool layered) { m_layered = layered; }
+ void setAccess(QShaderImage::Access access) { m_access = access; }
+ void setFormat(QShaderImage::ImageFormat format) { m_format = format; }
+#endif
private:
- Renderer* m_renderer;
- QSemaphore m_waitForStartSemaphore;
- QSemaphore m_initializedSemaphore;
- QSemaphore m_commandRequestedSemaphore;
- QSemaphore m_commandExecutionSemaphore;
- QMutex m_blockingCallerMutex;
- QOpenGLContext *m_mainContext;
- ShaderCache *m_shaderCache;
- OffscreenSurfaceHelper *m_offsreenSurfaceHelper;
- QScopedPointer<QOpenGLContext> m_localContext;
- QScopedPointer<GraphicsContext> m_graphicsContext;
- GLCommand *m_currentCommand;
- QAtomicInt m_running;
+ Qt3DCore::QNodeId m_textureId;
+ int m_mipLevel;
+ int m_layer;
+ bool m_layered;
+ QShaderImage::Access m_access;
+ QShaderImage::ImageFormat m_format;
};
-} // Render
+} // namespace Render
-} // Qt3DRender
+} // namespace Qt3DRender
QT_END_NAMESPACE
-#endif // QT3DRENDER_RENDER_COMMANDTHREAD_P_H
+#endif // QT3DRENDER_RENDER_SHADERIMAGE_P_H
diff --git a/src/render/materialsystem/technique.cpp b/src/render/materialsystem/technique.cpp
index 5438fa9c8..10e9af990 100644
--- a/src/render/materialsystem/technique.cpp
+++ b/src/render/materialsystem/technique.cpp
@@ -48,9 +48,6 @@
#include <Qt3DRender/private/qtechnique_p.h>
#include <Qt3DRender/private/shader_p.h>
#include <Qt3DCore/private/qchangearbiter_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/techniquemanager_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
@@ -85,71 +82,48 @@ void Technique::cleanup()
m_isCompatibleWithRenderer = false;
}
-void Technique::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void Technique::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QTechniqueData>>(change);
- const QTechniqueData &data = typedChange->data;
-
- m_graphicsApiFilterData = data.graphicsApiFilterData;
- m_filterKeyList = data.filterKeyIds;
- m_parameterPack.setParameters(data.parameterIds);
- m_renderPasses = data.renderPassIds;
- m_nodeManager->techniqueManager()->addDirtyTechnique(peerId());
-}
+ const QTechnique *node = qobject_cast<const QTechnique *>(frontEnd);
-void Technique::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyUpdated: {
- const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("enabled")) {
- markDirty(AbstractRenderer::TechniquesDirty);
- } else 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;
- m_nodeManager->techniqueManager()->addDirtyTechnique(peerId());
- markDirty(AbstractRenderer::TechniquesDirty);
- }
- break;
+ if (!node)
+ return;
+
+ bool dirty = isEnabled() != frontEnd->isEnabled();
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ auto renderPasses = qIdsForNodes(node->renderPasses());
+ std::sort(std::begin(renderPasses), std::end(renderPasses));
+ if (m_renderPasses != renderPasses) {
+ m_renderPasses = renderPasses;
+ dirty = true;
}
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("pass")) {
- appendRenderPass(change->addedNodeId());
- markDirty(AbstractRenderer::TechniquesDirty);
- } else if (change->propertyName() == QByteArrayLiteral("parameter")) {
- m_parameterPack.appendParameter(change->addedNodeId());
- markDirty(AbstractRenderer::TechniquesDirty);
- } else if (change->propertyName() == QByteArrayLiteral("filterKeys")) {
- appendFilterKey(change->addedNodeId());
- markDirty(AbstractRenderer::TechniquesDirty);
- }
- break;
+ auto parameters = qIdsForNodes(node->parameters());
+ std::sort(std::begin(parameters), std::end(parameters));
+ if (m_parameterPack.parameters() != parameters) {
+ m_parameterPack.setParameters(parameters);
+ dirty = true;
}
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("pass")) {
- removeRenderPass(change->removedNodeId());
- markDirty(AbstractRenderer::TechniquesDirty);
- } else if (change->propertyName() == QByteArrayLiteral("parameter")) {
- m_parameterPack.removeParameter(change->removedNodeId());
- markDirty(AbstractRenderer::TechniquesDirty);
- } else if (change->propertyName() == QByteArrayLiteral("filterKeys")) {
- removeFilterKey(change->removedNodeId());
- markDirty(AbstractRenderer::TechniquesDirty);
- }
- break;
+ auto filterKeys = qIdsForNodes(node->filterKeys());
+ std::sort(std::begin(filterKeys), std::end(filterKeys));
+ if (m_filterKeyList != filterKeys) {
+ m_filterKeyList = filterKeys;
+ dirty = true;
+ }
+
+ auto graphicsApiFilterData = QGraphicsApiFilterPrivate::get(node->graphicsApiFilter())->m_data;
+ if (m_graphicsApiFilterData != graphicsApiFilterData) {
+ m_graphicsApiFilterData = graphicsApiFilterData;
+ m_isCompatibleWithRenderer = false;
+ dirty = true;
}
- default:
- break;
+ if (dirty) {
+ m_nodeManager->techniqueManager()->addDirtyTechnique(peerId());
+ markDirty(AbstractRenderer::TechniquesDirty);
}
- BackendNode::sceneChangeEvent(e);
}
QVector<Qt3DCore::QNodeId> Technique::parameters() const
diff --git a/src/render/materialsystem/technique_p.h b/src/render/materialsystem/technique_p.h
index d885c1b87..1d0d0a9dd 100644
--- a/src/render/materialsystem/technique_p.h
+++ b/src/render/materialsystem/technique_p.h
@@ -80,7 +80,8 @@ public:
~Technique();
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
+
QVector<Qt3DCore::QNodeId> parameters() const;
void appendRenderPass(Qt3DCore::QNodeId renderPassId);
@@ -102,7 +103,6 @@ public:
NodeManagers *nodeManager() const;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
GraphicsApiFilterData m_graphicsApiFilterData;
ParameterPack m_parameterPack;
diff --git a/src/render/picking/objectpicker.cpp b/src/render/picking/objectpicker.cpp
index 43e308d20..84169586e 100644
--- a/src/render/picking/objectpicker.cpp
+++ b/src/render/picking/objectpicker.cpp
@@ -43,7 +43,6 @@
#include <Qt3DRender/private/qobjectpicker_p.h>
#include <Qt3DRender/qattribute.h>
#include <Qt3DRender/private/pickboundingvolumejob_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -75,40 +74,37 @@ void ObjectPicker::cleanup()
notifyJob();
}
-void ObjectPicker::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void ObjectPicker::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QObjectPickerData>>(change);
- const auto &data = typedChange->data;
- m_hoverEnabled = data.hoverEnabled;
- m_dragEnabled = data.dragEnabled;
- m_priority = data.priority;
- notifyJob();
-}
+ const QObjectPicker *node = qobject_cast<const QObjectPicker *>(frontEnd);
+ if (!node)
+ return;
-void ObjectPicker::notifyJob()
-{
- if (m_renderer && m_renderer->pickBoundingVolumeJob())
- qSharedPointerCast<PickBoundingVolumeJob>(m_renderer->pickBoundingVolumeJob())->markPickersDirty();
-}
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
-void ObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- if (e->type() == Qt3DCore::PropertyUpdated) {
- const Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
+ if (node->isHoverEnabled() != m_hoverEnabled) {
+ m_hoverEnabled = node->isHoverEnabled();
+ markDirty(AbstractRenderer::AllDirty);
+ notifyJob();
+ }
- if (propertyChange->propertyName() == QByteArrayLiteral("hoverEnabled")) {
- m_hoverEnabled = propertyChange->value().toBool();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("dragEnabled")) {
- m_dragEnabled = propertyChange->value().toBool();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("priority")) {
- m_priority = propertyChange->value().toInt();
- }
+ if (node->isDragEnabled() != m_dragEnabled) {
+ m_dragEnabled = node->isDragEnabled();
+ markDirty(AbstractRenderer::AllDirty);
+ notifyJob();
+ }
+ if (node->priority() != m_priority) {
+ m_priority = node->priority();
markDirty(AbstractRenderer::AllDirty);
notifyJob();
}
+}
- BackendNode::sceneChangeEvent(e);
+void ObjectPicker::notifyJob()
+{
+ if (m_renderer && m_renderer->pickBoundingVolumeJob())
+ qSharedPointerCast<PickBoundingVolumeJob>(m_renderer->pickBoundingVolumeJob())->markPickersDirty();
}
bool ObjectPicker::isPressed() const
@@ -126,58 +122,9 @@ bool ObjectPicker::isDragEnabled() const
return m_dragEnabled;
}
-void ObjectPicker::onClicked(QPickEventPtr event)
-{
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("clicked");
- e->setValue(QVariant::fromValue(event));
- notifyObservers(e);
-}
-
-void ObjectPicker::onMoved(QPickEventPtr event)
-{
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("moved");
- e->setValue(QVariant::fromValue(event));
- notifyObservers(e);
-}
-
-void ObjectPicker::onPressed(QPickEventPtr event)
-{
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("pressed");
- e->setValue(QVariant::fromValue(event));
- m_isPressed = true;
- notifyObservers(e);
-}
-
-void ObjectPicker::onReleased(QPickEventPtr event)
-{
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("released");
- e->setValue(QVariant::fromValue(event));
- m_isPressed = false;
- notifyObservers(e);
-}
-
-void ObjectPicker::onEntered()
-{
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("entered");
- notifyObservers(e);
-}
-
-void ObjectPicker::onExited()
+void ObjectPicker::setPressed(bool pressed)
{
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("exited");
- notifyObservers(e);
+ m_isPressed = pressed;
}
void ObjectPicker::setPriority(int priority)
diff --git a/src/render/picking/objectpicker_p.h b/src/render/picking/objectpicker_p.h
index 7389a4b53..49c8de770 100644
--- a/src/render/picking/objectpicker_p.h
+++ b/src/render/picking/objectpicker_p.h
@@ -69,24 +69,18 @@ public:
~ObjectPicker();
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) final;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
bool isPressed() const;
bool isHoverEnabled() const;
bool isDragEnabled() const;
- void onClicked(QPickEventPtr event);
- void onMoved(QPickEventPtr event);
- void onPressed(QPickEventPtr event);
- void onReleased(QPickEventPtr event);
- void onEntered();
- void onExited();
+ void setPressed(bool pressed);
// Needed for unit tests
void setPriority(int priority);
int priority() const;
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
void notifyJob();
int m_priority;
diff --git a/src/render/picking/picking.pri b/src/render/picking/picking.pri
index 89c549de0..189d64bb6 100644
--- a/src/render/picking/picking.pri
+++ b/src/render/picking/picking.pri
@@ -7,6 +7,7 @@ HEADERS += \
$$PWD/qpicklineevent.h \
$$PWD/qpickpointevent.h \
$$PWD/qpicktriangleevent.h \
+ $$PWD/qpicktriangleevent_p.h \
$$PWD/objectpicker_p.h \
$$PWD/pickeventfilter_p.h \
$$PWD/qobjectpicker_p.h \
diff --git a/src/render/picking/qabstractraycaster.cpp b/src/render/picking/qabstractraycaster.cpp
index ecec7a628..ab0916401 100644
--- a/src/render/picking/qabstractraycaster.cpp
+++ b/src/render/picking/qabstractraycaster.cpp
@@ -117,7 +117,8 @@ void QAbstractRayCasterPrivate::dispatchHits(const QAbstractRayCaster::Hits &hit
\note Components derived from QAbstractRayCaster should not be shared amount multiple entities.
- \sa Qt3DRender::QRayCaster, Qt3DRender::QScreenRayCaster, Qt3DRender::QObjectPicker, Qt3DRender::QPickingSettings
+ \sa Qt3DRender::QRayCaster, Qt3DRender::QScreenRayCaster, Qt3DRender::QObjectPicker,
+ Qt3DRender::QPickingSettings, Qt3DRender::QNoPicking
*/
/*!
\qmltype AbstractRayCaster
@@ -148,7 +149,8 @@ void QAbstractRayCasterPrivate::dispatchHits(const QAbstractRayCaster::Hits &hit
Note: components derived from AbstractRayCaster should not be shared amount multiple entities.
- \sa Qt3D.Render::RayCaster, Qt3D.Render::ScreenRayCaster, Qt3D.Render::ObjectPicker, Qt3D.Render::PickingSettings
+ \sa Qt3D.Render::RayCaster, Qt3D.Render::ScreenRayCaster, Qt3D.Render::ObjectPicker,
+ Qt3D.Render::PickingSettings, Qt3D.Render::NoPicking
*/
/*!
diff --git a/src/render/picking/qobjectpicker.cpp b/src/render/picking/qobjectpicker.cpp
index d1a246c27..7d9741f21 100644
--- a/src/render/picking/qobjectpicker.cpp
+++ b/src/render/picking/qobjectpicker.cpp
@@ -41,8 +41,10 @@
#include "qobjectpicker_p.h"
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/private/qcomponent_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qscene_p.h>
#include <Qt3DRender/qpickevent.h>
+#include <Qt3DRender/QViewport>
+#include <Qt3DRender/private/qpickevent_p.h>
QT_BEGIN_NAMESPACE
@@ -75,7 +77,7 @@ namespace Qt3DRender {
For generalised ray casting queries, see Qt3DRender::QRayCaster and Qt3DRender::QScreenRayCaster.
\sa Qt3DRender::QPickingSettings, Qt3DRender::QGeometry, Qt3DRender::QAttribute,
- Qt3DRender::QPickEvent, Qt3DRender::QPickTriangleEvent
+ Qt3DRender::QPickEvent, Qt3DRender::QPickTriangleEvent, Qt3DRender::QNoPicking
\note Instances of this component shouldn't be shared, not respecting that
condition will most likely result in undefined behavior.
@@ -110,7 +112,7 @@ namespace Qt3DRender {
If drag is enabled, queries also happen on each mouse move while any button is pressed.
If hover is enabled, queries happen on every mouse move even if no button is pressed.
- \sa PickingSettings, Geometry, Attribute, PickEvent, PickTriangleEvent
+ \sa PickingSettings, Geometry, Attribute, PickEvent, PickTriangleEvent, NoPicking
\note To receive hover events in QtQuick, the hoverEnabled property of Scene3D must also be set.
@@ -356,37 +358,6 @@ int QObjectPicker::priority() const
return d->m_priority;
}
-/*! \internal */
-void QObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
-{
- Q_D(QObjectPicker);
- Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
- if (e->type() == Qt3DCore::PropertyUpdated) {
- // TO DO: Complete this part
- // to emit the correct signals
- const QByteArray propertyName = e->propertyName();
- if (propertyName == QByteArrayLiteral("pressed")) {
- QPickEventPtr ev = e->value().value<QPickEventPtr>();
- d->pressedEvent(ev.data());
- } else if (propertyName == QByteArrayLiteral("released")) {
- QPickEventPtr ev = e->value().value<QPickEventPtr>();
- d->releasedEvent(ev.data());
- } else if (propertyName == QByteArrayLiteral("clicked")) {
- QPickEventPtr ev = e->value().value<QPickEventPtr>();
- d->clickedEvent(ev.data());
- } else if (propertyName == QByteArrayLiteral("moved")) {
- QPickEventPtr ev = e->value().value<QPickEventPtr>();
- d->movedEvent(ev.data());
- } else if (propertyName == QByteArrayLiteral("entered")) {
- emit entered();
- d->setContainsMouse(true);
- } else if (propertyName == QByteArrayLiteral("exited")) {
- d->setContainsMouse(false);
- emit exited();
- }
- }
-}
-
/*!
\internal
*/
diff --git a/src/render/picking/qobjectpicker.h b/src/render/picking/qobjectpicker.h
index 8866c99a9..ee63c9418 100644
--- a/src/render/picking/qobjectpicker.h
+++ b/src/render/picking/qobjectpicker.h
@@ -90,9 +90,6 @@ Q_SIGNALS:
void containsMouseChanged(bool containsMouse);
Q_REVISION(13) void priorityChanged(int priority);
-protected:
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
-
private:
Q_DECLARE_PRIVATE(QObjectPicker)
Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
diff --git a/src/render/picking/qobjectpicker_p.h b/src/render/picking/qobjectpicker_p.h
index b95183ab5..69cee529d 100644
--- a/src/render/picking/qobjectpicker_p.h
+++ b/src/render/picking/qobjectpicker_p.h
@@ -50,7 +50,9 @@
#include <Qt3DCore/private/qcomponent_p.h>
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/qt3drender_global_p.h>
+#include <Qt3DRender/private/objectpicker_p.h>
QT_BEGIN_NAMESPACE
@@ -107,8 +109,16 @@ struct QObjectPickerData
int priority;
};
+struct QObjectPickerEvent
+{
+ QPickEventPtr event;
+ Qt3DCore::QNodeId viewportNodeId;
+};
+
} // namespace Qt3DRender
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(Qt3DRender::QObjectPickerEvent);
+
#endif // QT3DRENDER_QOBJECTPICKER_P_H
diff --git a/src/render/picking/qpickevent.cpp b/src/render/picking/qpickevent.cpp
index 9230cc5e5..ae5748082 100644
--- a/src/render/picking/qpickevent.cpp
+++ b/src/render/picking/qpickevent.cpp
@@ -88,7 +88,8 @@ QPickEventPrivate *QPickEventPrivate::get(QPickEvent *object)
Constructs a new QPickEvent with the given parameters: \a position, \a intersection, \a localIntersection and \a distance
*/
// NOTE: remove in Qt6
-QPickEvent::QPickEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance)
+QPickEvent::QPickEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection,
+ float distance)
: QObject(*new QPickEventPrivate())
{
Q_D(QPickEvent);
@@ -101,7 +102,8 @@ QPickEvent::QPickEvent(const QPointF &position, const QVector3D &worldIntersecti
/*!
Constructs a new QPickEvent with the given parameters: \a position, \a worldIntersection, \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)
+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);
@@ -302,6 +304,51 @@ int QPickEvent::modifiers() const
return d->m_modifiers;
}
+/*!
+ * \qmlproperty Viewport Qt3D.Render::PickEvent::viewport
+ * The viewport in which this event originated. A null value means the event originated from a frame graph branch without a Viewport.
+ * If a frame graph branch has a Viewport inside a Viewport the property will contain the leaf viewport.
+ *
+ * \since 5.14
+ */
+/*!
+ * \property Qt3DRender::QPickEvent::viewport
+ * The viewport in which this event originated. A null value means the event originated from a frame graph branch without a QViewport.
+ * If a frame graph branch has a Viewport inside a Viewport the property will contain the leaf viewport.
+ *
+ * \since 5.14
+ */
+QViewport *QPickEvent::viewport() const
+{
+ Q_D(const QPickEvent);
+ return d->m_viewport;
+}
+
+
+/*!
+ * \qmlproperty Entity Qt3D.Render::PickEvent::entity
+ * The entity that the picked geometry belongs to.
+ *
+ * If the object picker is not attached to a leaf node in the scene graph,
+ * this is useful to find which child entity was actually picked.
+ *
+ * \since 5.14
+ */
+/*!
+ * \property Qt3DRender::QPickEvent::entity
+ * The entity that the picked geometry belongs to.
+ *
+ * If the object picker is not attached to a leaf node in the scene graph,
+ * this is useful to find which child entity was actually picked.
+ *
+ * \since 5.14
+ */
+Qt3DCore::QEntity *QPickEvent::entity() const
+{
+ Q_D(const QPickEvent);
+ return d->m_entityPtr;
+}
+
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/picking/qpickevent.h b/src/render/picking/qpickevent.h
index 5b354efb7..854008aaf 100644
--- a/src/render/picking/qpickevent.h
+++ b/src/render/picking/qpickevent.h
@@ -47,8 +47,13 @@
QT_BEGIN_NAMESPACE
+namespace Qt3DCore {
+class QEntity;
+}
+
namespace Qt3DRender {
+class QViewport;
class QPickEventPrivate;
class QPickEvent;
@@ -65,6 +70,8 @@ class Q_3DRENDERSHARED_EXPORT QPickEvent : public QObject
Q_PROPERTY(Qt3DRender::QPickEvent::Buttons button READ button CONSTANT)
Q_PROPERTY(int buttons READ buttons CONSTANT)
Q_PROPERTY(int modifiers READ modifiers CONSTANT)
+ Q_PROPERTY(Qt3DRender::QViewport *viewport READ viewport CONSTANT REVISION 14)
+ Q_PROPERTY(Qt3DCore::QEntity *entity READ entity CONSTANT REVISION 14)
public:
enum Buttons {
LeftButton = Qt::LeftButton,
@@ -87,7 +94,8 @@ public:
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(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance, Buttons button,
+ int buttons, int modifiers);
~QPickEvent();
bool isAccepted() const;
@@ -103,6 +111,8 @@ public:
Buttons button() const;
int buttons() const;
int modifiers() const;
+ QViewport *viewport() const;
+ Qt3DCore::QEntity *entity() const;
Q_SIGNALS:
void acceptedChanged(bool accepted);
@@ -112,6 +122,8 @@ protected:
private:
Q_DECLARE_PRIVATE(QPickEvent)
+
+ friend class QObjectPickerPrivate;
};
} // Qt3DRender
diff --git a/src/render/picking/qpickevent_p.h b/src/render/picking/qpickevent_p.h
index e27ee51e2..15eeb04b8 100644
--- a/src/render/picking/qpickevent_p.h
+++ b/src/render/picking/qpickevent_p.h
@@ -37,6 +37,9 @@
**
****************************************************************************/
+#ifndef QT3DRENDER_QPICKEVENT_P_H
+#define QT3DRENDER_QPICKEVENT_P_H
+
//
// W A R N I N G
// -------------
@@ -59,6 +62,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
class QPickEvent;
+class QViewport;
class Q_3DRENDERSHARED_PRIVATE_EXPORT QPickEventPrivate : public QObjectPrivate
{
@@ -70,6 +74,8 @@ public:
, m_button(QPickEvent::NoButton)
, m_buttons(QPickEvent::NoButton)
, m_modifiers(QPickEvent::NoModifier)
+ , m_entityPtr(nullptr)
+ , m_viewport(nullptr)
{
}
@@ -82,6 +88,8 @@ public:
int m_buttons;
int m_modifiers;
Qt3DCore::QNodeId m_entity;
+ Qt3DCore::QEntity *m_entityPtr;
+ QViewport *m_viewport;
static QPickEventPrivate *get(QPickEvent *object);
};
@@ -90,3 +98,4 @@ public:
QT_END_NAMESPACE
+#endif // QT3DRENDER_QPICKEVENT_P_H
diff --git a/src/render/picking/qpicktriangleevent.cpp b/src/render/picking/qpicktriangleevent.cpp
index 3e8e8c72c..c077d412f 100644
--- a/src/render/picking/qpicktriangleevent.cpp
+++ b/src/render/picking/qpicktriangleevent.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qpicktriangleevent.h"
+#include "qpicktriangleevent_p.h"
#include "qpickevent_p.h"
#include <private/qobject_p.h>
@@ -45,24 +46,42 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QPickTriangleEventPrivate : public QPickEventPrivate
+
+Qt3DRender::QPickTriangleEventPrivate::QPickTriangleEventPrivate()
+ : QPickEventPrivate()
+ , m_triangleIndex(0)
+ , m_vertex1Index(0)
+ , m_vertex2Index(0)
+ , m_vertex3Index(0)
+{
+}
+
+const QPickTriangleEventPrivate *QPickTriangleEventPrivate::get(const QPickTriangleEvent *ev)
{
-public:
- QPickTriangleEventPrivate()
- : QPickEventPrivate()
- , m_triangleIndex(0)
- , m_vertex1Index(0)
- , m_vertex2Index(0)
- , m_vertex3Index(0)
- {
- }
+ return ev->d_func();
+}
+
+QPickTriangleEvent *QPickTriangleEventPrivate::clone() const
+{
+ auto res = new QPickTriangleEvent();
+ res->d_func()->m_accepted = m_accepted;
+ res->d_func()->m_position = m_position;
+ res->d_func()->m_worldIntersection = m_worldIntersection;
+ res->d_func()->m_localIntersection = m_localIntersection;
+ res->d_func()->m_distance = m_distance;
+ res->d_func()->m_button = m_button;
+ res->d_func()->m_buttons = m_buttons;
+ res->d_func()->m_modifiers = m_modifiers;
+ res->d_func()->m_entity = m_entity;
+ res->d_func()->m_entityPtr = m_entityPtr;
+ res->d_func()->m_viewport = m_viewport;
+ res->d_func()->m_triangleIndex = m_triangleIndex;
+ res->d_func()->m_vertex1Index = m_vertex1Index;
+ res->d_func()->m_vertex2Index = m_vertex2Index;
+ res->d_func()->m_vertex3Index = m_vertex3Index;
+ return res;
+}
- uint m_triangleIndex;
- uint m_vertex1Index;
- uint m_vertex2Index;
- uint m_vertex3Index;
- QVector3D m_uvw;
-};
/*!
\class Qt3DRender::QPickTriangleEvent
diff --git a/src/render/jobs/updateentityhierarchyjob.cpp b/src/render/picking/qpicktriangleevent_p.h
index 7c18514bb..d646ac2bb 100644
--- a/src/render/jobs/updateentityhierarchyjob.cpp
+++ b/src/render/picking/qpicktriangleevent_p.h
@@ -37,44 +37,33 @@
**
****************************************************************************/
-#include "updateentityhierarchyjob_p.h"
-#include <Qt3DRender/private/managers_p.h>
-#include <Qt3DRender/private/nodemanagers_p.h>
-#include <Qt3DRender/private/entity_p.h>
-#include <Qt3DRender/private/job_common_p.h>
+#ifndef QT3DRENDER_QPICKTRIANGLEEVENT_P_H
+#define QT3DRENDER_QPICKTRIANGLEEVENT_P_H
+
+#include <Qt3DRender/private/qpickevent_p.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
+class QPickTriangleEvent;
-namespace Render {
-
-UpdateEntityHierarchyJob::UpdateEntityHierarchyJob()
- : m_manager(nullptr)
-{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateEntityHierarchy, 0);
-}
-
-void UpdateEntityHierarchyJob::run()
+class Q_3DRENDERSHARED_PRIVATE_EXPORT QPickTriangleEventPrivate : public QPickEventPrivate
{
- Q_ASSERT(m_manager);
- EntityManager *entityManager = m_manager->renderNodesManager();
-
- const QVector<HEntity> handles = entityManager->activeHandles();
+public:
+ QPickTriangleEventPrivate();
- // Clear the parents and children
- for (const HEntity &handle : handles) {
- Entity *entity = entityManager->data(handle);
- entity->clearEntityHierarchy();
- }
- for (const HEntity &handle : handles) {
- Entity *entity = entityManager->data(handle);
- entity->rebuildEntityHierarchy();
- }
-}
+ static const QPickTriangleEventPrivate *get(const QPickTriangleEvent *ev);
+ QPickTriangleEvent *clone() const;
-} // Render
+ uint m_triangleIndex;
+ uint m_vertex1Index;
+ uint m_vertex2Index;
+ uint m_vertex3Index;
+ QVector3D m_uvw;
+};
} // Qt3DRender
QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QPICKTRIANGLEEVENT_P_H
diff --git a/src/render/picking/qraycaster.cpp b/src/render/picking/qraycaster.cpp
index cfe5bce1b..f32ea32f1 100644
--- a/src/render/picking/qraycaster.cpp
+++ b/src/render/picking/qraycaster.cpp
@@ -40,7 +40,6 @@
#include "qraycaster.h"
#include "qabstractraycaster_p.h"
#include <Qt3DCore/qentity.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qcomponent_p.h>
#include <Qt3DCore/private/qscene_p.h>
@@ -63,7 +62,7 @@ namespace Qt3DRender {
Ray casting tests will be performed every frame as long as the component is enabled.
The hits property will be updated with the list of intersections.
- \sa QAbstractRayCaster, QScreenRayCaster
+ \sa QAbstractRayCaster, QScreenRayCaster, QNoPicking
*/
/*!
\qmltype RayCaster
@@ -78,7 +77,7 @@ namespace Qt3DRender {
Ray casting tests will be performed every frame as long as the component is enabled.
The hits property will be updated with the list of intersections.
- \sa AbstractRayCaster, ScreenRayCaster
+ \sa AbstractRayCaster, ScreenRayCaster, NoPicking
*/
/*!
diff --git a/src/render/picking/qscreenraycaster.cpp b/src/render/picking/qscreenraycaster.cpp
index 95df8e4c1..3e47c2a01 100644
--- a/src/render/picking/qscreenraycaster.cpp
+++ b/src/render/picking/qscreenraycaster.cpp
@@ -40,7 +40,6 @@
#include "qscreenraycaster.h"
#include "qabstractraycaster_p.h"
#include <Qt3DCore/qentity.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qcomponent_p.h>
#include <Qt3DCore/private/qscene_p.h>
@@ -59,7 +58,7 @@ namespace Qt3DRender {
screen space, which will be used to construct an actual 3D ray between the near and
far planes.
- \sa QRayCaster
+ \sa QRayCaster, QNoPicking
*/
/*!
\qmltype ScreenRayCaster
@@ -72,7 +71,7 @@ namespace Qt3DRender {
screen space, which will be used to construct an actual 3D ray between the near and
far planes.
- \sa RayCaster
+ \sa RayCaster, NoPicking
*/
/*!
diff --git a/src/render/picking/raycaster.cpp b/src/render/picking/raycaster.cpp
index a5fbf1206..3a79204c7 100644
--- a/src/render/picking/raycaster.cpp
+++ b/src/render/picking/raycaster.cpp
@@ -41,11 +41,10 @@
#include "qpickevent.h"
#include <Qt3DRender/private/abstractrenderer_p.h>
#include <Qt3DRender/qabstractraycaster.h>
+#include <Qt3DRender/qlayer.h>
#include <Qt3DRender/private/qabstractraycaster_p.h>
#include <Qt3DRender/private/raycastingjob_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
QT_BEGIN_NAMESPACE
@@ -119,87 +118,62 @@ void RayCaster::cleanup()
notifyJob();
}
-void RayCaster::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void RayCaster::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAbstractRayCasterData>>(change);
- const auto &data = typedChange->data;
- m_type = data.casterType;
- m_runMode = data.runMode;
- m_origin = data.origin;
- m_direction = data.direction;
- m_length = data.length;
- m_position = data.position;
- m_filterMode = data.filterMode;
- m_layerIds = data.layerIds;
-}
+ const QAbstractRayCaster *node = qobject_cast<const QAbstractRayCaster *>(frontEnd);
+ if (!node)
+ return;
-void RayCaster::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- switch (e->type()) {
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("layer")) {
- m_layerIds.append(change->addedNodeId());
- markDirty(AbstractRenderer::LayersDirty);
- notifyJob();
- }
- break;
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (node->runMode() != m_runMode) {
+ m_runMode = node->runMode();
+ notifyJob();
+ markDirty(AbstractRenderer::AllDirty);
}
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("layer")) {
- m_layerIds.removeOne(change->removedNodeId());
- markDirty(AbstractRenderer::LayersDirty);
- notifyJob();
- }
- break;
+ if (node->filterMode() != m_filterMode) {
+ m_filterMode = node->filterMode();
+ notifyJob();
+ markDirty(AbstractRenderer::AllDirty);
}
- case PropertyUpdated: {
- const Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
-
- if (propertyChange->propertyName() == QByteArrayLiteral("origin")) {
- m_origin = propertyChange->value().value<QVector3D>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("direction")) {
- m_direction = propertyChange->value().value<QVector3D>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("length")) {
- m_length = propertyChange->value().toFloat();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("position")) {
- m_position = propertyChange->value().toPoint();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("runMode")) {
- m_runMode = propertyChange->value().value<QAbstractRayCaster::RunMode>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("filterMode")) {
- m_filterMode = propertyChange->value().value<QAbstractRayCaster::FilterMode>();
- }
+ const Qt3DCore::QNodeIdVector layerIds = Qt3DCore::qIdsForNodes(node->layers());
+ if (layerIds != m_layerIds) {
+ m_layerIds = layerIds;
+ markDirty(AbstractRenderer::LayersDirty);
+ notifyJob();
+ }
+
+ const QAbstractRayCasterPrivate *d = static_cast<const QAbstractRayCasterPrivate *>(QNodePrivate::get(node));
+ if (d->m_direction != m_direction) {
+ m_direction = d->m_direction;
+ notifyJob();
+ markDirty(AbstractRenderer::AllDirty);
+ }
+ if (!qFuzzyCompare(d->m_length, m_length)) {
+ m_length = d->m_length;
notifyJob();
markDirty(AbstractRenderer::AllDirty);
- break;
}
- default:
- break;
+ if (d->m_origin != m_origin) {
+ m_origin = d->m_origin;
+ notifyJob();
+ markDirty(AbstractRenderer::AllDirty);
}
- BackendNode::sceneChangeEvent(e);
-}
+ if (d->m_position != m_position) {
+ m_position = d->m_position;
+ notifyJob();
+ markDirty(AbstractRenderer::AllDirty);
+ }
-void RayCaster::dispatchHits(const QAbstractRayCaster::Hits &hits)
-{
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("hits");
- e->setValue(QVariant::fromValue(hits));
- notifyObservers(e);
-
- if (m_runMode == QAbstractRayCaster::SingleShot) {
- setEnabled(false);
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("enabled");
- e->setValue(false);
- notifyObservers(e);
+ if (d->m_rayCasterType != m_type) {
+ m_type = d->m_rayCasterType;
+ notifyJob();
+ markDirty(AbstractRenderer::AllDirty);
}
}
diff --git a/src/render/picking/raycaster_p.h b/src/render/picking/raycaster_p.h
index 6fe6ee322..865d40365 100644
--- a/src/render/picking/raycaster_p.h
+++ b/src/render/picking/raycaster_p.h
@@ -80,13 +80,10 @@ public:
Qt3DCore::QNodeIdVector layerIds() const;
QAbstractRayCaster::FilterMode filterMode() const;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) final;
-
- void dispatchHits(const QAbstractRayCaster::Hits &hits);
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
void notifyJob();
QAbstractRayCasterPrivate::RayCasterType m_type = QAbstractRayCasterPrivate::WorldSpaceRayCaster;
diff --git a/src/render/raycasting/qraycastingservice.cpp b/src/render/raycasting/qraycastingservice.cpp
index a0f21aa41..bdb1557f7 100644
--- a/src/render/raycasting/qraycastingservice.cpp
+++ b/src/render/raycasting/qraycastingservice.cpp
@@ -43,7 +43,6 @@
#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DRender/private/qboundingvolumeprovider_p.h>
-#include <QMap>
#include <QtConcurrent>
#include "math.h"
diff --git a/src/render/render.pro b/src/render/render.pro
index ea5ce7dc5..55303fa83 100644
--- a/src/render/render.pro
+++ b/src/render/render.pro
@@ -20,9 +20,6 @@ include (services/services.pri)
include (texture/texture.pri)
include (renderers/renderers.pri)
-# Qt3D is free of Q_FOREACH - make sure it stays that way:
-DEFINES += QT_NO_FOREACH
-
gcov {
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp b/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp
index be8f861e3..333453ac7 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp
@@ -92,6 +92,10 @@ QT_BEGIN_NAMESPACE
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#endif
+#ifndef GL_MAX_IMAGE_UNITS
+#define GL_MAX_IMAGE_UNITS 0x8F38
+#endif
+
namespace {
QOpenGLShader::ShaderType shaderType(Qt3DRender::QShaderProgram::ShaderType type)
@@ -125,6 +129,7 @@ GraphicsContext::GraphicsContext()
: m_initialized(false)
, m_supportsVAO(false)
, m_maxTextureUnits(0)
+ , m_maxImageUnits(0)
, m_defaultFBO(0)
, m_gl(nullptr)
, m_glHelper(nullptr)
@@ -152,6 +157,8 @@ void GraphicsContext::initialize()
m_gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &m_maxTextureUnits);
qCDebug(Backend) << "context supports" << m_maxTextureUnits << "texture units";
+ m_gl->functions()->glGetIntegerv(GL_MAX_IMAGE_UNITS, &m_maxImageUnits);
+ qCDebug(Backend) << "context supports" << m_maxImageUnits << "image units";
if (m_gl->format().majorVersion() >= 3) {
m_supportsVAO = true;
@@ -272,7 +279,7 @@ void GraphicsContext::introspectShaderInterface(Shader *shader, QOpenGLShaderPro
}
-// Called by GL Command Thread
+// Called by Renderer::updateGLResources
void GraphicsContext::loadShader(Shader *shader, ShaderManager *manager)
{
bool wasPresent = false;
@@ -310,7 +317,8 @@ void GraphicsContext::loadShader(Shader *shader, ShaderManager *manager)
shader->setGraphicsContext(this);
shader->setLoaded(true);
- shader->markDirty(AbstractRenderer::AllDirty);
+ // Will force notifications to be sent to frontend at next frame
+ shader->markDirty(AbstractRenderer::ShadersDirty);
}
}
@@ -335,6 +343,11 @@ void GraphicsContext::activateDrawBuffers(const AttachmentPack &attachments)
}
}
+void GraphicsContext::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_glHelper->rasterMode(faceMode, rasterMode);
+}
+
/*!
* \internal
* Finds the highest supported opengl version and internally use the most optimized
@@ -555,6 +568,11 @@ void GraphicsContext::bindFramebuffer(GLuint fbo, GraphicsHelperInterface::FBOBi
m_glHelper->bindFrameBufferObject(fbo, mode);
}
+void GraphicsContext::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_glHelper->depthRange(nearValue, farValue);
+}
+
void GraphicsContext::depthTest(GLenum mode)
{
m_glHelper->depthTest(mode);
@@ -577,6 +595,19 @@ void GraphicsContext::bindFragOutputs(GLuint shader, const QHash<QString, int> &
m_glHelper->bindFragDataLocation(shader, outputs);
}
+void GraphicsContext::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ m_glHelper->bindImageTexture(imageUnit,
+ texture,
+ mipLevel,
+ layered,
+ layer,
+ access,
+ format);
+}
+
void GraphicsContext::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
{
m_glHelper->bindUniformBlock(programId, uniformBlockIndex, uniformBlockBinding);
@@ -652,11 +683,17 @@ GLint GraphicsContext::maxClipPlaneCount()
return m_glHelper->maxClipPlaneCount();
}
-GLint GraphicsContext::maxTextureUnitsCount()
+GLint GraphicsContext::maxTextureUnitsCount() const
{
return m_maxTextureUnits;
}
+GLint GraphicsContext::maxImageUnitsCount() const
+{
+ return m_maxImageUnits;
+}
+
+
void GraphicsContext::enablePrimitiveRestart(int restartIndex)
{
if (m_glHelper->supportsFeature(GraphicsHelperInterface::PrimitiveRestart))
@@ -759,6 +796,7 @@ void GraphicsContext::applyUniform(const ShaderUniform &description, const Unifo
break;
case UniformType::Sampler:
+ case UniformType::Image:
case UniformType::Int:
applyUniformHelper<UniformType::Int>(description, v);
break;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h b/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h
index 73d1f316c..2f4df2e22 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h
@@ -123,6 +123,7 @@ public:
void bindFramebuffer(GLuint fbo, GraphicsHelperInterface::FBOBindMode mode);
void bindBufferBase(GLenum target, GLuint bindingIndex, GLuint buffer);
void bindFragOutputs(GLuint shader, const QHash<QString, int> &outputs);
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format);
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding);
void blendEquation(GLenum mode);
@@ -134,6 +135,7 @@ public:
void clearColor(const QColor &color);
void clearDepthValue(float depth);
void clearStencilValue(int stencil);
+ void depthRange(GLdouble nearValue, GLdouble farValue);
void depthMask(GLenum mode);
void depthTest(GLenum mode);
void disableClipPlane(int clipPlane);
@@ -154,7 +156,8 @@ public:
void enablePrimitiveRestart(int restartIndex);
void frontFace(GLenum mode);
GLint maxClipPlaneCount();
- GLint maxTextureUnitsCount();
+ GLint maxTextureUnitsCount() const;
+ GLint maxImageUnitsCount() const;
void pointSize(bool programmable, GLfloat value);
void readBuffer(GLenum mode);
void drawBuffer(GLenum mode);
@@ -166,6 +169,7 @@ public:
void setVerticesPerPatch(GLint verticesPerPatch);
void memoryBarrier(QMemoryBarrier::Operations barriers);
void activateDrawBuffers(const AttachmentPack &attachments);
+ void rasterMode(GLenum faceMode, GLenum rasterMode);
// Helper methods
static GLint elementType(GLint type);
@@ -183,6 +187,7 @@ public:
bool m_initialized;
bool m_supportsVAO;
GLint m_maxTextureUnits;
+ GLint m_maxImageUnits;
GLuint m_defaultFBO;
QOpenGLContext *m_gl;
GraphicsHelperInterface *m_glHelper;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp
index 71540b1ad..5f77dd376 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp
@@ -345,6 +345,13 @@ void GraphicsHelperES2::deleteSync(void *)
qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
}
+void GraphicsHelperES2::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ Q_UNUSED(faceMode);
+ Q_UNUSED(rasterMode);
+ qWarning() << "glPolyonMode is not supported with OpenGL ES";
+}
+
void GraphicsHelperES2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -394,6 +401,11 @@ void GraphicsHelperES2::depthMask(GLenum mode)
m_funcs->glDepthMask(mode);
}
+void GraphicsHelperES2::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRangef(static_cast<float>(nearValue), static_cast<float>(farValue));
+}
+
void GraphicsHelperES2::frontFace(GLenum mode)
{
m_funcs->glFrontFace(mode);
@@ -435,6 +447,21 @@ void GraphicsHelperES2::bindFrameBufferObject(GLuint frameBufferId, FBOBindMode
m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, frameBufferId);
}
+void GraphicsHelperES2::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ Q_UNUSED(imageUnit)
+ Q_UNUSED(texture)
+ Q_UNUSED(mipLevel)
+ Q_UNUSED(layered)
+ Q_UNUSED(layer)
+ Q_UNUSED(access)
+ Q_UNUSED(format)
+ qWarning() << "Shader Images are not supported by ES 2.0 (since ES 3.1)";
+
+}
+
GLuint GraphicsHelperES2::boundFrameBufferObject()
{
GLint id = 0;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h
index 8c8dd34e9..882931ad9 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h
@@ -76,6 +76,7 @@ public:
void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
void blendEquation(GLenum mode) override;
@@ -88,6 +89,7 @@ public:
void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
GLuint createFrameBufferObject() override;
void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
void depthTest(GLenum mode) override;
void disableClipPlane(int clipPlane) override;
void disablei(GLenum cap, GLuint index) override;
@@ -131,6 +133,7 @@ public:
void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
void *fenceSync() override;
void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp
index a555b67ef..9c424d962 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp
@@ -110,6 +110,42 @@ QT_BEGIN_NAMESPACE
#ifndef GL_SHADER_STORAGE_BARRIER_BIT
#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
#endif
+#ifndef GL_IMAGE_2D
+#define GL_IMAGE_2D 0x904D
+#endif
+#ifndef GL_IMAGE_3D
+#define GL_IMAGE_3D 0x904E
+#endif
+#ifndef GL_IMAGE_CUBE
+#define GL_IMAGE_CUBE 0x9050
+#endif
+#ifndef GL_IMAGE_2D_ARRAY
+#define GL_IMAGE_2D_ARRAY 0x9053
+#endif
+#ifndef GL_INT_IMAGE_2D
+#define GL_INT_IMAGE_2D 0x9058
+#endif
+#ifndef GL_INT_IMAGE_3D
+#define GL_INT_IMAGE_3D 0x9059
+#endif
+#ifndef GL_INT_IMAGE_CUBE
+#define GL_INT_IMAGE_CUBE 0x905B
+#endif
+#ifndef GL_INT_IMAGE_2D_ARRAY
+#define GL_INT_IMAGE_2D_ARRAY 0x905E
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_2D
+#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_3D
+#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_CUBE
+#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+#endif
namespace Qt3DRender {
@@ -175,6 +211,7 @@ bool GraphicsHelperES3_1::supportsFeature(GraphicsHelperInterface::Feature featu
case GraphicsHelperInterface::Compute:
case GraphicsHelperInterface::ShaderStorageObject:
case GraphicsHelperInterface::IndirectDrawing:
+ case GraphicsHelperInterface::ShaderImage:
return true;
default:
break;
@@ -182,6 +219,19 @@ bool GraphicsHelperES3_1::supportsFeature(GraphicsHelperInterface::Feature featu
return GraphicsHelperES3::supportsFeature(feature);
}
+void GraphicsHelperES3_1::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ m_extraFuncs->glBindImageTexture(imageUnit,
+ texture,
+ mipLevel,
+ layered,
+ layer,
+ access,
+ format);
+}
+
void GraphicsHelperES3_1::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
{
m_extraFuncs->glDispatchCompute(wx, wy, wz);
@@ -240,6 +290,19 @@ UniformType GraphicsHelperES3_1::uniformTypeFromGLType(GLenum glType)
case GL_INT_SAMPLER_2D_MULTISAMPLE:
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
return UniformType::Sampler;
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ return UniformType::Image;
default:
return GraphicsHelperES3::uniformTypeFromGLType(glType);
@@ -254,6 +317,18 @@ uint GraphicsHelperES3_1::uniformByteSize(const ShaderUniform &description)
case GL_SAMPLER_2D_MULTISAMPLE:
case GL_INT_SAMPLER_2D_MULTISAMPLE:
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
rawByteSize = 4;
break;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h
index 2c130fbf5..43d9ae7dd 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h
@@ -65,6 +65,7 @@ public:
~GraphicsHelperES3_1();
bool supportsFeature(Feature feature) const override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) override;
void memoryBarrier(QMemoryBarrier::Operations barriers) override;
void drawArraysIndirect(GLenum mode,void *indirect) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp
index 56da249f2..9d0988410 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp
@@ -56,6 +56,25 @@ QT_BEGIN_NAMESPACE
#define GL_PATCH_VERTICES 36466
#endif
+#ifndef GL_IMAGE_BUFFER
+#define GL_IMAGE_BUFFER 0x9051
+#endif
+#ifndef GL_IMAGE_CUBE_MAP_ARRAY
+#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
+#endif
+#ifndef GL_INT_IMAGE_BUFFER
+#define GL_INT_IMAGE_BUFFER 0x905C
+#endif
+#ifndef GL_INT_IMAGE_CUBE_MAP_ARRAY
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_BUFFER
+#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#endif
+
namespace Qt3DRender {
namespace Render {
@@ -130,6 +149,44 @@ void GraphicsHelperES3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum pri
baseVertex);
}
+UniformType GraphicsHelperES3_2::uniformTypeFromGLType(GLenum glType)
+{
+ switch (glType) {
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ return UniformType::Image;
+
+ default:
+ return GraphicsHelperES3_1::uniformTypeFromGLType(glType);
+ }
+}
+
+uint GraphicsHelperES3_2::uniformByteSize(const ShaderUniform &description)
+{
+ uint rawByteSize = 0;
+
+ switch (description.m_type) {
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ rawByteSize = 4;
+ break;
+
+ default:
+ rawByteSize = GraphicsHelperES3_1::uniformByteSize(description);
+ break;
+ }
+
+ return rawByteSize;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h
index 259864379..6b1a893d4 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h
@@ -71,6 +71,9 @@ public:
bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override;
void setVerticesPerPatch(GLint verticesPerPatch) override;
void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override;
+ UniformType uniformTypeFromGLType(GLenum glType) override;
+ uint uniformByteSize(const ShaderUniform &description) override;
+
};
} // namespace Render
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp
index b6f3412b2..b9ee16acb 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp
@@ -299,6 +299,11 @@ void GraphicsHelperGL2::deleteSync(void *)
qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
}
+void GraphicsHelperGL2::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_funcs->glPolygonMode(faceMode, rasterMode);
+}
+
void GraphicsHelperGL2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -341,6 +346,11 @@ void GraphicsHelperGL2::depthMask(GLenum mode)
m_funcs->glDepthMask(mode);
}
+void GraphicsHelperGL2::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRange(nearValue, farValue);
+}
+
void GraphicsHelperGL2::frontFace(GLenum mode)
{
m_funcs->glFrontFace(mode);
@@ -480,6 +490,21 @@ void GraphicsHelperGL2::bindFrameBufferObject(GLuint frameBufferId, FBOBindMode
}
}
+void GraphicsHelperGL2::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ Q_UNUSED(imageUnit)
+ Q_UNUSED(texture)
+ Q_UNUSED(mipLevel)
+ Q_UNUSED(layered)
+ Q_UNUSED(layer)
+ Q_UNUSED(access)
+ Q_UNUSED(format)
+ qWarning() << "Shader Images are not supported by OpenGL 2.0 (since OpenGL 4.2)";
+
+}
+
GLuint GraphicsHelperGL2::boundFrameBufferObject()
{
GLint id = 0;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h
index b142b2623..eb85b8537 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h
@@ -76,6 +76,7 @@ public:
void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
void blendEquation(GLenum mode) override;
@@ -88,6 +89,7 @@ public:
void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
GLuint createFrameBufferObject() override;
void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
void depthTest(GLenum mode) override;
void disableClipPlane(int clipPlane) override;
void disablei(GLenum cap, GLuint index) override;
@@ -131,6 +133,7 @@ public:
void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
void *fenceSync() override;
void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp
index 5ff1a2ba5..f20491358 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp
@@ -365,6 +365,11 @@ void GraphicsHelperGL3_2::deleteSync(void *sync)
m_funcs->glDeleteSync(static_cast<GLsync>(sync));
}
+void GraphicsHelperGL3_2::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_funcs->glPolygonMode(faceMode, rasterMode);
+}
+
void GraphicsHelperGL3_2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -406,6 +411,11 @@ void GraphicsHelperGL3_2::depthMask(GLenum mode)
m_funcs->glDepthMask(mode);
}
+void GraphicsHelperGL3_2::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRange(nearValue, farValue);
+}
+
void GraphicsHelperGL3_2::frontFace(GLenum mode)
{
m_funcs->glFrontFace(mode);
@@ -452,6 +462,21 @@ void GraphicsHelperGL3_2::bindFrameBufferObject(GLuint frameBufferId, FBOBindMod
}
}
+void GraphicsHelperGL3_2::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ Q_UNUSED(imageUnit)
+ Q_UNUSED(texture)
+ Q_UNUSED(mipLevel)
+ Q_UNUSED(layered)
+ Q_UNUSED(layer)
+ Q_UNUSED(access)
+ Q_UNUSED(format)
+ qWarning() << "Shader Images are not supported by OpenGL 3.2 (since OpenGL 4.2)";
+
+}
+
GLuint GraphicsHelperGL3_2::boundFrameBufferObject()
{
GLint id = 0;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h
index 9e81345ad..914afc9ff 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h
@@ -78,6 +78,7 @@ public:
void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
void blendEquation(GLenum mode) override;
@@ -90,6 +91,7 @@ public:
void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
GLuint createFrameBufferObject() override;
void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
void depthTest(GLenum mode) override;
void disableClipPlane(int clipPlane) override;
void disablei(GLenum cap, GLuint index) override;
@@ -133,6 +135,7 @@ public:
void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
void *fenceSync() override;
void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp
index 81081943d..ddffb38e2 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp
@@ -361,6 +361,11 @@ void GraphicsHelperGL3_3::deleteSync(void *sync)
m_funcs->glDeleteSync(static_cast<GLsync>(sync));
}
+void GraphicsHelperGL3_3::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_funcs->glPolygonMode(faceMode, rasterMode);
+}
+
void GraphicsHelperGL3_3::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -402,6 +407,11 @@ void GraphicsHelperGL3_3::depthMask(GLenum mode)
m_funcs->glDepthMask(mode);
}
+void GraphicsHelperGL3_3::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRange(nearValue, farValue);
+}
+
void GraphicsHelperGL3_3::frontFace(GLenum mode)
{
m_funcs->glFrontFace(mode);
@@ -546,6 +556,20 @@ void GraphicsHelperGL3_3::bindShaderStorageBlock(GLuint programId, GLuint shader
qWarning() << "SSBO are not supported by OpenGL 3.3 (since OpenGL 4.3)";
}
+void GraphicsHelperGL3_3::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ Q_UNUSED(imageUnit)
+ Q_UNUSED(texture)
+ Q_UNUSED(mipLevel)
+ Q_UNUSED(layered)
+ Q_UNUSED(layer)
+ Q_UNUSED(access)
+ Q_UNUSED(format)
+ qWarning() << "Shader Images are not supported by OpenGL 3.3 (since OpenGL 4.2)";
+}
+
void GraphicsHelperGL3_3::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
{
m_funcs->glBindBufferBase(target, index, buffer);
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h
index c480e5258..4dbf6fe7b 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h
@@ -79,6 +79,7 @@ public:
void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
void blendEquation(GLenum mode) override;
void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) override;
@@ -90,6 +91,7 @@ public:
void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
GLuint createFrameBufferObject() override;
void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
void depthTest(GLenum mode) override;
void disableClipPlane(int clipPlane) override;
void disablei(GLenum cap, GLuint index) override;
@@ -133,6 +135,7 @@ public:
void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
void *fenceSync() override;
void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp
index 22cbf7428..60caed273 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp
@@ -79,6 +79,39 @@
# define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
# define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
# define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000
+# define GL_IMAGE_1D 0x904C
+# define GL_IMAGE_2D 0x904D
+# define GL_IMAGE_3D 0x904E
+# define GL_IMAGE_2D_RECT 0x904F
+# define GL_IMAGE_CUBE 0x9050
+# define GL_IMAGE_BUFFER 0x9051
+# define GL_IMAGE_1D_ARRAY 0x9052
+# define GL_IMAGE_2D_ARRAY 0x9053
+# define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
+# define GL_IMAGE_2D_MULTISAMPLE 0x9055
+# define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
+# define GL_INT_IMAGE_1D 0x9057
+# define GL_INT_IMAGE_2D 0x9058
+# define GL_INT_IMAGE_3D 0x9059
+# define GL_INT_IMAGE_2D_RECT 0x905A
+# define GL_INT_IMAGE_CUBE 0x905B
+# define GL_INT_IMAGE_BUFFER 0x905C
+# define GL_INT_IMAGE_1D_ARRAY 0x905D
+# define GL_INT_IMAGE_2D_ARRAY 0x905E
+# define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
+# define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
+# define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
+# define GL_UNSIGNED_INT_IMAGE_1D 0x9062
+# define GL_UNSIGNED_INT_IMAGE_2D 0x9063
+# define GL_UNSIGNED_INT_IMAGE_3D 0x9064
+# define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
+# define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+# define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
+# define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
+# define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+# define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+# define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
+# define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
# endif
QT_BEGIN_NAMESPACE
@@ -433,6 +466,11 @@ void GraphicsHelperGL4::deleteSync(void *sync)
m_funcs->glDeleteSync(static_cast<GLsync>(sync));
}
+void GraphicsHelperGL4::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_funcs->glPolygonMode(faceMode, rasterMode);
+}
+
void GraphicsHelperGL4::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform1fv(location, count, values);
@@ -630,6 +668,42 @@ UniformType GraphicsHelperGL4::uniformTypeFromGLType(GLenum type)
case GL_UNSIGNED_INT_SAMPLER_CUBE:
case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
return UniformType::Sampler;
+
+ case GL_IMAGE_1D:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_2D_RECT:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_1D_ARRAY:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_IMAGE_2D_MULTISAMPLE:
+ case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_IMAGE_1D:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_2D_RECT:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_1D_ARRAY:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_1D:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_2D_RECT:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ return UniformType::Image;
+
default:
// TO DO: Add support for Doubles and Images
Q_UNREACHABLE();
@@ -668,6 +742,11 @@ void GraphicsHelperGL4::depthMask(GLenum mode)
m_funcs->glDepthMask(mode);
}
+void GraphicsHelperGL4::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRange(nearValue, farValue);
+}
+
void GraphicsHelperGL4::frontFace(GLenum mode)
{
m_funcs->glFrontFace(mode);
@@ -714,6 +793,19 @@ void GraphicsHelperGL4::bindFrameBufferObject(GLuint frameBufferId, FBOBindMode
}
}
+void GraphicsHelperGL4::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ m_funcs->glBindImageTexture(imageUnit,
+ texture,
+ mipLevel,
+ layered,
+ layer,
+ access,
+ format);
+}
+
GLuint GraphicsHelperGL4::boundFrameBufferObject()
{
GLint id = 0;
@@ -781,6 +873,7 @@ bool GraphicsHelperGL4::supportsFeature(GraphicsHelperInterface::Feature feature
case IndirectDrawing:
case MapBuffer:
case Fences:
+ case ShaderImage:
return true;
default:
return false;
@@ -1009,7 +1102,40 @@ void GraphicsHelperGL4::buildUniformBuffer(const QVariant &v, const ShaderUnifor
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: {
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_IMAGE_1D:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_2D_RECT:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_1D_ARRAY:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_IMAGE_2D_MULTISAMPLE:
+ case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_IMAGE_1D:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_2D_RECT:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_1D_ARRAY:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_1D:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_2D_RECT:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: {
Q_ASSERT(description.m_size == 1);
int value = v.toInt();
QGraphicsUtils::fillDataArray<GLint>(bufferData, &value, description, 1);
@@ -1139,8 +1265,47 @@ uint GraphicsHelperGL4::uniformByteSize(const ShaderUniform &description)
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_IMAGE_1D:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_2D_RECT:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_1D_ARRAY:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_IMAGE_2D_MULTISAMPLE:
+ case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_IMAGE_1D:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_2D_RECT:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_1D_ARRAY:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_1D:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_2D_RECT:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
rawByteSize = 4;
break;
+
+ default: {
+ qWarning() << Q_FUNC_INFO << "unable to deduce rawByteSize for uniform type:" << description.m_type << "for uniform" << description.m_name;
+ break;
+ }
+
}
return arrayStride ? rawByteSize * arrayStride : rawByteSize;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h
index da62f4212..d3ce0d079 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h
@@ -76,6 +76,7 @@ public:
void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
void blendEquation(GLenum mode) override;
@@ -88,6 +89,7 @@ public:
void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
GLuint createFrameBufferObject() override;
void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
void depthTest(GLenum mode) override;
void disableClipPlane(int clipPlane) override;
void disablei(GLenum cap, GLuint index) override;
@@ -131,6 +133,7 @@ public:
void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
void *fenceSync() override;
void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h
index 2a1688b7f..21146c32b 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h
@@ -83,7 +83,8 @@ public:
BlitFramebuffer,
IndirectDrawing,
MapBuffer,
- Fences
+ Fences,
+ ShaderImage
};
enum FBOBindMode {
@@ -100,6 +101,7 @@ public:
virtual void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) = 0;
virtual void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) = 0;
virtual void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) = 0;
+ virtual void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) = 0;
virtual void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) = 0;
virtual void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0;
virtual void blendEquation(GLenum mode) = 0;
@@ -111,6 +113,7 @@ public:
virtual bool checkFrameBufferComplete() = 0;
virtual void clearBufferf(GLint drawbuffer, const QVector4D &values) = 0;
virtual GLuint createFrameBufferObject() = 0;
+ virtual void depthRange(GLdouble nearValue, GLdouble farValue) = 0;
virtual void depthMask(GLenum mode) = 0;
virtual void depthTest(GLenum mode) = 0;
virtual void disableClipPlane(int clipPlane) = 0;
@@ -155,6 +158,7 @@ public:
virtual void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) = 0;
virtual void readBuffer(GLenum mode) = 0;
virtual void drawBuffer(GLenum mode) = 0;
+ virtual void rasterMode(GLenum faceMode, GLenum rasterMode) = 0;
virtual void *fenceSync() = 0;
virtual void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) = 0;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri
index ad08038c9..f2f7274d7 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri
@@ -14,6 +14,7 @@ HEADERS += \
$$PWD/graphicshelpergl3_3_p.h \
$$PWD/graphicshelpergl4_p.h \
$$PWD/graphicshelpergl3_2_p.h \
+ $$PWD/imagesubmissioncontext_p.h \
$$PWD/submissioncontext_p.h \
$$PWD/texturesubmissioncontext_p.h
@@ -27,5 +28,6 @@ SOURCES += \
$$PWD/graphicshelpergl3_3.cpp \
$$PWD/graphicshelpergl4.cpp \
$$PWD/graphicshelpergl3_2.cpp \
+ $$PWD/imagesubmissioncontext.cpp \
$$PWD/submissioncontext.cpp \
$$PWD/texturesubmissioncontext.cpp
diff --git a/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp
new file mode 100644
index 000000000..ca600f994
--- /dev/null
+++ b/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "imagesubmissioncontext_p.h"
+#include <Qt3DRender/private/graphicscontext_p.h>
+#include <Qt3DRender/private/gltexture_p.h>
+#include <Qt3DRender/private/shaderimage_p.h>
+#include <Qt3DRender/qshaderimage.h>
+
+QT_BEGIN_NAMESPACE
+
+// ES 3.1+ or GL 4.2+
+#ifndef GL_READ_ONLY
+#define GL_READ_ONLY 0x88B8
+#endif
+#ifndef GL_WRITE_ONLY
+#define GL_WRITE_ONLY 0x88B9
+#endif
+#ifndef GL_READ_WRITE
+#define GL_READ_WRITE 0x88BA
+#endif
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsContext;
+class GLTexture;
+
+namespace {
+
+GLenum glAccessEnumForShaderImageAccess(QShaderImage::Access access)
+{
+ switch (access) {
+ case QShaderImage::ReadOnly:
+ return GL_READ_ONLY;
+ case QShaderImage::WriteOnly:
+ return GL_WRITE_ONLY;
+ case QShaderImage::ReadWrite:
+ default:
+ break;
+ }
+ return GL_READ_WRITE;
+}
+
+GLenum glImageFormatToGL(QShaderImage::ImageFormat format)
+{
+ // Right now we can abuse from the fact that the ImageFormat enum values
+ // have been assigned the same value as the GL enum
+ return GLenum(format);
+}
+
+GLenum glImageFormatForShaderImageFormat(QShaderImage::ImageFormat format,
+ QAbstractTexture::TextureFormat textureFormat)
+{
+ Q_ASSERT_X(format != QShaderImage::NoFormat, Q_FUNC_INFO, "Valid image format or Automatic expected");
+
+ if (format != QShaderImage::Automatic)
+ return glImageFormatToGL(format);
+
+ // Otherwise try to mind to best texture format
+ switch (textureFormat) {
+ case QAbstractTexture::R8_UNorm:
+ return glImageFormatToGL(QShaderImage::R8_UNorm);
+ case QAbstractTexture::RG8_UNorm:
+ return glImageFormatToGL(QShaderImage::RG8_UNorm);
+ case QAbstractTexture::RGBA8_UNorm:
+ return glImageFormatToGL(QShaderImage::RGBA8_UNorm);
+
+ case QAbstractTexture::R16_UNorm:
+ return glImageFormatToGL(QShaderImage::R16_UNorm);
+ case QAbstractTexture::RG16_UNorm:
+ return glImageFormatToGL(QShaderImage::RG16_UNorm);
+ case QAbstractTexture::RGBA16_UNorm:
+ return glImageFormatToGL(QShaderImage::RGBA16_UNorm);
+
+ case QAbstractTexture::R8_SNorm:
+ return glImageFormatToGL(QShaderImage::R8_SNorm);
+ case QAbstractTexture::RG8_SNorm:
+ return glImageFormatToGL(QShaderImage::RG8_SNorm);
+ case QAbstractTexture::RGBA8_SNorm:
+ return glImageFormatToGL(QShaderImage::RGBA8_SNorm);
+
+ case QAbstractTexture::R16_SNorm:
+ return glImageFormatToGL(QShaderImage::R16_SNorm);
+ case QAbstractTexture::RG16_SNorm:
+ return glImageFormatToGL(QShaderImage::RG16_SNorm);
+ case QAbstractTexture::RGBA16_SNorm:
+ return glImageFormatToGL(QShaderImage::RGBA16_SNorm);
+
+ case QAbstractTexture::R8U:
+ return glImageFormatToGL(QShaderImage::R8U);
+ case QAbstractTexture::RG8U:
+ return glImageFormatToGL(QShaderImage::RG8U);
+ case QAbstractTexture::RGBA8U:
+ return glImageFormatToGL(QShaderImage::RGBA8U);
+
+ case QAbstractTexture::R16U:
+ return glImageFormatToGL(QShaderImage::R16U);
+ case QAbstractTexture::RG16U:
+ return glImageFormatToGL(QShaderImage::RG16U);
+ case QAbstractTexture::RGBA16U:
+ return glImageFormatToGL(QShaderImage::RGBA16U);
+
+ case QAbstractTexture::R32U:
+ return glImageFormatToGL(QShaderImage::R32U);
+ case QAbstractTexture::RG32U:
+ return glImageFormatToGL(QShaderImage::RG32U);
+ case QAbstractTexture::RGBA32U:
+ return glImageFormatToGL(QShaderImage::RGBA32U);
+
+ case QAbstractTexture::R8I:
+ return glImageFormatToGL(QShaderImage::R8I);
+ case QAbstractTexture::RG8I:
+ return glImageFormatToGL(QShaderImage::RG8I);
+ case QAbstractTexture::RGBA8I:
+ return glImageFormatToGL(QShaderImage::RGBA8I);
+
+ case QAbstractTexture::R16I:
+ return glImageFormatToGL(QShaderImage::R16I);
+ case QAbstractTexture::RG16I:
+ return glImageFormatToGL(QShaderImage::RG16I);
+ case QAbstractTexture::RGBA16I:
+ return glImageFormatToGL(QShaderImage::RGBA16I);
+
+ case QAbstractTexture::R32I:
+ return glImageFormatToGL(QShaderImage::R32I);
+ case QAbstractTexture::RG32I:
+ return glImageFormatToGL(QShaderImage::RG32I);
+ case QAbstractTexture::RGBA32I:
+ return glImageFormatToGL(QShaderImage::RGBA32I);
+
+ case QAbstractTexture::R16F:
+ return glImageFormatToGL(QShaderImage::R16F);
+ case QAbstractTexture::RG16F:
+ return glImageFormatToGL(QShaderImage::RG16F);
+ case QAbstractTexture::RGBA16F:
+ return glImageFormatToGL(QShaderImage::RGBA16F);
+
+ case QAbstractTexture::R32F:
+ return glImageFormatToGL(QShaderImage::R32F);
+ case QAbstractTexture::RG32F:
+ return glImageFormatToGL(QShaderImage::RG32F);
+ case QAbstractTexture::RGBA32F:
+ return glImageFormatToGL(QShaderImage::RGBA32F);
+
+ case QAbstractTexture::RG11B10F:
+ return glImageFormatToGL(QShaderImage::RG11B10F);
+ case QAbstractTexture::RGB10A2:
+ return glImageFormatToGL(QShaderImage::RGB10A2);
+ case QAbstractTexture::RGB10A2U:
+ return glImageFormatToGL(QShaderImage::RGB10A2U);
+
+ default:
+ qWarning() << "Cannot map Texture format" << textureFormat << "to a valid Image Format";
+ Q_UNREACHABLE();
+ return GL_NONE;
+ }
+}
+
+} // anonymous
+
+ImageSubmissionContext::ImageSubmissionContext()
+ : m_ctx(nullptr)
+{
+}
+
+void ImageSubmissionContext::initialize(GraphicsContext *context)
+{
+ m_ctx = context;
+ m_activeImages.resize(m_ctx->maxImageUnitsCount());
+}
+
+void ImageSubmissionContext::endDrawing()
+{
+ // Reduce score of all active Images
+ decayImageScores();
+}
+
+// Return Image Unit for Image
+// If Image was used previously and recently, it will return the last used unit
+// for that image. Otherwise it will try to return the image unit the least used.
+int ImageSubmissionContext::activateImage(ShaderImage *image, GLTexture *tex)
+{
+ const int onUnit = assignUnitForImage(image->peerId());
+
+ if (onUnit < 0) {
+ qWarning() << "Unable to find available image unit";
+ return -1;
+ }
+
+ QOpenGLTexture *glTex = tex->getGLTexture();
+ if (glTex == nullptr) {
+ qWarning() << "Unable to retrieve valid texture for Image";
+ return -1;
+ }
+
+ // Bind Image against Texture and resolve Image Format
+ m_ctx->bindImageTexture(onUnit,
+ glTex->textureId(),
+ image->mipLevel(),
+ image->layered(),
+ image->layer(),
+ glAccessEnumForShaderImageAccess(image->access()),
+ glImageFormatForShaderImageFormat(image->format(),
+ tex->properties().format));
+
+ // Store information about the Texture/Image on ActiveImage for given
+ // image unit
+ m_activeImages[onUnit].shaderImageId = image->peerId();
+ m_activeImages[onUnit].texture = tex;
+ m_activeImages[onUnit].score = 200;
+ m_activeImages[onUnit].pinned = true;
+
+ return onUnit;
+}
+
+// Unset pinned Active Image and reduce their score
+void ImageSubmissionContext::deactivateImages()
+{
+ for (int u = 0, m = m_activeImages.size(); u < m; ++u) {
+ if (m_activeImages[u].pinned) {
+ m_activeImages[u].pinned = false;
+ m_activeImages[u].score = qMax(m_activeImages[u].score - 1, 0);
+ return;
+ }
+ }
+}
+
+// Reduce score of all active images (pinned or not)
+void ImageSubmissionContext::decayImageScores()
+{
+ for (int u = 0, m = m_activeImages.size(); u < m; ++u)
+ m_activeImages[u].score = qMax(m_activeImages[u].score - 1, 0);
+}
+
+int ImageSubmissionContext::assignUnitForImage(Qt3DCore::QNodeId shaderImageId)
+{
+ int lowestScoredUnit = -1;
+ int lowestScore = 0xfffffff;
+
+ const int m = m_activeImages.size();
+ for (int u = 0; u < m; ++u) {
+ if (m_activeImages[u].shaderImageId == shaderImageId)
+ return u;
+ }
+
+ for (int u = 0; u < m; ++u) {
+ // No image is currently active on the image unit
+ // we save the image unit with the texture that has been on there
+ // the longest time while not being used
+ if (!m_activeImages[u].pinned) {
+ const int score = m_activeImages[u].score;
+ if (score < lowestScore) {
+ lowestScore = score;
+ lowestScoredUnit = u;
+ }
+ }
+ }
+
+ if (lowestScoredUnit == -1)
+ qCWarning(Backend) << Q_FUNC_INFO << "No free image units!";
+
+ return lowestScoredUnit;
+}
+
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/loadtexturedatajob_p.h b/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h
index 607068712..6d39f469b 100644
--- a/src/render/jobs/loadtexturedatajob_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QT3DRENDER_RENDER_LOADTEXTUREDATAJOB_H
-#define QT3DRENDER_RENDER_LOADTEXTUREDATAJOB_H
+#ifndef QT3DRENDER_RENDER_IMAGESUBMISSIONCONTEXT_P_H
+#define QT3DRENDER_RENDER_IMAGESUBMISSIONCONTEXT_P_H
//
// W A R N I N G
@@ -51,44 +51,45 @@
// We mean it.
//
-#include <Qt3DCore/qnodeid.h>
-#include <Qt3DCore/qaspectjob.h>
-#include <Qt3DRender/qtexturegenerator.h>
-#include <Qt3DRender/qtextureimagedatagenerator.h>
+#include <Qt3DCore/QNodeId>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-
namespace Render {
-class NodeManagers;
+class GraphicsContext;
+class GLTexture;
+class ShaderImage;
-class LoadTextureDataJob : public Qt3DCore::QAspectJob
+class Q_AUTOTEST_EXPORT ImageSubmissionContext
{
public:
- LoadTextureDataJob(const QTextureGeneratorPtr &texGen);
- LoadTextureDataJob(const QTextureImageDataGeneratorPtr &imgDataGen);
- ~LoadTextureDataJob();
-
- inline void setNodeManagers(NodeManagers *manager) { m_manager = manager; }
+ ImageSubmissionContext();
-protected:
- void run() final;
+ void initialize(GraphicsContext *context);
+ void endDrawing();
+ int activateImage(ShaderImage *image, GLTexture *tex);
+ void deactivateImages();
private:
- QTextureGeneratorPtr m_texGen;
- QTextureImageDataGeneratorPtr m_imgDataGen;
-
- NodeManagers *m_manager;
+ void decayImageScores();
+ int assignUnitForImage(Qt3DCore::QNodeId shaderImageId);
+
+ struct ActiveImage
+ {
+ Qt3DCore::QNodeId shaderImageId;
+ GLTexture *texture = nullptr;
+ int score = 0;
+ bool pinned = false;
+ };
+ QVector<ActiveImage> m_activeImages;
+ GraphicsContext *m_ctx;
};
-typedef QSharedPointer<LoadTextureDataJob> LoadTextureDataJobPtr;
-
} // namespace Render
-
} // namespace Qt3DRender
QT_END_NAMESPACE
-#endif // QT3DRENDER_RENDER_LOADTEXTUREDATAJOB_H
+#endif // QT3DRENDER_RENDER_IMAGESUBMISSIONCONTEXT_P_H
diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp
index 73393d78b..4b4199820 100644
--- a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp
@@ -212,6 +212,12 @@ void applyStateHelper<MSAAEnabled>(const MSAAEnabled *state, SubmissionContext *
gc->setMSAAEnabled(std::get<0>(state->values()));
}
+template<>
+void applyStateHelper<DepthRange>(const DepthRange *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->depthRange(std::get<0>(values), std::get<1>(values));
+}
template<>
void applyStateHelper<DepthTest>(const DepthTest *state, SubmissionContext *gc)
@@ -219,6 +225,11 @@ void applyStateHelper<DepthTest>(const DepthTest *state, SubmissionContext *gc)
gc->depthTest(std::get<0>(state->values()));
}
+template<>
+void applyStateHelper<RasterMode>(const RasterMode *state, SubmissionContext *gc)
+{
+ gc->rasterMode(std::get<0>(state->values()), std::get<1>(state->values()));
+}
template<>
void applyStateHelper<NoDepthMask>(const NoDepthMask *state, SubmissionContext *gc)
@@ -226,7 +237,6 @@ void applyStateHelper<NoDepthMask>(const NoDepthMask *state, SubmissionContext *
gc->depthMask(std::get<0>(state->values()));
}
-
template<>
void applyStateHelper<CullFace>(const CullFace *state, SubmissionContext *gc)
{
@@ -379,6 +389,7 @@ void SubmissionContext::initialize()
{
GraphicsContext::initialize();
m_textureContext.initialize(this);
+ m_imageContext.initialize(this);
}
void SubmissionContext::resolveRenderTargetFormat()
@@ -469,6 +480,7 @@ void SubmissionContext::endDrawing(bool swapBuffers)
if (m_ownCurrent)
m_gl->doneCurrent();
m_textureContext.endDrawing();
+ m_imageContext.endDrawing();
}
void SubmissionContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments, GLuint defaultFboId)
@@ -854,6 +866,7 @@ void SubmissionContext::setActiveMaterial(Material *rmat)
return;
m_textureContext.deactivateTexturesWithScope(TextureSubmissionContext::TextureScopeMaterial);
+ m_imageContext.deactivateImages();
m_material = rmat;
}
@@ -911,6 +924,16 @@ void SubmissionContext::applyState(const StateVariant &stateVariant)
break;
}
+ case DepthRangeMask: {
+ applyStateHelper<DepthRange>(static_cast<const DepthRange *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case RasterModeMask: {
+ applyStateHelper<RasterMode>(static_cast<const RasterMode *>(stateVariant.constState()), this);
+ break;
+ }
+
case FrontFaceStateMask: {
applyStateHelper<FrontFace>(static_cast<const FrontFace *>(stateVariant.constState()), this);
break;
@@ -993,6 +1016,9 @@ void SubmissionContext::resetMasked(qint64 maskOfStatesToReset)
if (maskOfStatesToReset & StencilTestStateMask)
funcs->glDisable(GL_STENCIL_TEST);
+ if (maskOfStatesToReset & DepthRangeMask)
+ depthRange(0.0f, 1.0f);
+
if (maskOfStatesToReset & DepthTestStateMask)
funcs->glDisable(GL_DEPTH_TEST);
@@ -1034,6 +1060,11 @@ void SubmissionContext::resetMasked(qint64 maskOfStatesToReset)
if (maskOfStatesToReset & LineWidthMask)
funcs->glLineWidth(1.0f);
+
+#ifndef QT_OPENGL_ES_2
+ if (maskOfStatesToReset & RasterModeMask)
+ m_glHelper->rasterMode(GL_FRONT_AND_BACK, GL_FILL);
+#endif
}
void SubmissionContext::applyStateSet(RenderStateSet *ss)
@@ -1132,11 +1163,13 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
// Update the uniforms with the correct texture unit id's
PackUniformHash &uniformValues = parameterPack.uniforms();
+ // Fill Texture Uniform Value with proper texture units
+ // so that they can be applied as regular uniforms in a second step
for (int i = 0; i < parameterPack.textures().size(); ++i) {
- const ShaderParameterPack::NamedTexture &namedTex = parameterPack.textures().at(i);
+ const ShaderParameterPack::NamedResource &namedTex = parameterPack.textures().at(i);
// Given a Texture QNodeId, we retrieve the associated shared GLTexture
if (uniformValues.contains(namedTex.glslNameId)) {
- GLTexture *t = manager->glTextureManager()->lookupResource(namedTex.texId);
+ GLTexture *t = manager->glTextureManager()->lookupResource(namedTex.nodeId);
if (t != nullptr) {
UniformValue &texUniform = uniformValues[namedTex.glslNameId];
if (texUniform.valueType() == UniformValue::TextureValue) {
@@ -1146,6 +1179,34 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
if (namedTex.glslNameId != irradianceId &&
namedTex.glslNameId != specularId) {
// Only return false if we are not dealing with env light textures
+ qWarning() << "Unable to find suitable Texture Unit";
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Fill Image Uniform Value with proper image units
+ // so that they can be applied as regular uniforms in a second step
+ for (int i = 0; i < parameterPack.images().size(); ++i) {
+ const ShaderParameterPack::NamedResource &namedTex = parameterPack.images().at(i);
+ // Given a Texture QNodeId, we retrieve the associated shared GLTexture
+ if (uniformValues.contains(namedTex.glslNameId)) {
+ ShaderImage *img = manager->shaderImageManager()->lookupResource(namedTex.nodeId);
+ if (img != nullptr) {
+ GLTexture *t = manager->glTextureManager()->lookupResource(img->textureId());
+ if (t == nullptr) {
+ qWarning() << "Shader Image referencing invalid texture";
+ continue;
+ } else {
+ UniformValue &imgUniform = uniformValues[namedTex.glslNameId];
+ if (imgUniform.valueType() == UniformValue::ShaderImageValue) {
+ const int imgUnit = m_imageContext.activateImage(img, t);
+ imgUniform.data<int>()[namedTex.uniformArrayIndex] = imgUnit;
+ if (imgUnit == -1) {
+ qWarning() << "Unable to bind Image to Texture";
return false;
}
}
@@ -1201,8 +1262,10 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
// be un activeUniforms if there wasn't a matching value
const UniformValue &v = values[uniform.m_nameId];
- // skip invalid textures
- if (v.valueType() == UniformValue::TextureValue && *v.constData<int>() == -1)
+ // skip invalid textures/images
+ if ((v.valueType() == UniformValue::TextureValue ||
+ v.valueType() == UniformValue::ShaderImageValue) &&
+ *v.constData<int>() == -1)
continue;
applyUniform(uniform, v);
diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h
index 844e62f15..a8700dd3a 100644
--- a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h
@@ -55,6 +55,7 @@
#include <Qt3DRender/private/graphicscontext_p.h>
#include <Qt3DRender/private/texturesubmissioncontext_p.h>
+#include <Qt3DRender/private/imagesubmissioncontext_p.h>
#include <Qt3DRender/qclearbuffers.h>
#include <Qt3DRender/private/glbuffer_p.h>
#include <Qt3DRender/qattribute.h>
@@ -204,6 +205,7 @@ private:
QByteArray m_uboTempArray;
TextureSubmissionContext m_textureContext;
+ ImageSubmissionContext m_imageContext;
// Attributes
friend class OpenGLVertexArrayObject;
diff --git a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp
index d8f27d1cd..cc211ba68 100644
--- a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp
+++ b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp
@@ -180,9 +180,9 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
break;
}
- case FrameGraphNode::SubtreeSelector:
- // Has no meaning here. SubtreeSelector was used
- // in a prior step to build the list of RenderViewJobs
+ case FrameGraphNode::SubtreeEnabler:
+ // Has no meaning here. SubtreeEnabler was used
+ // in a prior step to filter the list of RenderViewJobs
break;
case FrameGraphNode::StateSet: {
@@ -286,6 +286,10 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
break;
}
+ case FrameGraphNode::NoPicking:
+ // Nothing to do RenderView wise for NoPicking
+ break;
+
default:
// Should never get here
qCWarning(Backend) << "Unhandled FrameGraphNode type";
@@ -508,27 +512,24 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(ShaderData *
// If the property needs to be transformed, we transform it here as
// the shaderdata cannot hold transformed properties for multiple
// thread contexts at once
- if (currentShaderData->propertyTransformType(qmlPropertyName) != ShaderData::NoTransform)
- activeUniformNamesToValue.insert(StringToInt::lookupId(varName),
- currentShaderData->getTransformedProperty(qmlPropertyName, viewMatrix));
- else
- activeUniformNamesToValue.insert(StringToInt::lookupId(varName), value);
+ activeUniformNamesToValue.insert(StringToInt::lookupId(varName),
+ currentShaderData->getTransformedProperty(qmlPropertyName, viewMatrix));
}
}
}
void UniformBlockValueBuilder::buildActiveUniformNameValueMapStructHelper(ShaderData *rShaderData, const QString &blockName, const QString &qmlPropertyName)
{
- const QHash<QString, QVariant> &properties = rShaderData->properties();
- QHash<QString, QVariant>::const_iterator it = properties.begin();
- const QHash<QString, QVariant>::const_iterator end = properties.end();
+ const QHash<QString, ShaderData::PropertyValue> &properties = rShaderData->properties();
+ auto it = properties.begin();
+ const auto end = properties.end();
while (it != end) {
const auto prefix = qmlPropertyName.isEmpty() ? QLatin1String("") : QLatin1String(".");
buildActiveUniformNameValueMapHelper(rShaderData,
blockName + prefix + qmlPropertyName,
it.key(),
- it.value());
+ it.value().value);
++it;
}
}
diff --git a/src/render/renderers/opengl/opengl.pri b/src/render/renderers/opengl/opengl.pri
index 22a32d30f..908c23c80 100644
--- a/src/render/renderers/opengl/opengl.pri
+++ b/src/render/renderers/opengl/opengl.pri
@@ -6,9 +6,6 @@ include (textures/textures.pri)
include (graphicshelpers/graphicshelpers.pri)
include (renderstates/renderstates.pri)
-# Qt3D is free of Q_FOREACH - make sure it stays that way:
-DEFINES += QT_NO_FOREACH
-
gcov {
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
diff --git a/src/render/renderers/opengl/renderer/commandthread.cpp b/src/render/renderers/opengl/renderer/commandthread.cpp
deleted file mode 100644
index 70ab964d6..000000000
--- a/src/render/renderers/opengl/renderer/commandthread.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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 "commandthread_p.h"
-#include <Qt3DRender/private/glcommands_p.h>
-#include <Qt3DRender/private/offscreensurfacehelper_p.h>
-#include <Qt3DRender/private/graphicscontext_p.h>
-#include <Qt3DRender/private/shadercache_p.h>
-#include <QOpenGLContext>
-#include <QOffscreenSurface>
-#include <QDebug>
-
-QT_BEGIN_NAMESPACE
-
-namespace Qt3DRender {
-
-namespace Render {
-
-CommandThread::CommandThread(Renderer *renderer)
- : QThread()
- , m_renderer(renderer)
- , m_waitForStartSemaphore(0)
- , m_initializedSemaphore(0)
- , m_commandRequestedSemaphore(0)
- , m_commandExecutionSemaphore(0)
- , m_mainContext(nullptr)
- , m_shaderCache(nullptr)
- , m_offsreenSurfaceHelper(nullptr)
- , m_currentCommand(nullptr)
- , m_running(0)
-{
-}
-
-CommandThread::~CommandThread()
-{
- Q_ASSERT(!isRunning());
-}
-
-void CommandThread::setShaderCache(ShaderCache *shaderCache)
-{
- m_shaderCache = shaderCache;
-}
-
-// Called by RenderThread or MainThread (Scene3d)
-void CommandThread::initialize(QOpenGLContext *mainContext, OffscreenSurfaceHelper *offsreenSurfaceHelper)
-{
- // Start the thread
- start();
-
- // Wait for thread to be started
- m_waitForStartSemaphore.acquire();
-
- m_mainContext = mainContext;
- m_offsreenSurfaceHelper = offsreenSurfaceHelper;
- Q_ASSERT(m_mainContext && offsreenSurfaceHelper);
-
- // Initialize shared context and resources for the thread. This must be
- // done here since some platforms do not allow context sharing to be set up
- // with contexts created on different threads. (Windows with WGL, in
- // particular; resource sharing works fine later on, what matters is the
- // thread the wglShareLists call is made on)
- m_localContext.reset(new QOpenGLContext());
- m_localContext->setFormat(m_mainContext->format());
- m_localContext->setScreen(m_mainContext->screen());
- m_localContext->setShareContext(m_mainContext);
- if (!m_localContext->create())
- qWarning("CommandThread: Failed to create local context");
- m_localContext->moveToThread(this);
-
- m_running.fetchAndStoreOrdered(1);
-
- // Allow thread to proceed
- m_initializedSemaphore.release();
-}
-
-// Called by RenderThread or MainThread (Scene3D)
-void CommandThread::shutdown()
-{
- m_running.fetchAndStoreOrdered(0);
-
- // Unblock thread
- m_commandRequestedSemaphore.release(1);
-
- // Wait for thread to exit
- wait();
-
- // Reset semaphores (in case we ever want to restart)
- m_waitForStartSemaphore.acquire(m_waitForStartSemaphore.available());
- m_initializedSemaphore.acquire(m_initializedSemaphore.available());
- m_commandRequestedSemaphore.acquire(m_commandRequestedSemaphore.available());
- m_commandExecutionSemaphore.acquire(m_commandExecutionSemaphore.available());
- m_localContext.reset();
-}
-
-// Any thread can call this, this is a blocking command
-void CommandThread::executeCommand(GLCommand *command)
-{
- if (!isRunning())
- return;
-
- // We lock to prevent any other call to executeCommand to be executed
- // before we have received the result of our command
- m_blockingCallerMutex.lock();
-
- // Store command to be executed
- m_currentCommand = command;
-
- // Allow thread to proceed and execute command
- m_commandRequestedSemaphore.release();
-
- // Wait for thread to be done
- m_commandExecutionSemaphore.acquire();
-
- // Reset command
- m_currentCommand = nullptr;
-
- // Unlock blocking semaphore so that other calls to executeCommand
- // can proceed
- m_blockingCallerMutex.unlock();
-}
-
-void CommandThread::run()
-{
- // Allow initialize to proceed
- m_waitForStartSemaphore.release();
-
- // Wait for initialize to be completed
- m_initializedSemaphore.acquire();
-
- Q_ASSERT(m_mainContext && m_shaderCache);
-
- // Initialize GraphicsContext
- m_graphicsContext.reset(new GraphicsContext());
- m_graphicsContext->setShaderCache(m_shaderCache);
- m_graphicsContext->setOpenGLContext(m_localContext.data());
-
- bool initialized = false;
- while (true) {
-
- // Wait for command
- m_commandRequestedSemaphore.acquire();
-
- // Are we still running?
- if (!m_running.load()) {
- m_graphicsContext->doneCurrent();
- // to prevent executeCommand being locked
- m_commandExecutionSemaphore.release();
- break;
- }
-
- if (Q_UNLIKELY(!initialized)) {
- QOffscreenSurface *offscreenSurface = m_offsreenSurfaceHelper->offscreenSurface();
- Q_ASSERT(offscreenSurface);
- m_graphicsContext->makeCurrent(offscreenSurface);
- initialized = true;
- }
-
- m_currentCommand->execute(m_renderer, m_graphicsContext.data());
-
- // Allow caller to proceed as we are done with the command
- m_commandExecutionSemaphore.release();
- }
-}
-
-} // Render
-
-} // Qt3DRender
-
-QT_END_NAMESPACE
diff --git a/src/render/renderers/opengl/renderer/rendercommand_p.h b/src/render/renderers/opengl/renderer/rendercommand_p.h
index 67e02d35b..61cc6d17d 100644
--- a/src/render/renderers/opengl/renderer/rendercommand_p.h
+++ b/src/render/renderers/opengl/renderer/rendercommand_p.h
@@ -89,7 +89,7 @@ public:
// A QAttribute pack might be interesting
// This is a temporary fix in the meantime, to remove the hacked methods in Technique
- QVector<int> m_attributes;
+ QVector<int> m_activeAttributes;
float m_depth;
int m_changeCost;
@@ -103,7 +103,7 @@ public:
CommandType m_type;
int m_workGroups[3];
- // Values filled for draw calls
+ // Values filled for draw calls by Renderer (in prepare Submission)
GLsizei m_primitiveCount;
QGeometryRenderer::PrimitiveType m_primitiveType;
int m_restartIndexValue;
diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp
index 0a79df501..121a6aa8f 100644
--- a/src/render/renderers/opengl/renderer/renderer.cpp
+++ b/src/render/renderers/opengl/renderer/renderer.cpp
@@ -89,14 +89,15 @@
#include <Qt3DRender/private/buffercapture_p.h>
#include <Qt3DRender/private/offscreensurfacehelper_p.h>
#include <Qt3DRender/private/renderviewbuilder_p.h>
-#include <Qt3DRender/private/commandthread_p.h>
-#include <Qt3DRender/private/glcommands_p.h>
#include <Qt3DRender/private/setfence_p.h>
+#include <Qt3DRender/private/subtreeenabler_p.h>
+#include <Qt3DRender/private/qshaderprogrambuilder_p.h>
+#include <Qt3DRender/private/qshaderprogram_p.h>
#include <Qt3DRender/qcameralens.h>
#include <Qt3DCore/private/qeventfilterservice_p.h>
#include <Qt3DCore/private/qabstractaspectjobmanager_p.h>
-#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/private/qaspectmanager_p.h>
#if QT_CONFIG(qt3d_profile_jobs)
#include <Qt3DCore/private/aspectcommanddebugger_p.h>
@@ -165,7 +166,6 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_submissionContext(nullptr)
, m_renderQueue(new RenderQueue())
, m_renderThread(type == QRenderAspect::Threaded ? new RenderThread(this) : nullptr)
- , m_commandThread(new CommandThread(this))
, m_vsyncFrameAdvanceService(new VSyncFrameAdvanceService(m_renderThread != nullptr))
, m_waitForInitializationToBeCompleted(0)
, m_hasBeenInitializedMutex()
@@ -193,16 +193,21 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create())
, m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create())
, m_updateEntityLayersJob(Render::UpdateEntityLayersJobPtr::create())
- , m_updateEntityHierarchyJob(Render::UpdateEntityHierarchyJobPtr::create())
- , m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering))
- , m_vaoGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering))
- , m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering))
- , m_sendTextureChangesToFrontendJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { sendTextureChangesToFrontend(); }, JobTypes::SendTextureChangesToFrontend))
- , m_sendSetFenceHandlesToFrontendJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { sendSetFenceHandlesToFrontend(); }, JobTypes::SendSetFenceHandlesToFrontend))
- , m_introspectShaderJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { reloadDirtyShaders(); }, JobTypes::DirtyShaderGathering))
- , m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading))
+ , m_bufferGathererJob(SynchronizerJobPtr::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering))
+ , m_vaoGathererJob(SynchronizerJobPtr::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering))
+ , m_textureGathererJob(SynchronizerJobPtr::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering))
+ , m_sendTextureChangesToFrontendJob(SynchronizerPostFramePtr::create([] {},
+ [this] (Qt3DCore::QAspectManager *m) { sendTextureChangesToFrontend(m); },
+ JobTypes::SendTextureChangesToFrontend))
+ , m_sendSetFenceHandlesToFrontendJob(SynchronizerJobPtr::create([this] { sendSetFenceHandlesToFrontend(); }, JobTypes::SendSetFenceHandlesToFrontend))
+ , m_sendDisablesToFrontendJob(SynchronizerJobPtr::create([this] { sendDisablesToFrontend(); }, JobTypes::SendDisablesToFrontend))
+ , m_introspectShaderJob(SynchronizerPostFramePtr::create([this] { reloadDirtyShaders(); },
+ [this] (Qt3DCore::QAspectManager *m) { sendShaderChangesToFrontend(m); },
+ JobTypes::DirtyShaderGathering))
+ , m_syncLoadingJobs(SynchronizerJobPtr::create([] {}, JobTypes::SyncLoadingJobs))
, m_ownedContext(false)
, m_offscreenHelper(nullptr)
+ , m_shouldSwapBuffers(true)
#if QT_CONFIG(qt3d_profile_jobs)
, m_commandExecuter(new Qt3DRender::Debug::CommandExecuter(this))
#endif
@@ -213,9 +218,6 @@ Renderer::Renderer(QRenderAspect::RenderType type)
if (m_renderThread)
m_renderThread->waitForStart();
- m_worldTransformJob->addDependency(m_updateEntityHierarchyJob);
- m_updateEntityLayersJob->addDependency(m_updateEntityHierarchyJob);
-
// Create jobs to update transforms and bounding volumes
// We can only update bounding volumes once all world transforms are known
m_updateWorldBoundingVolumeJob->addDependency(m_worldTransformJob);
@@ -226,12 +228,8 @@ Renderer::Renderer(QRenderAspect::RenderType type)
m_rayCastingJob->addDependency(m_expandBoundingVolumeJob);
// m_calculateBoundingVolumeJob's dependency on m_updateTreeEnabledJob is set in renderBinJobs
- // Dirty texture gathering depends on m_syncTextureLoadingJob
- // m_syncTextureLoadingJob will depend on the texture loading jobs
- m_textureGathererJob->addDependency(m_syncTextureLoadingJob);
-
// Ensures all skeletons are loaded before we try to update them
- m_updateSkinningPaletteJob->addDependency(m_syncTextureLoadingJob);
+ m_updateSkinningPaletteJob->addDependency(m_syncLoadingJobs);
// All world stuff depends on the RenderEntity's localBoundingVolume
m_updateLevelOfDetailJob->addDependency(m_updateMeshTriangleListJob);
@@ -308,7 +306,6 @@ void Renderer::setNodeManagers(NodeManagers *managers)
m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager());
m_updateEntityLayersJob->setManager(m_nodesManager);
m_updateTreeEnabledJob->setManagers(m_nodesManager);
- m_updateEntityHierarchyJob->setManager(m_nodesManager);
}
void Renderer::setServices(QServiceLocator *services)
@@ -338,18 +335,11 @@ QOpenGLContext *Renderer::shareContext() const
: nullptr);
}
-// Executed in the command thread
+// Executed in the reloadDirtyShader job
void Renderer::loadShader(Shader *shader, HShader shaderHandle)
{
-#ifdef SHADER_LOADING_IN_COMMAND_THREAD
- Q_UNUSED(shaderHandle);
- Profiling::GLTimeRecorder recorder(Profiling::ShaderUpload);
- LoadShaderCommand cmd(shader);
- m_commandThread->executeCommand(&cmd);
-#else
Q_UNUSED(shader);
m_dirtyShaders.push_back(shaderHandle);
-#endif
}
void Renderer::setOpenGLContext(QOpenGLContext *context)
@@ -424,7 +414,6 @@ void Renderer::initialize()
// Set shader cache on submission context and command thread
m_submissionContext->setShaderCache(m_shaderCache);
- m_commandThread->setShaderCache(m_shaderCache);
// Note: we don't have a surface at this point
// The context will be made current later on (at render time)
@@ -437,13 +426,6 @@ void Renderer::initialize()
// (MS Windows), an offscreen surface is just a hidden QWindow.
m_format = ctx->format();
QMetaObject::invokeMethod(m_offscreenHelper, "createOffscreenSurface");
-
- // Initialize command thread (uses the offscreen surface to make its own ctx current)
- m_commandThread->initialize(ctx, m_offscreenHelper);
- // Note: the offscreen surface is also used at shutdown time to release resources
- // of the submission gl context (when the window is already gone).
- // By that time (in releaseGraphicResources), the commandThread has been destroyed
- // and the offscreenSurface can be reused
}
// Awake setScenegraphRoot in case it was waiting
@@ -466,7 +448,7 @@ void Renderer::shutdown()
QMutexLocker lock(&m_hasBeenInitializedMutex);
qCDebug(Backend) << Q_FUNC_INFO << "Requesting renderer shutdown";
- m_running.store(0);
+ m_running.storeRelaxed(0);
// We delete any renderqueue that we may not have had time to render
// before the surface was destroyed
@@ -475,8 +457,6 @@ void Renderer::shutdown()
m_renderQueue->reset();
lockRenderQueue.unlock();
- m_commandThread->shutdown();
-
if (!m_renderThread) {
releaseGraphicsResources();
} else {
@@ -524,9 +504,11 @@ void Renderer::releaseGraphicsResources()
if (context->thread() == QThread::currentThread() && context->makeCurrent(offscreenSurface)) {
// Clean up the graphics context and any resources
- const QVector<GLTexture*> activeTextures = m_nodesManager->glTextureManager()->activeResources();
- for (GLTexture *tex : activeTextures)
- tex->destroyGLTexture();
+ const QVector<HGLTexture> activeTexturesHandles = m_nodesManager->glTextureManager()->activeHandles();
+ for (const HGLTexture &textureHandle : activeTexturesHandles) {
+ GLTexture *tex = m_nodesManager->glTextureManager()->data(textureHandle);
+ tex->destroy();
+ }
// Do the same thing with buffers
const QVector<HGLBuffer> activeBuffers = m_nodesManager->glBufferManager()->activeHandles();
@@ -576,10 +558,9 @@ Render::FrameGraphNode *Renderer::frameGraphRoot() const
// 2) setSceneRoot waits to acquire initialization
// 3) submitRenderView -> check for surface
// -> make surface current + create proper glHelper if needed
-void Renderer::setSceneRoot(QBackendNodeFactory *factory, Entity *sgRoot)
+void Renderer::setSceneRoot(Entity *sgRoot)
{
Q_ASSERT(sgRoot);
- Q_UNUSED(factory);
// If initialization hasn't been completed we must wait
m_waitForInitializationToBeCompleted.acquire();
@@ -637,41 +618,30 @@ void Renderer::render()
// One scene description
// One framegraph description
- while (m_running.load() > 0) {
+ while (m_running.loadRelaxed() > 0) {
doRender();
// TO DO: Restore windows exposed detection
// Probably needs to happens some place else though
}
}
-void Renderer::doRender(bool scene3dBlocking)
+// Either called by render if Qt3D is in charge of the RenderThread
+// or by QRenderAspectPrivate::renderSynchronous (for Scene3D)
+void Renderer::doRender(bool swapBuffers)
{
Renderer::ViewSubmissionResultData submissionData;
bool hasCleanedQueueAndProceeded = false;
bool preprocessingComplete = false;
bool beganDrawing = false;
+
+ // Blocking until RenderQueue is full
const bool canSubmit = isReadyToSubmit();
+ m_shouldSwapBuffers = swapBuffers;
// Lock the mutex to protect access to the renderQueue while we look for its state
QMutexLocker locker(m_renderQueue->mutex());
- bool queueIsComplete = m_renderQueue->isFrameQueueComplete();
- bool queueIsEmpty = m_renderQueue->targetRenderViewCount() == 0;
-
- // Scene3D Blocking Mode
- if (scene3dBlocking && !queueIsComplete && !queueIsEmpty) {
- int i = 0;
- // We wait at most 10ms to avoid a case we could never recover from
- while (!queueIsComplete && !queueIsEmpty && i++ < 10) {
- qCDebug(Backend) << Q_FUNC_INFO << "Waiting for ready queue (try:" << i << "/ 10)";
- locker.unlock();
- // Give worker threads a chance to complete the queue
- QThread::msleep(1);
- locker.relock();
- queueIsComplete = m_renderQueue->isFrameQueueComplete();
- // This could become true if we've tried to shutdown
- queueIsEmpty = m_renderQueue->targetRenderViewCount() == 0;
- }
- }
+ const bool queueIsComplete = m_renderQueue->isFrameQueueComplete();
+ const bool queueIsEmpty = m_renderQueue->targetRenderViewCount() == 0;
// When using synchronous rendering (QtQuick)
// We are not sure that the frame queue is actually complete
@@ -768,16 +738,12 @@ void Renderer::doRender(bool scene3dBlocking)
#endif
}
- // Only reset renderQueue and proceed to next frame if the submission
- // succeeded or if we are using a render thread and that is wasn't performed
- // already
-
// If hasCleanedQueueAndProceeded isn't true this implies that something went wrong
// with the rendering and/or the renderqueue is incomplete from some reason
- // (in the case of scene3d the render jobs may be taking too long ....)
// or alternatively it could be complete but empty (RenderQueue of size 0)
- if (!hasCleanedQueueAndProceeded &&
- (m_renderThread || queueIsComplete || queueIsEmpty)) {
+
+
+ if (!hasCleanedQueueAndProceeded) {
// RenderQueue was full but something bad happened when
// trying to render it and therefore proceedToNextFrame was not called
// Note: in this case the renderQueue mutex is still locked
@@ -800,7 +766,10 @@ void Renderer::doRender(bool scene3dBlocking)
if (beganDrawing) {
SurfaceLocker surfaceLock(submissionData.surface);
// Finish up with last surface used in the list of RenderViews
- m_submissionContext->endDrawing(submissionData.lastBoundFBOId == m_submissionContext->defaultFBO() && surfaceLock.isSurfaceValid());
+ const bool swapBuffers = submissionData.lastBoundFBOId == m_submissionContext->defaultFBO()
+ && surfaceLock.isSurfaceValid()
+ && m_shouldSwapBuffers;
+ m_submissionContext->endDrawing(swapBuffers);
}
}
@@ -819,7 +788,7 @@ void Renderer::enqueueRenderView(Render::RenderView *renderView, int submitOrder
const bool isQueueComplete = m_renderQueue->queueRenderView(renderView, submitOrder);
locker.unlock(); // We're done protecting the queue at this point
if (isQueueComplete) {
- if (m_renderThread && m_running.load())
+ if (m_renderThread && m_running.loadRelaxed())
Q_ASSERT(m_submitRenderViewsSemaphore.available() == 0);
m_submitRenderViewsSemaphore.release(1);
}
@@ -828,7 +797,7 @@ void Renderer::enqueueRenderView(Render::RenderView *renderView, int submitOrder
bool Renderer::canRender() const
{
// Make sure that we've not been told to terminate
- if (m_renderThread && !m_running.load()) {
+ if (m_renderThread && !m_running.loadRelaxed()) {
qCDebug(Rendering) << "RenderThread termination requested whilst waiting";
return false;
}
@@ -842,21 +811,19 @@ bool Renderer::canRender() const
bool Renderer::isReadyToSubmit()
{
- // If we are using a render thread, make sure that
- // we've been told to render before rendering
- if (m_renderThread) { // Prevent ouf of order execution
- m_submitRenderViewsSemaphore.acquire(1);
+ // Make sure that we've been told to render before rendering
+ // Prevent ouf of order execution
+ m_submitRenderViewsSemaphore.acquire(1);
- // Check if shutdown has been requested
- if (m_running.load() == 0)
- return false;
+ // Check if shutdown has been requested
+ if (m_running.loadRelaxed() == 0)
+ return false;
- // When using Thread rendering, the semaphore should only
- // be released when the frame queue is complete and there's
- // something to render
- // The case of shutdown should have been handled just before
- Q_ASSERT(m_renderQueue->isFrameQueueComplete());
- }
+ // The semaphore should only
+ // be released when the frame queue is complete and there's
+ // something to render
+ // The case of shutdown should have been handled just before
+ Q_ASSERT(m_renderQueue->isFrameQueueComplete());
return true;
}
@@ -931,7 +898,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
if (rGeometry->isDirty())
m_dirtyGeometry.push_back(rGeometry);
- if (!command->m_attributes.isEmpty() && (requiresFullVAOUpdate || requiresPartialVAOUpdate)) {
+ if (!command->m_activeAttributes.isEmpty() && (requiresFullVAOUpdate || requiresPartialVAOUpdate)) {
Profiling::GLTimeRecorder recorder(Profiling::VAOUpload);
// Activate shader
m_submissionContext->activateShader(shader->dna());
@@ -953,9 +920,8 @@ 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
- command->m_isValid = !command->m_attributes.empty();
+ command->m_isValid = !command->m_activeAttributes.empty();
if (!command->m_isValid)
continue;
@@ -976,7 +942,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
indirectAttribute = attribute;
break;
case QAttribute::VertexAttribute: {
- if (command->m_attributes.contains(attribute->nameId()))
+ if (command->m_activeAttributes.contains(attribute->nameId()))
estimatedCount = qMax(attribute->count(), estimatedCount);
break;
}
@@ -1157,45 +1123,22 @@ void Renderer::reloadDirtyShaders()
if (shaderBuilder) {
shaderBuilder->setGraphicsApi(*technique->graphicsApiFilter());
- for (int i = 0; i <= ShaderBuilder::Compute; i++) {
- const auto builderType = static_cast<ShaderBuilder::ShaderType>(i);
- if (!shaderBuilder->shaderGraph(builderType).isValid())
+ for (int i = 0; i <= QShaderProgram::Compute; i++) {
+ const auto shaderType = static_cast<QShaderProgram::ShaderType>(i);
+ if (!shaderBuilder->shaderGraph(shaderType).isValid())
continue;
- if (shaderBuilder->isShaderCodeDirty(builderType)) {
- shaderBuilder->generateCode(builderType);
- }
-
- QShaderProgram::ShaderType shaderType = QShaderProgram::Vertex;
- switch (builderType) {
- case ShaderBuilder::Vertex:
- shaderType = QShaderProgram::Vertex;
- break;
- case ShaderBuilder::TessellationControl:
- shaderType = QShaderProgram::TessellationControl;
- break;
- case ShaderBuilder::TessellationEvaluation:
- shaderType = QShaderProgram::TessellationEvaluation;
- break;
- case ShaderBuilder::Geometry:
- shaderType = QShaderProgram::Geometry;
- break;
- case ShaderBuilder::Fragment:
- shaderType = QShaderProgram::Fragment;
- break;
- case ShaderBuilder::Compute:
- shaderType = QShaderProgram::Compute;
- break;
+ if (shaderBuilder->isShaderCodeDirty(shaderType)) {
+ shaderBuilder->generateCode(shaderType);
+ m_shaderBuilderUpdates.append(shaderBuilder->takePendingUpdates());
}
- const auto code = shaderBuilder->shaderCode(builderType);
+ const auto code = shaderBuilder->shaderCode(shaderType);
shader->setShaderCode(shaderType, code);
}
}
- if (Q_UNLIKELY(shader->hasPendingNotifications()))
- shader->submitPendingNotifications();
- // If the shader hasn't be loaded, load it
+ // If the shader hasn't been loaded, load it
if (shader != nullptr && !shader->isLoaded())
loadShader(shader, shaderHandle);
}
@@ -1203,24 +1146,66 @@ void Renderer::reloadDirtyShaders()
}
}
-// Executed in a job
-void Renderer::sendTextureChangesToFrontend()
+// Executed in job postFrame
+void Renderer::sendShaderChangesToFrontend(Qt3DCore::QAspectManager *manager)
+{
+ Q_ASSERT(isRunning());
+
+ // Sync Shader
+ const QVector<HShader> activeShaders = m_nodesManager->shaderManager()->activeHandles();
+ for (const HShader &handle :activeShaders) {
+ Shader *s = m_nodesManager->shaderManager()->data(handle);
+ if (s->requiresFrontendSync()) {
+ QShaderProgram *frontend = static_cast<decltype(frontend)>(manager->lookupNode(s->peerId()));
+ QShaderProgramPrivate *dFrontend = static_cast<decltype(dFrontend)>(QNodePrivate::get(frontend));
+ s->unsetRequiresFrontendSync();
+ dFrontend->setStatus(s->status());
+ dFrontend->setLog(s->log());
+ }
+ }
+
+ // Sync ShaderBuilder
+ const QVector<ShaderBuilderUpdate> shaderBuilderUpdates = std::move(m_shaderBuilderUpdates);
+ for (const ShaderBuilderUpdate &update : shaderBuilderUpdates) {
+ QShaderProgramBuilder *builder = static_cast<decltype(builder)>(manager->lookupNode(update.builderId));
+ QShaderProgramBuilderPrivate *dBuilder = static_cast<decltype(dBuilder)>(QNodePrivate::get(builder));
+ dBuilder->setShaderCode(update.shaderCode, update.shaderType);
+ }
+}
+
+// Executed in a job (as postFrame)
+void Renderer::sendTextureChangesToFrontend(Qt3DCore::QAspectManager *manager)
{
const QVector<QPair<Texture::TextureUpdateInfo, Qt3DCore::QNodeIdVector>> updateTextureProperties = std::move(m_updatedTextureProperties);
for (const auto &pair : updateTextureProperties) {
- // Prepare change notification
-
const Qt3DCore::QNodeIdVector targetIds = pair.second;
for (const Qt3DCore::QNodeId targetId: targetIds) {
+
// Lookup texture
Texture *t = m_nodesManager->textureManager()->lookupResource(targetId);
+ // If backend texture is Dirty, some property has changed and the properties we are
+ // about to send are already outdate
+ if (t == nullptr || t->dirtyFlags() != Texture::NotDirty)
+ continue;
- // Texture might have been deleted between previous and current frame
- if (t == nullptr)
+ QAbstractTexture *texture = static_cast<QAbstractTexture *>(manager->lookupNode(targetId));
+ if (!texture)
continue;
+ const TextureProperties &properties = pair.first.properties;
- // Send change and update backend
- t->updatePropertiesAndNotify(pair.first);
+ const bool blocked = texture->blockNotifications(true);
+ texture->setWidth(properties.width);
+ texture->setHeight(properties.height);
+ texture->setDepth(properties.depth);
+ texture->setLayers(properties.layers);
+ texture->setFormat(properties.format);
+ texture->blockNotifications(blocked);
+
+ QAbstractTexturePrivate *dTexture = static_cast<QAbstractTexturePrivate *>(QNodePrivate::get(texture));
+
+ dTexture->setStatus(properties.status);
+ dTexture->setHandleType(pair.first.handleType);
+ dTexture->setHandle(pair.first.handle);
}
}
}
@@ -1241,6 +1226,21 @@ void Renderer::sendSetFenceHandlesToFrontend()
}
}
+// Executed in a job
+void Renderer::sendDisablesToFrontend()
+{
+ const auto updatedDisables = std::move(m_updatedDisables);
+ FrameGraphManager *fgManager = m_nodesManager->frameGraphManager();
+ for (const auto &nodeId : updatedDisables) {
+ FrameGraphNode *fgNode = fgManager->lookupNode(nodeId);
+ if (fgNode != nullptr) { // Node could have been deleted before we got a chance to notify it
+ Q_ASSERT(fgNode->nodeType() == FrameGraphNode::SubtreeEnabler);
+ SubtreeEnabler *enabler = static_cast<SubtreeEnabler *>(fgNode);
+ enabler->sendDisableToFrontend();
+ }
+ }
+}
+
// Render Thread (or QtQuick RenderThread when using Scene3D)
// Scene3D: When using Scene3D rendering, we can't assume that when
// updateGLResources is called, the resource handles points to still existing
@@ -1320,7 +1320,8 @@ void Renderer::updateGLResources()
if (texture == nullptr)
continue;
- // Create or Update GLTexture
+ // Create or Update GLTexture (the GLTexture instance is created if required
+ // and all things that can take place without a GL context are done here)
updateTexture(texture);
}
// We want to upload textures data at this point as the SubmissionThread and
@@ -1328,15 +1329,18 @@ void Renderer::updateGLResources()
// GLTexture
if (m_submissionContext != nullptr) {
GLTextureManager *glTextureManager = m_nodesManager->glTextureManager();
- const QVector<GLTexture *> glTextures = glTextureManager->activeResources();
+ const QVector<HGLTexture> glTextureHandles = glTextureManager->activeHandles();
// Upload texture data
- for (GLTexture *glTexture : glTextures) {
+ for (const HGLTexture &glTextureHandle : glTextureHandles) {
+ GLTexture *glTexture = glTextureManager->data(glTextureHandle);
+
+ // We create/update the actual GL texture using the GL context at this point
const GLTexture::TextureUpdateInfo info = glTexture->createOrUpdateGLTexture();
// GLTexture creation provides us width/height/format ... information
// for textures which had not initially specified these information (TargetAutomatic...)
// Gather these information and store them to be distributed by a change next frame
- const QNodeIdVector referenceTextureIds = glTextureManager->referencedTextureIds(glTexture);
+ const QNodeIdVector referenceTextureIds = { glTextureManager->texNodeIdForGLTexture.value(glTexture) };
// Store properties and referenceTextureIds
if (info.wasUpdated) {
Texture::TextureUpdateInfo updateInfo;
@@ -1347,14 +1351,10 @@ void Renderer::updateGLResources()
}
}
}
+
+ // Record ids of texture to cleanup while we are still blocking the aspect thread
+ m_textureIdsToCleanup += m_nodesManager->textureManager()->takeTexturesIdsToCleanup();
}
- // When Textures are cleaned up, their id is saved so that they can be
- // cleaned up in the render thread Note: we perform this step in second so
- // that the previous updateTexture call has a chance to find a shared
- // texture and avoid possible destroying recreating a new texture
- const QVector<Qt3DCore::QNodeId> cleanedUpTextureIds = m_nodesManager->textureManager()->takeTexturesIdsToCleanup();
- for (const Qt3DCore::QNodeId textureCleanedUpId: cleanedUpTextureIds)
- cleanupTexture(textureCleanedUpId);
}
// Render Thread
@@ -1362,92 +1362,60 @@ void Renderer::updateTexture(Texture *texture)
{
// Check that the current texture images are still in place, if not, do not update
const bool isValid = texture->isValid(m_nodesManager->textureImageManager());
- if (!isValid)
+ if (!isValid) {
+ qWarning() << Q_FUNC_INFO << "QTexture referencing invalid QTextureImages";
return;
-
- // For implementing unique, non-shared, non-cached textures.
- // for now, every texture is shared by default except if:
- // - texture is reference by a render attachment
- // - texture is referencing a shared texture id
- bool isUnique = texture->sharedTextureId() > 0;
-
- if (!isUnique) {
- // 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;
- }
- }
}
+ // All textures are unique, if you instanciate twice the exact same texture
+ // this will create 2 identical GLTextures, no sharing will take place
+
// Try to find the associated GLTexture for the backend Texture
GLTextureManager *glTextureManager = m_nodesManager->glTextureManager();
GLTexture *glTexture = glTextureManager->lookupResource(texture->peerId());
- auto createOrUpdateGLTexture = [=] () {
- if (isUnique)
- glTextureManager->createUnique(texture);
- else
- glTextureManager->getOrCreateShared(texture);
- texture->unsetDirty();
- };
-
// No GLTexture associated yet -> create it
if (glTexture == nullptr) {
- createOrUpdateGLTexture();
- 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->peerId());
- // Note: if isUnique is true, a once shared texture will become unique
- createOrUpdateGLTexture();
- 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->peerId());
- glTextureManager->adoptShared(newSharedTex, texture);
- texture->unsetDirty();
- return;
- }
+ glTexture = glTextureManager->getOrCreateResource(texture->peerId());
+ glTextureManager->texNodeIdForGLTexture.insert(glTexture, texture->peerId());
}
- // we hold a reference to a unique or exclusive access to a shared texture
- // we can thus modify the texture directly.
+ // Update GLTexture to match Texture instance
const Texture::DirtyFlags dirtyFlags = texture->dirtyFlags();
- if (dirtyFlags.testFlag(Texture::DirtySharedTextureId) &&
- !glTextureManager->setSharedTextureId(glTexture, texture->sharedTextureId()))
- qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setSharedTextureId failed, should be non-shared";
+ if (dirtyFlags.testFlag(Texture::DirtySharedTextureId))
+ glTexture->setSharedTextureId(texture->sharedTextureId());
- 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::DirtyProperties))
+ glTexture->setProperties(texture->properties());
- 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::DirtyParameters))
+ glTexture->setParameters(texture->parameters());
// Will make the texture requestUpload
- if (dirtyFlags.testFlag(Texture::DirtyImageGenerators) &&
- !glTextureManager->setImages(glTexture, texture->textureImageIds()))
- qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerators failed, should be non-shared";
+ if (dirtyFlags.testFlag(Texture::DirtyImageGenerators)) {
+ const QNodeIdVector textureImageIds = texture->textureImageIds();
+ QVector<GLTexture::Image> images;
+ images.reserve(textureImageIds.size());
+ // TODO: Move this into GLTexture directly
+ for (const QNodeId textureImageId : textureImageIds) {
+ const TextureImage *img = m_nodesManager->textureImageManager()->lookupResource(textureImageId);
+ if (img == nullptr) {
+ qWarning() << Q_FUNC_INFO << "invalid TextureImage handle";
+ } else {
+ GLTexture::Image glImg {img->dataGenerator(), img->layer(), img->mipLevel(), img->face()};
+ images.push_back(glImg);
+ }
+ }
+ glTexture->setImages(images);
+ }
+
+ // Will make the texture requestUpload
+ if (dirtyFlags.testFlag(Texture::DirtyDataGenerator))
+ glTexture->setGenerator(texture->dataGenerator());
// Will make the texture requestUpload
- if (dirtyFlags.testFlag(Texture::DirtyDataGenerator) &&
- !glTextureManager->setGenerator(glTexture, texture->dataGenerator()))
- qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerator failed, should be non-shared";
+ if (dirtyFlags.testFlag(Texture::DirtyPendingDataUpdates))
+ glTexture->addTextureDataUpdates(texture->takePendingTextureDataUpdates());
// Unset the dirty flag on the texture
texture->unsetDirty();
@@ -1459,8 +1427,11 @@ void Renderer::cleanupTexture(Qt3DCore::QNodeId cleanedUpTextureId)
GLTextureManager *glTextureManager = m_nodesManager->glTextureManager();
GLTexture *glTexture = glTextureManager->lookupResource(cleanedUpTextureId);
- if (glTexture != nullptr)
- glTextureManager->abandon(glTexture, cleanedUpTextureId);
+ // Destroying the GLTexture implicitely also destroy the GL resources
+ if (glTexture != nullptr) {
+ glTextureManager->releaseResource(cleanedUpTextureId);
+ glTextureManager->texNodeIdForGLTexture.remove(glTexture);
+ }
}
// Called by SubmitRenderView
@@ -1485,7 +1456,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
const int renderViewsCount = renderViews.size();
quint64 frameElapsed = queueElapsed;
- m_lastFrameCorrect.store(1); // everything fine until now.....
+ m_lastFrameCorrect.storeRelaxed(1); // everything fine until now.....
qCDebug(Memory) << Q_FUNC_INFO << "rendering frame ";
@@ -1518,7 +1489,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
// to use when surface is null. Or if we should instead expose an
// offscreensurface to Qt3D.
if (!surface || !surfaceLock.isSurfaceValid()) {
- m_lastFrameCorrect.store(0);
+ m_lastFrameCorrect.storeRelaxed(0);
continue;
}
@@ -1526,7 +1497,9 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
const bool surfaceHasChanged = surface != previousSurface;
if (surfaceHasChanged && previousSurface) {
- const bool swapBuffers = (lastBoundFBOId == m_submissionContext->defaultFBO()) && PlatformSurfaceFilter::isSurfaceValid(previousSurface);
+ const bool swapBuffers = lastBoundFBOId == m_submissionContext->defaultFBO()
+ && surfaceLock.isSurfaceValid()
+ && m_shouldSwapBuffers;
// We only call swap buffer if we are sure the previous surface is still valid
m_submissionContext->endDrawing(swapBuffers);
}
@@ -1536,7 +1509,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
// next RenderView. We won't get the full frame but we may get something
if (!m_submissionContext->beginDrawing(surface)) {
qWarning() << "Failed to make OpenGL context current on surface";
- m_lastFrameCorrect.store(0);
+ m_lastFrameCorrect.storeRelaxed(0);
continue;
}
@@ -1637,7 +1610,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
// Execute the render commands
if (!executeCommandsSubmission(renderView))
- m_lastFrameCorrect.store(0); // something went wrong; make sure to render the next frame!
+ m_lastFrameCorrect.storeRelaxed(0); // something went wrong; make sure to render the next frame!
// executeCommandsSubmission takes care of restoring the stateset to the value
// of gc->currentContext() at the moment it was called (either
@@ -1737,9 +1710,10 @@ bool Renderer::shouldRender()
// Only render if something changed during the last frame, or the last frame
// was not rendered successfully (or render-on-demand is disabled)
return (m_settings->renderPolicy() == QRenderSettings::Always
+ || m_renderThread == nullptr // <==> we use Scene3D
|| m_dirtyBits.marked != 0
|| m_dirtyBits.remaining != 0
- || !m_lastFrameCorrect.load());
+ || !m_lastFrameCorrect.loadRelaxed());
}
void Renderer::skipNextFrame()
@@ -1806,17 +1780,14 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
// Add jobs
const bool entitiesEnabledDirty = dirtyBitsForFrame & AbstractRenderer::EntityEnabledDirty;
- const bool entityHierarchyNeedsToBeRebuilt = dirtyBitsForFrame & AbstractRenderer::EntityHierarchyDirty;
- if (entitiesEnabledDirty || entityHierarchyNeedsToBeRebuilt) {
+ if (entitiesEnabledDirty) {
renderBinJobs.push_back(m_updateTreeEnabledJob);
// This dependency is added here because we clear all dependencies
// at the start of this function.
m_calculateBoundingVolumeJob->addDependency(m_updateTreeEnabledJob);
- m_calculateBoundingVolumeJob->addDependency(m_updateEntityHierarchyJob);
}
- if (dirtyBitsForFrame & AbstractRenderer::TransformDirty ||
- dirtyBitsForFrame & AbstractRenderer::EntityHierarchyDirty) {
+ if (dirtyBitsForFrame & AbstractRenderer::TransformDirty) {
renderBinJobs.push_back(m_worldTransformJob);
renderBinJobs.push_back(m_updateWorldBoundingVolumeJob);
renderBinJobs.push_back(m_updateShaderDataTransformJob);
@@ -1829,11 +1800,12 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
}
if (dirtyBitsForFrame & AbstractRenderer::GeometryDirty ||
- dirtyBitsForFrame & AbstractRenderer::EntityHierarchyDirty ||
dirtyBitsForFrame & AbstractRenderer::TransformDirty) {
renderBinJobs.push_back(m_expandBoundingVolumeJob);
}
+ // TO DO: Conditionally add if skeletons dirty
+ renderBinJobs.push_back(m_syncLoadingJobs);
m_updateSkinningPaletteJob->setDirtyJoints(m_nodesManager->jointManager()->dirtyJoints());
renderBinJobs.push_back(m_updateSkinningPaletteJob);
renderBinJobs.push_back(m_updateLevelOfDetailJob);
@@ -1847,26 +1819,21 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
if (dirtyBitsForFrame & AbstractRenderer::BuffersDirty)
renderBinJobs.push_back(m_bufferGathererJob);
- if (dirtyBitsForFrame & AbstractRenderer::TexturesDirty) {
- renderBinJobs.push_back(m_syncTextureLoadingJob);
+ if (dirtyBitsForFrame & AbstractRenderer::TexturesDirty)
renderBinJobs.push_back(m_textureGathererJob);
- }
// Layer cache is dependent on layers, layer filters (hence FG structure
// changes) and the enabled flag on entities
const bool frameGraphDirty = dirtyBitsForFrame & AbstractRenderer::FrameGraphDirty;
- const bool layersDirty = dirtyBitsForFrame & AbstractRenderer::LayersDirty || entityHierarchyNeedsToBeRebuilt;
+ const bool layersDirty = dirtyBitsForFrame & AbstractRenderer::LayersDirty;
const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty || frameGraphDirty;
+ const bool shadersDirty = dirtyBitsForFrame & AbstractRenderer::ShadersDirty;
const bool materialDirty = dirtyBitsForFrame & AbstractRenderer::MaterialDirty;
- const bool materialCacheNeedsToBeRebuilt = materialDirty || frameGraphDirty;
const bool lightsDirty = dirtyBitsForFrame & AbstractRenderer::LightsDirty;
const bool computeableDirty = dirtyBitsForFrame & AbstractRenderer::ComputeDirty;
const bool renderableDirty = dirtyBitsForFrame & AbstractRenderer::GeometryDirty;
-
- // Rebuild Entity Hierarchy if dirty
- if (entityHierarchyNeedsToBeRebuilt)
- renderBinJobs.push_back(m_updateEntityHierarchyJob);
+ const bool materialCacheNeedsToBeRebuilt = shadersDirty || materialDirty || frameGraphDirty;
// Rebuild Entity Layers list if layers are dirty
if (layersDirty)
@@ -1879,24 +1846,33 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
// populate the RenderView with a set of RenderCommands that get
// their details from the RenderNodes that are visible to the
// Camera selected by the framegraph configuration
- FrameGraphVisitor visitor(m_nodesManager->frameGraphManager());
- const QVector<FrameGraphNode *> fgLeaves = visitor.traverse(frameGraphRoot());
-
- // Remove leaf nodes that no longer exist from cache
- const QList<FrameGraphNode *> keys = m_cache.leafNodeCache.keys();
- for (FrameGraphNode *leafNode : keys) {
- if (!fgLeaves.contains(leafNode))
- m_cache.leafNodeCache.remove(leafNode);
+ if (frameGraphDirty) {
+ FrameGraphVisitor visitor(m_nodesManager->frameGraphManager());
+ m_frameGraphLeaves = visitor.traverse(frameGraphRoot());
+ // Remove leaf nodes that no longer exist from cache
+ const QList<FrameGraphNode *> keys = m_cache.leafNodeCache.keys();
+ for (FrameGraphNode *leafNode : keys) {
+ if (!m_frameGraphLeaves.contains(leafNode))
+ m_cache.leafNodeCache.remove(leafNode);
+ }
+
+ // Handle single shot subtree enablers
+ const auto subtreeEnablers = visitor.takeEnablersToDisable();
+ for (auto *node : subtreeEnablers)
+ m_updatedDisables.push_back(node->peerId());
+ if (m_updatedDisables.size() > 0)
+ renderBinJobs.push_back(m_sendDisablesToFrontendJob);
}
- const int fgBranchCount = fgLeaves.size();
+ const int fgBranchCount = m_frameGraphLeaves.size();
for (int i = 0; i < fgBranchCount; ++i) {
- RenderViewBuilder builder(fgLeaves.at(i), i, this);
+ RenderViewBuilder builder(m_frameGraphLeaves.at(i), i, this);
builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt);
- builder.setMaterialGathererCacheNeedsToBeRebuilt(materialCacheNeedsToBeRebuilt);
builder.setRenderableCacheNeedsToBeRebuilt(renderableDirty);
builder.setComputableCacheNeedsToBeRebuilt(computeableDirty);
builder.setLightGathererCacheNeedsToBeRebuilt(lightsDirty);
+ builder.setMaterialGathererCacheNeedsToBeRebuilt(materialCacheNeedsToBeRebuilt);
+ builder.setLightGathererCacheNeedsToBeRebuilt(lightsDirty);
builder.prepareJobs();
renderBinJobs.append(builder.buildJobHierachy());
@@ -1953,9 +1929,9 @@ QAspectJobPtr Renderer::rayCastingJob()
return m_rayCastingJob;
}
-QAspectJobPtr Renderer::syncTextureLoadingJob()
+QAspectJobPtr Renderer::syncLoadingJobs()
{
- return m_syncTextureLoadingJob;
+ return m_syncLoadingJobs;
}
QAspectJobPtr Renderer::expandBoundingVolumeJob()
@@ -2218,7 +2194,7 @@ bool Renderer::updateVAOWithAttributes(Geometry *geometry,
if ((attributeWasDirty = attribute->isDirty()) == true || forceUpdate)
m_submissionContext->specifyIndices(buffer);
// Vertex Attribute
- } else if (command->m_attributes.contains(attribute->nameId())) {
+ } else if (command->m_activeAttributes.contains(attribute->nameId())) {
if ((attributeWasDirty = attribute->isDirty()) == true || forceUpdate) {
// Find the location for the attribute
const QVector<ShaderAttribute> shaderAttributes = shader->attributes();
@@ -2263,7 +2239,7 @@ bool Renderer::requiresVAOAttributeUpdate(Geometry *geometry,
continue;
if ((attribute->attributeType() == QAttribute::IndexAttribute && attribute->isDirty()) ||
- (command->m_attributes.contains(attribute->nameId()) && attribute->isDirty()))
+ (command->m_activeAttributes.contains(attribute->nameId()) && attribute->isDirty()))
return true;
}
return false;
@@ -2277,12 +2253,11 @@ void Renderer::cleanGraphicsResources()
for (Qt3DCore::QNodeId bufferId : buffersToRelease)
m_submissionContext->releaseBuffer(bufferId);
- // Delete abandoned textures
- const QVector<GLTexture*> abandonedTextures = m_nodesManager->glTextureManager()->takeAbandonedTextures();
- for (GLTexture *tex : abandonedTextures) {
- tex->destroyGLTexture();
- delete tex;
- }
+ // When Textures are cleaned up, their id is saved so that they can be
+ // cleaned up in the render thread
+ const QVector<Qt3DCore::QNodeId> cleanedUpTextureIds = std::move(m_textureIdsToCleanup);
+ for (const Qt3DCore::QNodeId textureCleanedUpId: cleanedUpTextureIds)
+ cleanupTexture(textureCleanedUpId);
// Delete abandoned VAOs
m_abandonedVaosMutex.lock();
diff --git a/src/render/renderers/opengl/renderer/renderer.pri b/src/render/renderers/opengl/renderer/renderer.pri
index 34f6064bd..849bac702 100644
--- a/src/render/renderers/opengl/renderer/renderer.pri
+++ b/src/render/renderers/opengl/renderer/renderer.pri
@@ -1,8 +1,6 @@
INCLUDEPATH += $$PWD
SOURCES += \
- $$PWD/commandthread.cpp \
- $$PWD/glcommands.cpp \
$$PWD/openglvertexarrayobject.cpp \
$$PWD/rendercommand.cpp \
$$PWD/renderer.cpp \
@@ -12,8 +10,6 @@ SOURCES += \
$$PWD/shaderparameterpack.cpp
HEADERS += \
- $$PWD/commandthread_p.h \
- $$PWD/glcommands_p.h \
$$PWD/openglvertexarrayobject_p.h \
$$PWD/renderercache_p.h \
$$PWD/rendercommand_p.h \
diff --git a/src/render/renderers/opengl/renderer/renderer_p.h b/src/render/renderers/opengl/renderer/renderer_p.h
index 9376e9eda..b1cd4aac5 100644
--- a/src/render/renderers/opengl/renderer/renderer_p.h
+++ b/src/render/renderers/opengl/renderer/renderer_p.h
@@ -78,10 +78,10 @@
#include <Qt3DRender/private/filtercompatibletechniquejob_p.h>
#include <Qt3DRender/private/updateskinningpalettejob_p.h>
#include <Qt3DRender/private/updateentitylayersjob_p.h>
-#include <Qt3DRender/private/updateentityhierarchyjob_p.h>
#include <Qt3DRender/private/renderercache_p.h>
#include <Qt3DRender/private/texture_p.h>
#include <Qt3DRender/private/glfence_p.h>
+#include <Qt3DRender/private/shaderbuilder_p.h>
#include <QHash>
#include <QMatrix4x4>
@@ -146,7 +146,6 @@ class RenderView;
class Effect;
class RenderPass;
class RenderThread;
-class CommandThread;
class RenderStateSet;
class VSyncFrameAdvanceService;
class PickEventFilter;
@@ -157,7 +156,7 @@ class UpdateLevelOfDetailJob;
typedef QSharedPointer<UpdateLevelOfDetailJob> UpdateLevelOfDetailJobPtr;
using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>;
-using IntrospectShadersJobPtr = GenericLambdaJobPtr<std::function<void()>>;
+using SynchronizerPostFramePtr = GenericLambdaJobAndPostFramePtr<std::function<void ()>, std::function<void (Qt3DCore::QAspectManager *)>>;
class Q_3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer
{
@@ -183,12 +182,12 @@ public:
void releaseGraphicsResources() override;
void render() override;
- void doRender(bool scene3dBlocking = false) override;
+ void doRender(bool swapBuffers = true) override;
void cleanGraphicsResources() override;
- bool isRunning() const override { return m_running.load(); }
+ bool isRunning() const override { return m_running.loadRelaxed(); }
- void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Entity *sgRoot) override;
+ void setSceneRoot(Entity *sgRoot) override;
Entity *sceneRoot() const override { return m_renderSceneRoot; }
FrameGraphNode *frameGraphRoot() const override;
@@ -207,7 +206,7 @@ public:
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() override;
Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() override;
Qt3DCore::QAspectJobPtr rayCastingJob() override;
- Qt3DCore::QAspectJobPtr syncTextureLoadingJob() override;
+ Qt3DCore::QAspectJobPtr syncLoadingJobs() override;
Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() override;
QVector<Qt3DCore::QAspectJobPtr> createRenderBufferJobs() const;
@@ -221,9 +220,9 @@ public:
inline UpdateLevelOfDetailJobPtr updateLevelOfDetailJob() const { return m_updateLevelOfDetailJob; }
inline UpdateMeshTriangleListJobPtr updateMeshTriangleListJob() const { return m_updateMeshTriangleListJob; }
inline FilterCompatibleTechniqueJobPtr filterCompatibleTechniqueJob() const { return m_filterCompatibleTechniqueJob; }
- inline SynchronizerJobPtr textureLoadSyncJob() const { return m_syncTextureLoadingJob; }
+ inline SynchronizerJobPtr syncLoadingJobs() const { return m_syncLoadingJobs; }
inline UpdateSkinningPaletteJobPtr updateSkinningPaletteJob() const { return m_updateSkinningPaletteJob; }
- inline IntrospectShadersJobPtr introspectShadersJob() const { return m_introspectShaderJob; }
+ inline SynchronizerPostFramePtr introspectShadersJob() const { return m_introspectShaderJob; }
inline Qt3DCore::QAspectJobPtr bufferGathererJob() const { return m_bufferGathererJob; }
inline Qt3DCore::QAspectJobPtr textureGathererJob() const { return m_textureGathererJob; }
inline Qt3DCore::QAspectJobPtr sendTextureChangesToFrontendJob() const { return m_sendTextureChangesToFrontendJob; }
@@ -324,7 +323,6 @@ private:
RenderQueue *m_renderQueue;
QScopedPointer<RenderThread> m_renderThread;
- QScopedPointer<CommandThread> m_commandThread;
QScopedPointer<VSyncFrameAdvanceService> m_vsyncFrameAdvanceService;
QSemaphore m_submitRenderViewsSemaphore;
@@ -371,7 +369,6 @@ private:
UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob;
FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob;
UpdateEntityLayersJobPtr m_updateEntityLayersJob;
- UpdateEntityHierarchyJobPtr m_updateEntityHierarchyJob;
QVector<Qt3DCore::QNodeId> m_pendingRenderCaptureSendRequests;
@@ -381,22 +378,24 @@ private:
HVao *previousVAOHandle,
OpenGLVertexArrayObject **vao);
- GenericLambdaJobPtr<std::function<void ()>> m_bufferGathererJob;
- GenericLambdaJobPtr<std::function<void ()>> m_vaoGathererJob;
- GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob;
- GenericLambdaJobPtr<std::function<void ()>> m_sendTextureChangesToFrontendJob;
- GenericLambdaJobPtr<std::function<void ()>> m_sendSetFenceHandlesToFrontendJob;
- IntrospectShadersJobPtr m_introspectShaderJob;
-
- SynchronizerJobPtr m_syncTextureLoadingJob;
+ SynchronizerJobPtr m_bufferGathererJob;
+ SynchronizerJobPtr m_vaoGathererJob;
+ SynchronizerJobPtr m_textureGathererJob;
+ SynchronizerPostFramePtr m_sendTextureChangesToFrontendJob;
+ SynchronizerJobPtr m_sendSetFenceHandlesToFrontendJob;
+ SynchronizerJobPtr m_sendDisablesToFrontendJob;
+ SynchronizerPostFramePtr m_introspectShaderJob;
+ SynchronizerJobPtr m_syncLoadingJobs;
void lookForAbandonedVaos();
void lookForDirtyBuffers();
void lookForDownloadableBuffers();
void lookForDirtyTextures();
void reloadDirtyShaders();
- void sendTextureChangesToFrontend();
+ void sendShaderChangesToFrontend(Qt3DCore::QAspectManager *manager);
+ void sendTextureChangesToFrontend(Qt3DCore::QAspectManager *manager);
void sendSetFenceHandlesToFrontend();
+ void sendDisablesToFrontend();
QMutex m_abandonedVaosMutex;
QVector<HVao> m_abandonedVaos;
@@ -407,6 +406,9 @@ private:
QVector<HTexture> m_dirtyTextures;
QVector<QPair<Texture::TextureUpdateInfo, Qt3DCore::QNodeIdVector>> m_updatedTextureProperties;
QVector<QPair<Qt3DCore::QNodeId, GLFence>> m_updatedSetFences;
+ QVector<Qt3DCore::QNodeId> m_updatedDisables;
+ Qt3DCore::QNodeIdVector m_textureIdsToCleanup;
+ QVector<ShaderBuilderUpdate> m_shaderBuilderUpdates;
bool m_ownedContext;
@@ -424,6 +426,9 @@ private:
QMetaObject::Connection m_contextConnection;
RendererCache m_cache;
+ bool m_shouldSwapBuffers;
+
+ QVector<FrameGraphNode *> m_frameGraphLeaves;
QScreen *m_screen = nullptr;
};
diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp
index 117aca3c7..aa9f4d1a5 100644
--- a/src/render/renderers/opengl/renderer/renderview.cpp
+++ b/src/render/renderers/opengl/renderer/renderview.cpp
@@ -334,6 +334,27 @@ struct AdjacentSubRangeFinder<QSortPolicy::FrontToBack>
}
};
+template<>
+struct AdjacentSubRangeFinder<QSortPolicy::Texture>
+{
+ static bool adjacentSubRange(RenderCommand *a, RenderCommand *b)
+ {
+ // Two renderCommands are adjacent if one contains all the other command's textures
+ QVector<ShaderParameterPack::NamedResource> texturesA = a->m_parameterPack.textures();
+ QVector<ShaderParameterPack::NamedResource> texturesB = b->m_parameterPack.textures();
+
+ if (texturesB.size() > texturesA.size())
+ qSwap(texturesA, texturesB);
+
+ // textureB.size() is always <= textureA.size()
+ for (const ShaderParameterPack::NamedResource &texB : qAsConst(texturesB)) {
+ if (!texturesA.contains(texB))
+ return false;
+ }
+ return true;
+ }
+};
+
template<typename Predicate>
int advanceUntilNonAdjacent(const QVector<RenderCommand *> &commands,
const int beg, const int end, Predicate pred)
@@ -406,6 +427,32 @@ struct SubRangeSorter<QSortPolicy::FrontToBack>
}
};
+template<>
+struct SubRangeSorter<QSortPolicy::Texture>
+{
+ static void sortSubRange(CommandIt begin, const CommandIt end)
+ {
+ std::stable_sort(begin, end, [] (RenderCommand *a, RenderCommand *b) {
+ QVector<ShaderParameterPack::NamedResource> texturesA = a->m_parameterPack.textures();
+ QVector<ShaderParameterPack::NamedResource> texturesB = b->m_parameterPack.textures();
+
+ const int originalTextureASize = texturesA.size();
+
+ if (texturesB.size() > texturesA.size())
+ qSwap(texturesA, texturesB);
+
+ int identicalTextureCount = 0;
+
+ for (const ShaderParameterPack::NamedResource &texB : qAsConst(texturesB)) {
+ if (texturesA.contains(texB))
+ ++identicalTextureCount;
+ }
+
+ return identicalTextureCount < originalTextureASize;
+ });
+ }
+};
+
int findSubRange(const QVector<RenderCommand *> &commands,
const int begin, const int end,
const QSortPolicy::SortType sortType)
@@ -419,6 +466,8 @@ int findSubRange(const QVector<RenderCommand *> &commands,
return advanceUntilNonAdjacent(commands, begin, end, AdjacentSubRangeFinder<QSortPolicy::Material>::adjacentSubRange);
case QSortPolicy::FrontToBack:
return advanceUntilNonAdjacent(commands, begin, end, AdjacentSubRangeFinder<QSortPolicy::FrontToBack>::adjacentSubRange);
+ case QSortPolicy::Texture:
+ return advanceUntilNonAdjacent(commands, begin, end, AdjacentSubRangeFinder<QSortPolicy::Texture>::adjacentSubRange);
default:
Q_UNREACHABLE();
return end;
@@ -462,6 +511,9 @@ void sortCommandRange(QVector<RenderCommand *> &commands, int begin, const int e
case QSortPolicy::FrontToBack:
SubRangeSorter<QSortPolicy::FrontToBack>::sortSubRange(commands.begin() + begin, commands.begin() + end);
break;
+ case QSortPolicy::Texture:
+ SubRangeSorter<QSortPolicy::Texture>::sortSubRange(commands.begin() + begin, commands.begin() + end);
+ break;
default:
Q_UNREACHABLE();
}
@@ -592,21 +644,18 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
const Qt3DCore::QNodeId materialComponentId = entity->componentUuid<Material>();
const HMaterial materialHandle = entity->componentHandle<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_geometryRenderer = geometryRendererHandle;
+ command->m_geometry = m_manager->geometryManager()->lookupHandle(geometryRenderer->geometryId());
// Project the camera-to-object-center vector onto the camera
// view vector. This gives a depth value suitable as the key
// for BackToFront sorting.
command->m_depth = Vector3D::dotProduct(entity->worldBoundingVolume()->center() - m_data.m_eyePos, m_data.m_eyeViewDir);
-
- command->m_geometry = geometryHandle;
- command->m_geometryRenderer = geometryRendererHandle;
command->m_material = materialHandle;
// For RenderPass based states we use the globally set RenderState
// if no renderstates are defined as part of the pass. That means:
@@ -646,51 +695,6 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)),
m_environmentLight);
- // 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();
- }
-
commands.append(command);
}
}
@@ -796,23 +800,35 @@ void RenderView::updateMatrices()
void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, const UniformValue &value) const
{
// At this point a uniform value can only be a scalar type
- // or a Qt3DCore::QNodeId corresponding to a Texture
+ // or a Qt3DCore::QNodeId corresponding to a Texture or Image
// ShaderData/Buffers would be handled as UBO/SSBO and would therefore
// not be in the default uniform block
if (value.valueType() == UniformValue::NodeId) {
const Qt3DCore::QNodeId *nodeIds = value.constData<Qt3DCore::QNodeId>();
const int uniformArraySize = value.byteSize() / sizeof(Qt3DCore::QNodeId);
+ UniformValue::ValueType resourceType = UniformValue::TextureValue;
+
for (int i = 0; i < uniformArraySize; ++i) {
- const Qt3DCore::QNodeId texId = nodeIds[i];
- const Texture *tex = m_manager->textureManager()->lookupResource(texId);
- if (tex != nullptr)
- uniformPack.setTexture(nameId, i, texId);
+ const Qt3DCore::QNodeId resourceId = nodeIds[i];
+
+ const Texture *tex = m_manager->textureManager()->lookupResource(resourceId);
+ if (tex != nullptr) {
+ uniformPack.setTexture(nameId, i, resourceId);
+ } else {
+ const ShaderImage *img = m_manager->shaderImageManager()->lookupResource(resourceId);
+ if (img != nullptr) {
+ resourceType = UniformValue::ShaderImageValue;
+ uniformPack.setImage(nameId, i, resourceId);
+ }
+ }
}
- UniformValue textureValue(uniformArraySize * sizeof(int), UniformValue::TextureValue);
- std::fill(textureValue.data<int>(), textureValue.data<int>() + uniformArraySize, -1);
- uniformPack.setUniform(nameId, textureValue);
+ // This uniform will be overridden in SubmissionContext::setParameters
+ // and -1 values will be replaced by valid Texture or Image units
+ UniformValue uniformValue(uniformArraySize * sizeof(int), resourceType);
+ std::fill(uniformValue.data<int>(), uniformValue.data<int>() + uniformArraySize, -1);
+ uniformPack.setUniform(nameId, uniformValue);
} else {
uniformPack.setUniform(nameId, value);
}
@@ -845,56 +861,6 @@ void RenderView::setUniformBlockValue(ShaderParameterPack &uniformPack,
uniformPack.setUniformBuffer(std::move(uniformBlockUBO));
// Buffer update to GL buffer will be done at render time
}
-
-
- //ShaderData *shaderData = nullptr;
- // if ((shaderData = m_manager->shaderDataManager()->lookupResource(value.value<Qt3DCore::QNodeId>())) != nullptr) {
- // UBO are indexed by <ShaderId, ShaderDataId> so that a same QShaderData can be used among different shaders
- // while still making sure that if they have a different layout everything will still work
- // If two shaders define the same block with the exact same layout, in that case the UBO could be shared
- // but how do we know that ? We'll need to compare ShaderUniformBlocks
-
- // Note: we assume that if a buffer is shared across multiple shaders
- // then it implies that they share the same layout
-
- // Temporarly disabled
-
- // BufferShaderKey uboKey(shaderData->peerId(),
- // shader->peerId());
-
- // BlockToUBO uniformBlockUBO;
- // uniformBlockUBO.m_blockIndex = block.m_index;
- // uniformBlockUBO.m_shaderDataID = shaderData->peerId();
- // bool uboNeedsUpdate = false;
-
- // // build UBO at uboId if not created before
- // if (!m_manager->glBufferManager()->contains(uboKey)) {
- // m_manager->glBufferManager()->getOrCreateResource(uboKey);
- // uboNeedsUpdate = true;
- // }
-
- // // If shaderData has been updated (property has changed or one of the nested properties has changed)
- // // foreach property defined in the QShaderData, we try to fill the value of the corresponding active uniform(s)
- // // for all the updated properties (all the properties if the UBO was just created)
- // if (shaderData->updateViewTransform(*m_data->m_viewMatrix) || uboNeedsUpdate) {
- // // Clear previous values remaining in the hash
- // m_data->m_uniformBlockBuilder.activeUniformNamesToValue.clear();
- // // Update only update properties if uboNeedsUpdate is true, otherwise update the whole block
- // m_data->m_uniformBlockBuilder.updatedPropertiesOnly = uboNeedsUpdate;
- // // Retrieve names and description of each active uniforms in the uniform block
- // m_data->m_uniformBlockBuilder.uniforms = shader->activeUniformsForUniformBlock(block.m_index);
- // // Builds the name-value map for the block
- // m_data->m_uniformBlockBuilder.buildActiveUniformNameValueMapStructHelper(shaderData, block.m_name);
- // if (!uboNeedsUpdate)
- // shaderData->markDirty();
- // // copy the name-value map into the BlockToUBO
- // uniformBlockUBO.m_updatedProperties = m_data->m_uniformBlockBuilder.activeUniformNamesToValue;
- // uboNeedsUpdate = true;
- // }
-
- // uniformBlockUBO.m_needsUpdate = uboNeedsUpdate;
- // uniformPack.setUniformBuffer(std::move(uniformBlockUBO));
- // }
}
}
@@ -997,7 +963,7 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
// Set default attributes
for (const int attributeNameId : attributeNamesIds)
- command->m_attributes.push_back(attributeNameId);
+ command->m_activeAttributes.push_back(attributeNameId);
// Parameters remaining could be
// -> uniform scalar / vector
diff --git a/src/render/renderers/opengl/renderer/shaderparameterpack.cpp b/src/render/renderers/opengl/renderer/shaderparameterpack.cpp
index f78e45a5e..13d05cac1 100644
--- a/src/render/renderers/opengl/renderer/shaderparameterpack.cpp
+++ b/src/render/renderers/opengl/renderer/shaderparameterpack.cpp
@@ -71,11 +71,24 @@ void ShaderParameterPack::setTexture(const int glslNameId, int uniformArrayIndex
if (m_textures[t].glslNameId != glslNameId || m_textures[t].uniformArrayIndex != uniformArrayIndex)
continue;
- m_textures[t].texId = texId;
+ m_textures[t].nodeId = texId;
return;
}
- m_textures.append(NamedTexture(glslNameId, texId, uniformArrayIndex));
+ m_textures.append(NamedResource(glslNameId, texId, uniformArrayIndex, NamedResource::Texture));
+}
+
+void ShaderParameterPack::setImage(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId id)
+{
+ for (int i=0, m = m_images.size(); i < m; ++i) {
+ if (m_images[i].glslNameId != glslNameId || m_images[i].uniformArrayIndex != uniformArrayIndex)
+ continue;
+
+ m_images[i].nodeId = id;
+ return;
+ }
+
+ m_images.append(NamedResource(glslNameId, id, uniformArrayIndex, NamedResource::Image));
}
// Contains Uniform Block Index and QNodeId of the ShaderData (UBO)
diff --git a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h
index fe9ab3995..a5aee6ac4 100644
--- a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h
+++ b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h
@@ -98,6 +98,8 @@ public:
void setUniform(const int glslNameId, const UniformValue &val);
void setTexture(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId id);
+ void setImage(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId id);
+
void setUniformBuffer(BlockToUBO blockToUBO);
void setShaderStorageBuffer(BlockToSSBO blockToSSBO);
void setSubmissionUniform(const ShaderUniform &uniform);
@@ -106,35 +108,59 @@ public:
inline const PackUniformHash &uniforms() const { return m_uniforms; }
UniformValue uniform(const int glslNameId) const { return m_uniforms.value(glslNameId); }
- struct NamedTexture
+
+ struct NamedResource
{
- NamedTexture() {}
- NamedTexture(const int glslNameId, Qt3DCore::QNodeId texId, int uniformArrayIndex)
+ enum Type {
+ Texture = 0,
+ Image
+ };
+
+ NamedResource() {}
+ NamedResource(const int glslNameId, Qt3DCore::QNodeId texId,
+ int uniformArrayIndex, Type type)
: glslNameId(glslNameId)
- , texId(texId)
+ , nodeId(texId)
, uniformArrayIndex(uniformArrayIndex)
+ , type(type)
{ }
int glslNameId;
- Qt3DCore::QNodeId texId;
+ Qt3DCore::QNodeId nodeId;
int uniformArrayIndex;
+ Type type;
+
+ bool operator==(const NamedResource &other) const
+ {
+ return glslNameId == other.glslNameId &&
+ nodeId == other.nodeId &&
+ uniformArrayIndex == other.uniformArrayIndex &&
+ type == other.type;
+ }
+
+ bool operator!=(const NamedResource &other) const
+ {
+ return !(*this == other);
+ }
};
- inline QVector<NamedTexture> textures() const { return m_textures; }
+ inline QVector<NamedResource> textures() const { return m_textures; }
+ inline QVector<NamedResource> images() const { return m_images; }
inline QVector<BlockToUBO> uniformBuffers() const { return m_uniformBuffers; }
inline QVector<BlockToSSBO> shaderStorageBuffers() const { return m_shaderStorageBuffers; }
inline QVector<ShaderUniform> submissionUniforms() const { return m_submissionUniforms; }
private:
PackUniformHash m_uniforms;
- QVector<NamedTexture> m_textures;
+ QVector<NamedResource> m_textures;
+ QVector<NamedResource> m_images;
QVector<BlockToUBO> m_uniformBuffers;
QVector<BlockToSSBO> m_shaderStorageBuffers;
QVector<ShaderUniform> m_submissionUniforms;
friend class RenderView;
};
-QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, ShaderParameterPack::NamedTexture, Q_PRIMITIVE_TYPE)
+QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, ShaderParameterPack::NamedResource, Q_PRIMITIVE_TYPE)
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/renderers/opengl/textures/gltexture.cpp b/src/render/renderers/opengl/textures/gltexture.cpp
index 4fd8a8a86..1b5a972ec 100644
--- a/src/render/renderers/opengl/textures/gltexture.cpp
+++ b/src/render/renderers/opengl/textures/gltexture.cpp
@@ -41,6 +41,8 @@
#include "gltexture_p.h"
#include <private/qdebug_p.h>
+#include <private/qopengltexture_p.h>
+#include <private/qopengltexturehelper_p.h>
#include <QDebug>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
@@ -49,13 +51,9 @@
#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 <Qt3DRender/private/renderbuffer_p.h>
#include <Qt3DRender/private/qtextureimagedata_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/qpropertynodeaddedchange.h>
-#include <Qt3DCore/qpropertynoderemovedchange.h>
#if !defined(QT_OPENGL_ES_2)
#include <QOpenGLFunctions_3_1>
@@ -69,59 +67,110 @@ using namespace Qt3DCore;
namespace Qt3DRender {
namespace Render {
-GLTexture::GLTexture(TextureDataManager *texDataMgr,
- TextureImageDataManager *texImgDataMgr,
- const QTextureGeneratorPtr &texGen,
- bool unique)
- : m_unique(unique)
+namespace {
+
+// This uploadGLData where the data is a fullsize subimage
+// as QOpenGLTexture doesn't allow partial subimage uploads
+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);
+ }
+}
+
+// For partial sub image uploads
+void uploadGLData(QOpenGLTexture *glTex,
+ int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace,
+ int xOffset, int yOffset, int zOffset,
+ const QByteArray &bytes, const QTextureImageDataPtr &data)
+{
+ if (data->isCompressed()) {
+ qWarning() << Q_FUNC_INFO << "Uploading non full sized Compressed Data not supported yet";
+ } else {
+ QOpenGLPixelTransferOptions uploadOptions;
+ uploadOptions.setAlignment(1);
+ glTex->setData(xOffset, yOffset, zOffset,
+ data->width(), data->height(), data->depth(),
+ mipLevel, layer, cubeFace, data->layers(),
+ data->pixelFormat(), data->pixelType(),
+ bytes.constData(), &uploadOptions);
+ }
+}
+
+} // anonymous
+
+
+GLTexture::GLTexture()
+ : m_dirtyFlags(None)
, m_gl(nullptr)
, m_renderBuffer(nullptr)
- , m_textureDataManager(texDataMgr)
- , m_textureImageDataManager(texImgDataMgr)
- , m_dataFunctor(texGen)
+ , m_dataFunctor()
, m_pendingDataFunctor(nullptr)
, m_sharedTextureId(-1)
, m_externalRendering(false)
+ , m_wasTextureRecreated(false)
{
- // make sure texture generator is executed
- // this is needed when Texture have the TargetAutomatic
- // to ensure they are loaded before trying to instantiate the QOpenGLTexture
- if (!texGen.isNull())
- m_textureDataManager->requestData(texGen, this);
}
GLTexture::~GLTexture()
{
- destroyGLTexture();
}
-void GLTexture::destroyResources()
-{
- if (m_dataFunctor)
- m_textureDataManager->releaseData(m_dataFunctor, this);
-}
-
-void GLTexture::destroyGLTexture()
+// Must be called from RenderThread with active GL context
+void GLTexture::destroy()
{
delete m_gl;
m_gl = nullptr;
delete m_renderBuffer;
m_renderBuffer = nullptr;
- m_dirtyFlags.store(0);
+ m_dirtyFlags = None;
+ m_sharedTextureId = -1;
+ m_externalRendering = false;
+ m_wasTextureRecreated = false;
+ m_dataFunctor.reset();
+ m_pendingDataFunctor = nullptr;
- destroyResources();
+ m_properties = {};
+ m_parameters = {};
+ m_textureData.reset();
+ m_images.clear();
+ m_imageData.clear();
+ m_pendingTextureDataUpdates.clear();
}
bool GLTexture::loadTextureDataFromGenerator()
{
- m_textureData = m_textureDataManager->getData(m_dataFunctor);
+ m_textureData = m_dataFunctor->operator()();
// 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";
+ const QAbstractTexture::Target target = m_textureData->target();
+
+ // If both target and functor return Automatic we are still
+ // probably loading the texture, return false
+ if (m_properties.target == QAbstractTexture::TargetAutomatic &&
+ target == QAbstractTexture::TargetAutomatic) {
+ m_textureData.reset();
+ return false;
+ }
+
+ if (m_properties.target != QAbstractTexture::TargetAutomatic &&
+ target != QAbstractTexture::TargetAutomatic &&
+ m_properties.target != target) {
+ qWarning() << Q_FUNC_INFO << "Generator and Properties not requesting the same texture target";
+ m_textureData.reset();
+ return false;
+ }
- m_actualTarget = m_textureData->target();
+ // We take target type from generator if it wasn't explicitly set by the user
+ if (m_properties.target == QAbstractTexture::TargetAutomatic)
+ m_properties.target = target;
m_properties.width = m_textureData->width();
m_properties.height = m_textureData->height();
m_properties.depth = m_textureData->depth();
@@ -143,7 +192,7 @@ void GLTexture::loadTextureDataFromImages()
{
int maxMipLevel = 0;
for (const Image &img : qAsConst(m_images)) {
- const QTextureImageDataPtr imgData = m_textureImageDataManager->getData(img.generator);
+ const QTextureImageDataPtr imgData = img.generator->operator()();
// imgData may be null in the following cases:
// - Texture is created with TextureImages which have yet to be
// loaded (skybox where you don't yet know the path, source set by
@@ -179,26 +228,25 @@ void GLTexture::loadTextureDataFromImages()
}
}
+// Called from RenderThread
GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture()
{
- QMutexLocker locker(&m_textureMutex);
- bool needUpload = false;
TextureUpdateInfo textureInfo;
-
m_properties.status = QAbstractTexture::Error;
+ m_wasTextureRecreated = false;
const bool hasSharedTextureId = m_sharedTextureId > 0;
// Only load texture data if we are not using a sharedTextureId
+ // Check if dataFunctor or images have changed
if (!hasSharedTextureId) {
- // 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) {
+ // If dataFunctor exists and we have no data and it hasn´t run yet
+ if (m_dataFunctor && !m_textureData && m_dataFunctor.get() != m_pendingDataFunctor ) {
const bool successfullyLoadedTextureData = loadTextureDataFromGenerator();
+ // If successful, m_textureData has content
if (successfullyLoadedTextureData) {
setDirtyFlag(Properties, true);
- needUpload = true;
+ setDirtyFlag(TextureData, true);
} else {
if (m_pendingDataFunctor != m_dataFunctor.get()) {
qWarning() << "[Qt3DRender::GLTexture] No QTextureData generated from Texture Generator yet. Texture will be invalid for this frame";
@@ -209,56 +257,77 @@ GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture()
}
}
- // additional texture images may be defined through image data generators
- if (testDirtyFlag(TextureData)) {
+ // If images have changed, clear previous images data
+ // and regenerate m_imageData for the images
+ if (testDirtyFlag(TextureImageData)) {
m_imageData.clear();
loadTextureDataFromImages();
- needUpload = true;
+ // Mark for upload if we actually have something to upload
+ if (!m_imageData.empty()) {
+ setDirtyFlag(TextureData, true);
+ }
+ // Reset image flag
+ setDirtyFlag(TextureImageData, false);
}
+ }
- // don't try to create the texture if the format was not set
- if (m_properties.format == QAbstractTexture::Automatic) {
- textureInfo.properties.status = QAbstractTexture::Error;
- return textureInfo;
- }
+ // Don't try to create the texture if the target or format was still not set
+ // Format should either be set by user or if Automatic
+ // by either the dataGenerator of the texture or the first Image
+ // Target should explicitly be set by the user or the dataGenerator
+ if (m_properties.target == QAbstractTexture::TargetAutomatic ||
+ m_properties.format == QAbstractTexture::Automatic ||
+ m_properties.format == QAbstractTexture::NoFormat) {
+ textureInfo.properties.status = QAbstractTexture::Error;
+ return textureInfo;
}
- // if the properties changed, we need to re-allocate the texture
+ // If the properties changed or texture has become a shared texture from a
+ // 3rd party engine, we need to destroy and maybe re-allocate the texture
if (testDirtyFlag(Properties) || testDirtyFlag(SharedTextureId)) {
delete m_gl;
m_gl = nullptr;
textureInfo.wasUpdated = true;
- // If we are destroyed because of some property change but still our content data
- // make sure we are marked for upload
- if (m_textureData || !m_imageData.empty())
- needUpload = true;
+ // If we are destroyed because of some property change but still have (some) of
+ // our content data make sure we are marked for upload
+ // TO DO: We should actually check if the textureData is still correct
+ // in regard to the size, target and format of the texture though.
+ if (!testDirtyFlag(SharedTextureId) &&
+ (m_textureData || !m_imageData.empty() || !m_pendingTextureDataUpdates.empty()))
+ setDirtyFlag(TextureData, true);
}
m_properties.status = QAbstractTexture::Ready;
- if (hasSharedTextureId && testDirtyFlag(SharedTextureId)) {
+ if (testDirtyFlag(SharedTextureId) || hasSharedTextureId) {
// Update m_properties by doing introspection on the texture
- introspectPropertiesFromSharedTextureId();
+ if (hasSharedTextureId)
+ introspectPropertiesFromSharedTextureId();
+ setDirtyFlag(SharedTextureId, false);
} else {
// We only build a QOpenGLTexture if we have no shared textureId set
if (!m_gl) {
m_gl = buildGLTexture();
if (!m_gl) {
+ qWarning() << "[Qt3DRender::GLTexture] failed to create texture";
textureInfo.properties.status = QAbstractTexture::Error;
return textureInfo;
}
m_gl->allocateStorage();
if (!m_gl->isStorageAllocated()) {
+ qWarning() << "[Qt3DRender::GLTexture] failed to allocate texture";
textureInfo.properties.status = QAbstractTexture::Error;
return textureInfo;
}
+ m_wasTextureRecreated = true;
}
textureInfo.texture = m_gl;
// need to (re-)upload texture data?
- if (needUpload) {
+ const bool needsUpload = testDirtyFlag(TextureData);
+ if (needsUpload) {
uploadGLTextureData();
setDirtyFlag(TextureData, false);
}
@@ -266,26 +335,20 @@ GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture()
// need to set texture parameters?
if (testDirtyFlag(Properties) || testDirtyFlag(Parameters)) {
updateGLTextureParameters();
+ setDirtyFlag(Properties, false);
+ setDirtyFlag(Parameters, false);
}
}
textureInfo.properties = m_properties;
- // un-set properties and parameters. The TextureData flag might have been set by another thread
- // in the meantime, so don't clear that.
- setDirtyFlag(Properties, false);
- setDirtyFlag(Parameters, false);
- setDirtyFlag(SharedTextureId, false);
-
return textureInfo;
}
RenderBuffer *GLTexture::getOrCreateRenderBuffer()
{
- QMutexLocker locker(&m_textureMutex);
-
if (m_dataFunctor && !m_textureData) {
- m_textureData = m_textureDataManager->getData(m_dataFunctor);
+ m_textureData = m_dataFunctor->operator()();
if (m_textureData) {
if (m_properties.target != QAbstractTexture::TargetAutomatic)
qWarning() << "[Qt3DRender::GLTexture] [renderbuffer] When a texture provides a generator, it's target is expected to be TargetAutomatic";
@@ -318,9 +381,15 @@ RenderBuffer *GLTexture::getOrCreateRenderBuffer()
return m_renderBuffer;
}
+// This must be called from the RenderThread
+// So GLTexture release from the manager can only be done from that thread
+void GLTexture::cleanup()
+{
+ destroy();
+}
+
void GLTexture::setParameters(const TextureParameters &params)
{
- QMutexLocker locker(&m_textureMutex);
if (m_parameters != params) {
m_parameters = params;
setDirtyFlag(Parameters);
@@ -329,10 +398,8 @@ void GLTexture::setParameters(const TextureParameters &params)
void GLTexture::setProperties(const TextureProperties &props)
{
- QMutexLocker locker(&m_textureMutex);
if (m_properties != props) {
m_properties = props;
- m_actualTarget = props.target;
setDirtyFlag(Properties);
}
}
@@ -353,25 +420,16 @@ void GLTexture::setImages(const QVector<Image> &images)
if (!same) {
m_images = images;
- requestUpload();
+ requestImageUpload();
}
}
void GLTexture::setGenerator(const QTextureGeneratorPtr &generator)
{
- // Note: we do not compare if the generator is different
- // as in some cases we may want to reset the same generator to force a reload
- // e.g when using remote urls for textures
- if (m_dataFunctor)
- m_textureDataManager->releaseData(m_dataFunctor, this);
-
m_textureData.reset();
m_dataFunctor = generator;
-
- if (m_dataFunctor) {
- m_textureDataManager->requestData(m_dataFunctor, this);
- requestUpload();
- }
+ m_pendingDataFunctor = nullptr;
+ requestUpload();
}
void GLTexture::setSharedTextureId(int textureId)
@@ -382,6 +440,12 @@ void GLTexture::setSharedTextureId(int textureId)
}
}
+void GLTexture::addTextureDataUpdates(const QVector<QTextureDataUpdate> &updates)
+{
+ m_pendingTextureDataUpdates += updates;
+ requestUpload();
+}
+
// Return nullptr if
// - context cannot be obtained
// - texture hasn't yet been loaded
@@ -393,28 +457,29 @@ QOpenGLTexture *GLTexture::buildGLTexture()
return nullptr;
}
- if (m_actualTarget == QAbstractTexture::TargetAutomatic) {
+ const QAbstractTexture::Target actualTarget = m_properties.target;
+ if (actualTarget == QAbstractTexture::TargetAutomatic) {
// If the target is automatic at this point, it means that the texture
// hasn't been loaded yet (case of remote urls) and that loading failed
// and that target format couldn't be deduced
return nullptr;
}
- QOpenGLTexture* glTex = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(m_actualTarget));
+ QOpenGLTexture* glTex = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(actualTarget));
// 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:
+ case QAbstractTexture::RGBA8_UNorm:
+ case QAbstractTexture::RGBAFormat:
format = QAbstractTexture::RGBAFormat;
break;
- case QOpenGLTexture::RGB8_UNorm:
- case QOpenGLTexture::RGBFormat:
+ case QAbstractTexture::RGB8_UNorm:
+ case QAbstractTexture::RGBFormat:
format = QAbstractTexture::RGBFormat;
break;
- case QOpenGLTexture::DepthFormat:
+ case QAbstractTexture::DepthFormat:
format = QAbstractTexture::DepthFormat;
break;
default:
@@ -436,19 +501,19 @@ QOpenGLTexture *GLTexture::buildGLTexture()
}
glTex->setFormat(m_properties.format == QAbstractTexture::Automatic ?
- QOpenGLTexture::NoFormat :
- static_cast<QOpenGLTexture::TextureFormat>(format));
+ 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_actualTarget == QAbstractTexture::Target1DArray ||
- m_actualTarget == QAbstractTexture::Target2DArray ||
- m_actualTarget == QAbstractTexture::Target2DMultisampleArray ||
- m_actualTarget == QAbstractTexture::TargetCubeMapArray) {
+ if (actualTarget == QAbstractTexture::Target1DArray ||
+ actualTarget == QAbstractTexture::Target2DArray ||
+ actualTarget == QAbstractTexture::Target2DMultisampleArray ||
+ actualTarget == QAbstractTexture::TargetCubeMapArray) {
glTex->setLayers(m_properties.layers);
}
- if (m_actualTarget == QAbstractTexture::Target2DMultisample ||
- m_actualTarget == QAbstractTexture::Target2DMultisampleArray) {
+ if (actualTarget == QAbstractTexture::Target2DMultisample ||
+ actualTarget == QAbstractTexture::Target2DMultisampleArray) {
// Set samples count if multisampled texture
// (multisampled textures don't have mipmaps)
glTex->setSamples(m_properties.samples);
@@ -471,19 +536,6 @@ QOpenGLTexture *GLTexture::buildGLTexture()
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
@@ -518,23 +570,69 @@ void GLTexture::uploadGLTextureData()
static_cast<QOpenGLTexture::CubeMapFace>(m_images[i].face),
bytes, imgData);
}
+ // Free up image data once content has been uploaded
+ // Note: if data functor stores the data, this won't really free anything though
+ m_imageData.clear();
+
+ // Update data from TextureUpdates
+ const QVector<QTextureDataUpdate> textureDataUpdates = std::move(m_pendingTextureDataUpdates);
+ for (const QTextureDataUpdate &update : textureDataUpdates) {
+ const QTextureImageDataPtr imgData = update.data();
+
+ if (!imgData) {
+ qWarning() << Q_FUNC_INFO << "QTextureDataUpdate no QTextureImageData set";
+ continue;
+ }
+
+ const int xOffset = update.x();
+ const int yOffset = update.y();
+ const int zOffset = update.z();
+ const int xExtent = xOffset + imgData->width();
+ const int yExtent = yOffset + imgData->height();
+ const int zExtent = zOffset + imgData->depth();
+
+ // Check update is compatible with our texture
+ if (xOffset >= m_gl->width() ||
+ yOffset >= m_gl->height() ||
+ zOffset >= m_gl->depth() ||
+ xExtent > m_gl->width() ||
+ yExtent > m_gl->height() ||
+ zExtent > m_gl->depth() ||
+ update.mipLevel() >= m_gl->mipLevels() ||
+ update.layer() >= m_gl->layers()) {
+ qWarning() << Q_FUNC_INFO << "QTextureDataUpdate incompatible with texture";
+ continue;
+ }
+
+ const QByteArray bytes = (QTextureImageDataPrivate::get(imgData.get())->m_data);
+ // Here the bytes in the QTextureImageData contain data for a single
+ // layer, face or mip level, unlike the QTextureGenerator case where
+ // they are in a single blob. Hence QTextureImageData::data() is not suitable.
+
+ uploadGLData(m_gl,
+ update.mipLevel(), update.layer(),
+ static_cast<QOpenGLTexture::CubeMapFace>(update.face()),
+ xOffset, yOffset, zOffset,
+ bytes, imgData);
+ }
}
void GLTexture::updateGLTextureParameters()
{
- const bool isMultisampledTexture = (m_actualTarget == QAbstractTexture::Target2DMultisample ||
- m_actualTarget == QAbstractTexture::Target2DMultisampleArray);
+ const QAbstractTexture::Target actualTarget = m_properties.target;
+ const bool isMultisampledTexture = (actualTarget == QAbstractTexture::Target2DMultisample ||
+ actualTarget == QAbstractTexture::Target2DMultisampleArray);
// Multisampled textures can only be accessed by texelFetch in shaders
// and don't support wrap modes and mig/mag filtes
if (isMultisampledTexture)
return;
m_gl->setWrapMode(QOpenGLTexture::DirectionS, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeX));
- if (m_actualTarget != QAbstractTexture::Target1D &&
- m_actualTarget != QAbstractTexture::Target1DArray &&
- m_actualTarget != QAbstractTexture::TargetBuffer)
+ if (actualTarget != QAbstractTexture::Target1D &&
+ actualTarget != QAbstractTexture::Target1DArray &&
+ actualTarget != QAbstractTexture::TargetBuffer)
m_gl->setWrapMode(QOpenGLTexture::DirectionT, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeY));
- if (m_actualTarget == QAbstractTexture::Target3D)
+ if (actualTarget == 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));
@@ -581,8 +679,8 @@ void GLTexture::introspectPropertiesFromSharedTextureId()
const QPair<int, int> ctxGLVersion = ctx->format().version();
if (ctxGLVersion.first > 4 || (ctxGLVersion.first == 4 && ctxGLVersion.second >= 5)) {
// Only for GL 4.5+
- QOpenGLFunctions_4_5_Core *gl5 = ctx->versionFunctions<QOpenGLFunctions_4_5_Core>();
#ifdef GL_TEXTURE_TARGET
+ QOpenGLFunctions_4_5_Core *gl5 = ctx->versionFunctions<QOpenGLFunctions_4_5_Core>();
if (gl5 != nullptr)
gl5->glGetTextureParameteriv(m_sharedTextureId, GL_TEXTURE_TARGET, reinterpret_cast<int *>(&m_properties.target));
#endif
diff --git a/src/render/renderers/opengl/textures/gltexture_p.h b/src/render/renderers/opengl/textures/gltexture_p.h
index 66f66926c..ca851712d 100644
--- a/src/render/renderers/opengl/textures/gltexture_p.h
+++ b/src/render/renderers/opengl/textures/gltexture_p.h
@@ -96,13 +96,18 @@ class RenderBuffer;
class Q_AUTOTEST_EXPORT GLTexture
{
public:
- GLTexture(TextureDataManager *texDataMgr,
- TextureImageDataManager *texImgDataMgr,
- const QTextureGeneratorPtr &texGen,
- bool unique);
-
+ GLTexture();
~GLTexture();
+ enum DirtyFlag {
+ None = 0,
+ TextureData = (1 << 0), // texture data needs uploading to GPU
+ Properties = (1 << 1), // texture needs to be (re-)created
+ Parameters = (1 << 2), // texture parameters need to be (re-)set
+ SharedTextureId = (1 << 3), // texture id from shared context
+ TextureImageData = (1 << 4) // texture image data needs uploading
+ };
+
/**
* Helper class to hold the defining properties of TextureImages
*/
@@ -120,8 +125,6 @@ public:
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; }
@@ -157,23 +160,21 @@ public:
*/
RenderBuffer *getOrCreateRenderBuffer();
- /**
- * @brief Make sure to call this before calling the dtor
- */
- void destroyGLTexture();
- // Called by TextureDataManager when it has new texture data from
- // a generator that needs to be uploaded.
- void requestUpload()
- {
- setDirtyFlag(TextureData, true);
- }
+ void destroy();
- bool isDirty()
+ void cleanup();
+
+ bool isDirty() const
{
- return m_dirtyFlags.load() != 0;
+ return m_dirtyFlags != None;
}
+ bool hasTextureData() const { return !m_textureData.isNull(); }
+ bool hasImagesData() const { return !m_imageData.isEmpty(); }
+
+ QFlags<DirtyFlag> dirtyFlags() const { return m_dirtyFlags; }
+
QMutex *externalRenderingLock()
{
return &m_externalRenderingMutex;
@@ -189,44 +190,41 @@ public:
return m_externalRendering;
}
-protected:
- template<class APITexture, class APITextureImage>
- friend class APITextureManager;
+ // Purely for unit testing purposes
+ bool wasTextureRecreated() const
+ {
+ return m_wasTextureRecreated;
+ }
- /*
- * 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);
void setGenerator(const QTextureGeneratorPtr &generator);
void setSharedTextureId(int textureId);
+ void addTextureDataUpdates(const QVector<QTextureDataUpdate> &updates);
+
+ QVector<QTextureDataUpdate> textureDataUpdates() const { return m_pendingTextureDataUpdates; }
+ QTextureGeneratorPtr dataGenerator() const { return m_dataFunctor; }
private:
+ void requestImageUpload()
+ {
+ m_dirtyFlags |= TextureImageData;
+ }
- enum DirtyFlag {
- TextureData = 0x01, // one or more image generators have been executed, data needs uploading to GPU
- Properties = 0x02, // texture needs to be (re-)created
- Parameters = 0x04, // texture parameters need to be (re-)set
- SharedTextureId = 0x08 // texture id from shared context
- };
+ void requestUpload()
+ {
+ m_dirtyFlags |= TextureData;
+ }
bool testDirtyFlag(DirtyFlag flag)
{
- return m_dirtyFlags.load() & flag;
+ return m_dirtyFlags.testFlag(flag);
}
void setDirtyFlag(DirtyFlag flag, bool value = true)
{
- if (value)
- m_dirtyFlags |= flag;
- else
- m_dirtyFlags &= ~static_cast<int>(flag);
+ m_dirtyFlags.setFlag(flag, value);
}
QOpenGLTexture *buildGLTexture();
@@ -237,18 +235,12 @@ private:
void introspectPropertiesFromSharedTextureId();
void destroyResources();
- bool m_unique;
- QAtomicInt m_dirtyFlags;
- QMutex m_textureMutex;
+ QFlags<DirtyFlag> m_dirtyFlags;
QMutex m_externalRenderingMutex;
QOpenGLTexture *m_gl;
RenderBuffer *m_renderBuffer;
- TextureDataManager *m_textureDataManager;
- TextureImageDataManager *m_textureImageDataManager;
-
// target which is actually used for GL texture
- QAbstractTexture::Target m_actualTarget;
TextureProperties m_properties;
TextureParameters m_parameters;
@@ -259,9 +251,11 @@ private:
// cache actual image data generated by the functors
QTextureDataPtr m_textureData;
QVector<QTextureImageDataPtr> m_imageData;
+ QVector<QTextureDataUpdate> m_pendingTextureDataUpdates;
int m_sharedTextureId;
bool m_externalRendering;
+ bool m_wasTextureRecreated;
};
} // namespace Render
diff --git a/src/render/renderers/opengl/textures/gltexturemanager_p.h b/src/render/renderers/opengl/textures/gltexturemanager_p.h
index 1c8b49911..335af136c 100644
--- a/src/render/renderers/opengl/textures/gltexturemanager_p.h
+++ b/src/render/renderers/opengl/textures/gltexturemanager_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <Qt3DRender/private/apitexturemanager_p.h>
+#include <Qt3DCore/private/qresourcemanager_p.h>
#include <Qt3DRender/private/gltexture_p.h>
QT_BEGIN_NAMESPACE
@@ -59,21 +59,20 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
-class Q_AUTOTEST_EXPORT GLTextureManager : public APITextureManager<GLTexture, GLTexture::Image>
+class Q_AUTOTEST_EXPORT GLTextureManager : public Qt3DCore::QResourceManager<
+ GLTexture,
+ Qt3DCore::QNodeId,
+ Qt3DCore::NonLockingPolicy>
{
public:
- explicit GLTextureManager(TextureImageManager *textureImageManager,
- TextureDataManager *textureDataManager,
- TextureImageDataManager *textureImageDataManager)
- : APITextureManager<GLTexture, GLTexture::Image>(textureImageManager,
- textureDataManager,
- textureImageDataManager)
- {}
+ QHash<GLTexture *, Qt3DCore::QNodeId> texNodeIdForGLTexture;
};
} // namespace Render
} // namespace Qt3DRender
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::GLTexture, Q_REQUIRES_CLEANUP)
+
QT_END_NAMESPACE
#endif // QT3DRENDER_RENDER_GLTEXTUREMANAGER_H
diff --git a/src/render/renderstates/genericstate_p.h b/src/render/renderstates/genericstate_p.h
index b07487d65..e3ece36f5 100644
--- a/src/render/renderstates/genericstate_p.h
+++ b/src/render/renderstates/genericstate_p.h
@@ -80,7 +80,7 @@ public:
virtual StateMask mask() const = 0;
virtual bool equalTo(const RenderStateImpl &renderState) const = 0;
- virtual void updateProperty(const char *name, const QVariant &value);
+ virtual void updateProperties(const QRenderState *);
};
template <class StateSetImpl, StateMask stateMask, typename ... T>
diff --git a/src/render/renderstates/qdepthrange.cpp b/src/render/renderstates/qdepthrange.cpp
new file mode 100644
index 000000000..ec5bbce9f
--- /dev/null
+++ b/src/render/renderstates/qdepthrange.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qdepthrange.h"
+#include "qdepthrange_p.h"
+#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+/*!
+ \class Qt3DRender::QDepthRange
+ \inmodule Qt3DRender
+ \since 5.14
+ \ingroup renderstates
+ \brief Enables remapping depth values written into the depth buffer.
+
+ By default, OpenGL writes scene depth information into the depth buffer in
+ the range [0.0, 1.0] with 0.0 corresponding to the near clip plane and 1.0 to
+ the far clip plane. QDepthRange allows mapping these values into a different
+ range so parts of the scene are always rendered in front of or behind other
+ parts. Valid values for near and far are between 0 and 1.
+ */
+
+/*!
+ \qmltype DepthRange
+ \instantiates Qt3DRender::QDepthRange
+ \inherits RenderState
+ \inqmlmodule Qt3D.Render
+ \ingroup renderstates
+ \since 5.14
+ \brief Enables remapping depth values written into the depth buffer.
+
+ By default, OpenGL writes scene depth information into the depth buffer in
+ the range [0.0, 1.0] corresponding to the near and far clip planes.
+ QDepthRange allows mapping these values into a different range. For example
+ setting the range [0.0, 0.5] will map the rendered scene into the depth
+ buffer such that objects at the near clip plane have depth value of 0.0 and
+ objects at the far clip plane have a depth value of 0.5. This allows
+ rendering parts of the scene always in front of or behind other parts.
+*/
+
+/*!
+ \qmlproperty real QDepthRange::nearValue
+ The depth buffer value corresponding to the near clip plane. Valid values for are
+ between 0 and 1.
+*/
+
+/*!
+ \qmlproperty real QDepthRange::farValue
+ The depth buffer value corresponding to the far clip plane. Valid values for are
+ between 0 and 1.
+*/
+
+/*!
+ \property QDepthRange::nearValue
+ The depth buffer value corresponding to the near clip plane. Valid values for are
+ between 0 and 1.
+*/
+
+/*!
+ \property QDepthRange::farValue
+ The depth buffer value corresponding to the far clip plane. Valid values for are
+ between 0 and 1.
+*/
+
+QDepthRange::QDepthRange(QNode *parent)
+ : QRenderState(*new QDepthRangePrivate(), parent)
+{
+}
+
+/*! \internal */
+QDepthRange::~QDepthRange()
+{
+}
+
+double QDepthRange::nearValue() const
+{
+ Q_D(const QDepthRange);
+ return d->m_nearValue;
+}
+
+double QDepthRange::farValue() const
+{
+ Q_D(const QDepthRange);
+ return d->m_farValue;
+}
+
+void QDepthRange::setNearValue(double value)
+{
+ Q_D(QDepthRange);
+ if (value != d->m_nearValue) {
+ d->m_nearValue = value;
+ Q_EMIT nearValueChanged(value);
+ }
+}
+
+void QDepthRange::setFarValue(double value)
+{
+ Q_D(QDepthRange);
+ if (value != d->m_farValue) {
+ d->m_farValue = value;
+ Q_EMIT farValueChanged(value);
+ }
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QDepthRange::createNodeCreationChange() const
+{
+ auto creationChange = QRenderStateCreatedChangePtr<QDepthRangeData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QDepthRange);
+ data.nearValue = d->m_nearValue;
+ data.farValue = d->m_farValue;
+ return creationChange;
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/renderstates/qdepthrange.h b/src/render/renderstates/qdepthrange.h
new file mode 100644
index 000000000..9352f5e3a
--- /dev/null
+++ b/src/render/renderstates/qdepthrange.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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_QDEPTHRANGE_H
+#define QT3DRENDER_QDEPTHRANGE_H
+
+#include <Qt3DRender/qrenderstate.h>
+#include <QtGui/qvector3d.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QDepthRangePrivate;
+
+class Q_3DRENDERSHARED_EXPORT QDepthRange : public QRenderState
+{
+ Q_OBJECT
+ Q_PROPERTY(double nearValue READ nearValue WRITE setNearValue NOTIFY nearValueChanged)
+ Q_PROPERTY(double farValue READ farValue WRITE setFarValue NOTIFY farValueChanged)
+public:
+ explicit QDepthRange(Qt3DCore::QNode *parent = nullptr);
+ ~QDepthRange();
+
+ double nearValue() const;
+ double farValue() const;
+
+public Q_SLOTS:
+ void setNearValue(double value);
+ void setFarValue(double value);
+
+Q_SIGNALS:
+ void nearValueChanged(double nearValue);
+ void farValueChanged(double farValue);
+
+private:
+ Q_DECLARE_PRIVATE(QDepthRange)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QDEPTHRANGE_H
diff --git a/src/render/jobs/updateentityhierarchyjob_p.h b/src/render/renderstates/qdepthrange_p.h
index fd2b13631..43eeeb4c7 100644
--- a/src/render/jobs/updateentityhierarchyjob_p.h
+++ b/src/render/renderstates/qdepthrange_p.h
@@ -37,9 +37,8 @@
**
****************************************************************************/
-
-#ifndef QT3DRENDER_RENDER_UPDATEENTITYHIERARCHYJOB_P_H
-#define QT3DRENDER_RENDER_UPDATEENTITYHIERARCHYJOB_P_H
+#ifndef QT3DRENDER_QDEPTHRANGE_P_H
+#define QT3DRENDER_QDEPTHRANGE_P_H
//
// W A R N I N G
@@ -52,40 +51,35 @@
// We mean it.
//
+#include <Qt3DRender/private/qrenderstate_p.h>
+#include <Qt3DRender/qalphatest.h>
#include <Qt3DRender/private/qt3drender_global_p.h>
-#include <Qt3DCore/qaspectjob.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-namespace Render {
-
-class Entity;
-class NodeManagers;
-
-class Q_3DRENDERSHARED_PRIVATE_EXPORT UpdateEntityHierarchyJob: public Qt3DCore::QAspectJob
+class Q_3DRENDERSHARED_PRIVATE_EXPORT QDepthRangePrivate : public QRenderStatePrivate
{
public:
- UpdateEntityHierarchyJob();
-
- inline void setManager(NodeManagers *manager) { m_manager = manager; }
- inline NodeManagers *manager() const { return m_manager; }
-
- // QAspectJob interface
- void run() final;
-
-private:
- NodeManagers *m_manager;
+ QDepthRangePrivate()
+ : QRenderStatePrivate(Render::DepthRangeMask)
+ , m_nearValue(0.0f)
+ , m_farValue(1.0f)
+ {}
+
+ double m_nearValue;
+ double m_farValue;
};
+struct QDepthRangeData
+{
+ double nearValue;
+ double farValue;
+};
-using UpdateEntityHierarchyJobPtr = QSharedPointer<UpdateEntityHierarchyJob>;
-
-} // Render
-
-} // Qt3DRender
+} // namespace Qt3DRender
QT_END_NAMESPACE
-#endif // QT3DRENDER_RENDER_UPDATEENTITYHIERARCHYJOB_P_H
+#endif // QT3DRENDER_QDEPTHRANGE_P_H
diff --git a/src/render/renderstates/qdithering.cpp b/src/render/renderstates/qdithering.cpp
index ae77ced97..a449be508 100644
--- a/src/render/renderstates/qdithering.cpp
+++ b/src/render/renderstates/qdithering.cpp
@@ -41,7 +41,6 @@
#include "qdithering.h"
#include "qrenderstate_p.h"
#include <private/qnode_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/renderstates/qmultisampleantialiasing.cpp b/src/render/renderstates/qmultisampleantialiasing.cpp
index bb5136846..249dcd4bd 100644
--- a/src/render/renderstates/qmultisampleantialiasing.cpp
+++ b/src/render/renderstates/qmultisampleantialiasing.cpp
@@ -40,7 +40,6 @@
#include "qmultisampleantialiasing.h"
#include "qrenderstate_p.h"
#include <private/qnode_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/renderstates/qnodepthmask.cpp b/src/render/renderstates/qnodepthmask.cpp
index 7be7f24f4..241751a26 100644
--- a/src/render/renderstates/qnodepthmask.cpp
+++ b/src/render/renderstates/qnodepthmask.cpp
@@ -41,7 +41,6 @@
#include "qnodepthmask.h"
#include "qrenderstate_p.h"
#include <private/qnode_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/renderstates/qrastermode.cpp b/src/render/renderstates/qrastermode.cpp
new file mode 100644
index 000000000..c432f1063
--- /dev/null
+++ b/src/render/renderstates/qrastermode.cpp
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 "qrastermode.h"
+#include "qrastermode_p.h"
+#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+/*!
+ \class Qt3DRender::QRasterMode
+ \brief The QRasterMode render state allows to control the type of
+ rasterization to be performed
+ \since 5.14
+ \inmodule Qt3DRender
+ \ingroup renderstates
+
+ The QRasterMode class is used to control the rasterization step of the
+ primitives at render time. This can be used to choose whether we only
+ want to show points, edges or fill a primitive.
+
+ \note This is not supported when rendering on OpenGL ES 2.0 platforms.
+
+ \sa QAlphaTest, QStencilTest
+ */
+
+/*!
+ \qmltype RasterMode
+ \brief The RasterMode render state allows to control the type of
+ rasterization to be performed
+ \since 5.14
+ \inqmlmodule Qt3D.Render
+ \inherits RenderState
+ \instantiates Qt3DRender::QRasterMode
+ \ingroup renderstates
+
+ The QRasterMode class is used to control the rasterization step of the
+ primitives at render time. This can be used to choose whether we only
+ want to show points, edges or fill a primitive.
+
+ \note This is not supported when rendering on OpenGL ES 2.0 platforms.
+
+ \sa AlphaTest, StencilTest
+ */
+
+/*!
+ \enum Qt3DRender::QRasterMode::RasterMode
+
+ Enumeration for raster mode values
+ \value Points Vertices at the start of an edge are drawn as points.
+ \value Lines Edges of a polygon are draw as line segments.
+ \value Fill Fills the interior of the primitive.
+*/
+
+/*!
+ \enum Qt3DRender::QRasterMode::FaceMode
+
+ Enumeration for face mode values
+ \value Front Applies to front faces only
+ \value Back Applies to back faces only
+ \value FrontAndBack Applies to front and back faces
+*/
+
+/*!
+ \property QRasterMode::rasterMode
+
+ Holds the raster mode to be used.
+*/
+
+/*!
+ \property QRasterMode::faceMode
+
+ Holds the face mode to be used. Controls on which face the raster mode is
+ to be applied.
+*/
+
+/*!
+ \qmlproperty enumeration RasterMode::rasterMode
+
+ Holds the raster mode to be used.
+
+ \list
+ \li Points Vertices at the start of an edge are drawn as points.
+ \li Lines Edges of a polygon are draw as line segments.
+ \li Fill Fills the interior of the primitive.
+ \endlist
+*/
+
+/*!
+ \qmlproperty enumeration RasterMode::faceMode
+
+ Holds the face mode to be used. Controls on which face the raster mode is
+ to be applied.
+
+ \list
+ \li Front Applies to front faces only
+ \li Back Applies to back faces only
+ \li FrontAndBack Applies to front and back faces
+ \endlist
+*/
+
+
+
+QRasterMode::QRasterMode(QNode *parent)
+ : QRenderState(*new QRasterModePrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QRasterMode::~QRasterMode()
+ = default;
+
+QRasterMode::RasterMode QRasterMode::rasterMode() const
+{
+ Q_D(const QRasterMode);
+ return d->m_rasterMode;
+}
+
+QRasterMode::FaceMode QRasterMode::faceMode() const
+{
+ Q_D(const QRasterMode);
+ return d->m_faceMode;
+}
+
+void QRasterMode::setRasterMode(QRasterMode::RasterMode rasterMode)
+{
+ Q_D(QRasterMode);
+ if (d->m_rasterMode != rasterMode) {
+ d->m_rasterMode = rasterMode;
+ emit rasterModeChanged(rasterMode);
+ }
+}
+
+void QRasterMode::setFaceMode(QRasterMode::FaceMode faceMode)
+{
+ Q_D(QRasterMode);
+ if (d->m_faceMode != faceMode) {
+ d->m_faceMode = faceMode;
+ emit faceModeChanged(faceMode);
+ }
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QRasterMode::createNodeCreationChange() const
+{
+ auto creationChange = QRenderStateCreatedChangePtr<QRasterModeData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QRasterMode);
+ data.rasterMode = d->m_rasterMode;
+ data.faceMode = d->m_faceMode;
+ return creationChange;
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/renderstates/qrastermode.h b/src/render/renderstates/qrastermode.h
new file mode 100644
index 000000000..d460fa10c
--- /dev/null
+++ b/src/render/renderstates/qrastermode.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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_QRASTERMODE_H
+#define QT3DRENDER_QRASTERMODE_H
+
+#include <Qt3DRender/qrenderstate.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QRasterModePrivate;
+
+class Q_3DRENDERSHARED_EXPORT QRasterMode : public QRenderState
+{
+ Q_OBJECT
+ Q_PROPERTY(RasterMode rasterMode READ rasterMode WRITE setRasterMode NOTIFY rasterModeChanged)
+ Q_PROPERTY(FaceMode faceMode READ faceMode WRITE setFaceMode NOTIFY faceModeChanged)
+public:
+
+ enum RasterMode {
+ Points = 0x1B00,
+ Lines = 0x1B01,
+ Fill = 0x1B02,
+ };
+ Q_ENUM(RasterMode) // LCOV_EXCL_LINE
+
+ enum FaceMode
+ {
+ Front = 0x0404,
+ Back = 0x0405,
+ FrontAndBack = 0x0408
+ };
+ Q_ENUM(FaceMode) // LCOV_EXCL_LINE
+
+ explicit QRasterMode(Qt3DCore::QNode *parent = nullptr);
+ ~QRasterMode();
+
+ RasterMode rasterMode() const;
+ FaceMode faceMode() const;
+
+public Q_SLOTS:
+ void setRasterMode(RasterMode rasterMode);
+ void setFaceMode(FaceMode faceMode);
+
+Q_SIGNALS:
+ void rasterModeChanged(RasterMode rasterMode);
+ void faceModeChanged(FaceMode faceMode);
+
+private:
+ Q_DECLARE_PRIVATE(QRasterMode)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QRASTERMODE_H
diff --git a/src/render/renderstates/qrastermode_p.h b/src/render/renderstates/qrastermode_p.h
new file mode 100644
index 000000000..2e8e790de
--- /dev/null
+++ b/src/render/renderstates/qrastermode_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DRENDER_QRASTERMODE_P_H
+#define QT3DRENDER_QRASTERMODE_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/qrenderstate_p.h>
+#include <Qt3DRender/qrastermode.h>
+#include <Qt3DRender/private/qt3drender_global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class Q_3DRENDERSHARED_PRIVATE_EXPORT QRasterModePrivate : public QRenderStatePrivate
+{
+public :
+ QRasterModePrivate()
+ : QRenderStatePrivate(Render::RasterModeMask)
+ , m_rasterMode(QRasterMode::Fill)
+ , m_faceMode(QRasterMode::FrontAndBack)
+ {
+ }
+
+ Q_DECLARE_PUBLIC(QRasterMode)
+ QRasterMode::RasterMode m_rasterMode;
+ QRasterMode::FaceMode m_faceMode;
+};
+
+struct QRasterModeData
+{
+ QRasterMode::FaceMode faceMode;
+ QRasterMode::RasterMode rasterMode;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QRASTERMODE_P_H
diff --git a/src/render/renderstates/qseamlesscubemap.cpp b/src/render/renderstates/qseamlesscubemap.cpp
index 860b36450..8458aded8 100644
--- a/src/render/renderstates/qseamlesscubemap.cpp
+++ b/src/render/renderstates/qseamlesscubemap.cpp
@@ -40,7 +40,6 @@
#include "qseamlesscubemap.h"
#include "qrenderstate_p.h"
#include <private/qnode_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/renderstates/qstenciloperation.cpp b/src/render/renderstates/qstenciloperation.cpp
index af7e014f5..34f95c03d 100644
--- a/src/render/renderstates/qstenciloperation.cpp
+++ b/src/render/renderstates/qstenciloperation.cpp
@@ -40,7 +40,6 @@
#include "qstenciloperation.h"
#include "qstenciloperation_p.h"
#include "qstenciloperationarguments.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
QT_BEGIN_NAMESPACE
@@ -106,7 +105,7 @@ QStencilOperation::QStencilOperation(QNode *parent)
{
Q_D(QStencilOperation);
- const auto resend = [d]() { d->resendArguments(); };
+ const auto resend = [d]() { d->update(); };
(void) connect(d->m_front, &QStencilOperationArguments::allTestsPassOperationChanged, resend);
(void) connect(d->m_front, &QStencilOperationArguments::depthTestFailureOperationChanged, resend);
@@ -125,17 +124,6 @@ QStencilOperation::~QStencilOperation()
}
/*! \internal */
-void QStencilOperationPrivate::resendArguments()
-{
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(m_id);
- QStencilOperationData data;
- fillData(data);
- e->setPropertyName("arguments");
- e->setValue(QVariant::fromValue(data));
- notifyObservers(e);
-}
-
-/*! \internal */
void QStencilOperationPrivate::fillData(QStencilOperationData &data) const
{
data.front.face = m_front->faceMode();
diff --git a/src/render/renderstates/qstenciloperation_p.h b/src/render/renderstates/qstenciloperation_p.h
index a1c0cda4a..d38abf0d7 100644
--- a/src/render/renderstates/qstenciloperation_p.h
+++ b/src/render/renderstates/qstenciloperation_p.h
@@ -76,7 +76,6 @@ public:
QStencilOperationArguments *m_front;
QStencilOperationArguments *m_back;
- void resendArguments();
void fillData(QStencilOperationData &data) const;
};
diff --git a/src/render/renderstates/qstenciltest.cpp b/src/render/renderstates/qstenciltest.cpp
index a364c3b88..7284af140 100644
--- a/src/render/renderstates/qstenciltest.cpp
+++ b/src/render/renderstates/qstenciltest.cpp
@@ -41,7 +41,6 @@
#include "qstenciltest.h"
#include "qstenciltest_p.h"
#include "qstenciltestarguments.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
QT_BEGIN_NAMESPACE
@@ -109,7 +108,7 @@ QStencilTest::QStencilTest(QNode *parent)
{
Q_D(QStencilTest);
- const auto resend = [d]() { d->resendArguments(); };
+ const auto resend = [d]() { d->update(); };
(void) connect(d->m_front, &QStencilTestArguments::comparisonMaskChanged, resend);
(void) connect(d->m_front, &QStencilTestArguments::faceModeChanged, resend);
@@ -128,17 +127,6 @@ QStencilTest::~QStencilTest()
}
/*! \internal */
-void QStencilTestPrivate::resendArguments()
-{
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(m_id);
- QStencilTestData data;
- fillData(data);
- e->setPropertyName("arguments");
- e->setValue(QVariant::fromValue(data));
- notifyObservers(e);
-}
-
-/*! \internal */
void QStencilTestPrivate::fillData(QStencilTestData &data) const
{
data.front.face = m_front->faceMode();
diff --git a/src/render/renderstates/qstenciltest_p.h b/src/render/renderstates/qstenciltest_p.h
index 328e34878..9ddfc6e33 100644
--- a/src/render/renderstates/qstenciltest_p.h
+++ b/src/render/renderstates/qstenciltest_p.h
@@ -78,7 +78,6 @@ public:
QStencilTestArguments *m_front;
QStencilTestArguments *m_back;
- void resendArguments();
void fillData(QStencilTestData &data) const;
};
diff --git a/src/render/renderstates/renderstatenode.cpp b/src/render/renderstates/renderstatenode.cpp
index 52d5e20ce..3040c5aaa 100644
--- a/src/render/renderstates/renderstatenode.cpp
+++ b/src/render/renderstates/renderstatenode.cpp
@@ -37,7 +37,6 @@
#include "renderstatenode_p.h"
#include <Qt3DRender/qrenderstate.h>
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qalphacoverage.h>
#include <Qt3DRender/qalphatest.h>
@@ -51,8 +50,12 @@
#include <Qt3DRender/qcullface.h>
#include <Qt3DRender/private/qcullface_p.h>
#include <Qt3DRender/qnodepthmask.h>
+#include <Qt3DRender/qdepthrange.h>
+#include <Qt3DRender/private/qdepthrange_p.h>
#include <Qt3DRender/qdepthtest.h>
#include <Qt3DRender/private/qdepthtest_p.h>
+#include <Qt3DRender/qrastermode.h>
+#include <Qt3DRender/private/qrastermode_p.h>
#include <Qt3DRender/qdithering.h>
#include <Qt3DRender/qfrontface.h>
#include <Qt3DRender/private/qfrontface_p.h>
@@ -86,106 +89,105 @@ namespace Render {
namespace {
-StateVariant createStateImplementation(const Qt3DRender::QRenderStateCreatedChangeBasePtr renderStateChange)
+StateVariant createStateImplementation(const QRenderState *node)
{
- switch (renderStateChange->renderStateType()) {
+ const QRenderStatePrivate *d = static_cast<const QRenderStatePrivate *>(Qt3DCore::QNodePrivate::get(node));
+ switch (d->m_type) {
case AlphaCoverageStateMask: {
return StateVariant::createState<AlphaCoverage>();
}
case AlphaTestMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QAlphaTestData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<AlphaFunc>(data.alphaFunction, data.referenceValue);
+ const QAlphaTest *alphaTest = static_cast<const QAlphaTest *>(node);
+ return StateVariant::createState<AlphaFunc>(alphaTest->alphaFunction(), alphaTest->referenceValue());
}
case BlendStateMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QBlendEquationData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<BlendEquation>(data.blendFunction);
+ const QBlendEquation *blendEquation = static_cast<const QBlendEquation *>(node);
+ return StateVariant::createState<BlendEquation>(blendEquation->blendFunction());
}
case BlendEquationArgumentsMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QBlendEquationArgumentsData>>(renderStateChange);
- const auto &data = typedChange->data;
+ const QBlendEquationArguments *blendArgs = static_cast<const QBlendEquationArguments *>(node);
return StateVariant::createState<BlendEquationArguments>(
- data.sourceRgb, data.destinationRgb,
- data.sourceAlpha, data.destinationAlpha,
- renderStateChange->isNodeEnabled(),
- data.bufferIndex);
+ blendArgs->sourceRgb(), blendArgs->destinationRgb(),
+ blendArgs->sourceAlpha(), blendArgs->destinationAlpha(),
+ blendArgs->isEnabled(),
+ blendArgs->bufferIndex());
}
case MSAAEnabledStateMask: {
- return StateVariant::createState<MSAAEnabled>(renderStateChange->isNodeEnabled());
+ return StateVariant::createState<MSAAEnabled>(node->isEnabled());
}
case CullFaceStateMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QCullFaceData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<CullFace>(data.mode);
+ const QCullFace *cullFace = static_cast<const QCullFace *>(node);
+ return StateVariant::createState<CullFace>(cullFace->mode());
+ }
+
+ case DepthRangeMask: {
+ const QDepthRange *depthRange = static_cast<const QDepthRange *>(node);
+ return StateVariant::createState<DepthRange>(depthRange->nearValue(), depthRange->farValue());
}
case DepthWriteStateMask: {
- return StateVariant::createState<NoDepthMask>(false);
+ return StateVariant::createState<NoDepthMask>(!node->isEnabled());
}
case DepthTestStateMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QDepthTestData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<DepthTest>(data.depthFunction);
+ const QDepthTest *depthTest = static_cast<const QDepthTest *>(node);
+ return StateVariant::createState<DepthTest>(depthTest->depthFunction());
+ }
+
+ case RasterModeMask: {
+ const QRasterMode *rasterMode = static_cast<const QRasterMode *>(node);
+ return StateVariant::createState<RasterMode>(rasterMode->faceMode(), rasterMode->rasterMode());
}
case FrontFaceStateMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QFrontFaceData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<FrontFace>(data.direction);
+ const QFrontFace *frontFace = static_cast<const QFrontFace *>(node);
+ return StateVariant::createState<FrontFace>(frontFace->direction());
}
case ScissorStateMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QScissorTestData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<ScissorTest>(data.left, data.bottom,
- data.width, data.height);
+ const QScissorTest *scissorTest = static_cast<const QScissorTest *>(node);
+ return StateVariant::createState<ScissorTest>(scissorTest->left(), scissorTest->bottom(),
+ scissorTest->width(), scissorTest->height());
}
case StencilTestStateMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QStencilTestData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<StencilTest>(data.front.stencilFunction,
- data.front.referenceValue,
- data.front.comparisonMask,
- data.back.stencilFunction,
- data.back.referenceValue,
- data.back.comparisonMask);
+ const QStencilTest *stencilTest = static_cast<const QStencilTest *>(node);
+ return StateVariant::createState<StencilTest>(stencilTest->front()->stencilFunction(),
+ stencilTest->front()->referenceValue(),
+ stencilTest->front()->comparisonMask(),
+ stencilTest->back()->stencilFunction(),
+ stencilTest->back()->referenceValue(),
+ stencilTest->back()->comparisonMask());
}
case PointSizeMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QPointSizeData>>(renderStateChange);
- const auto &data = typedChange->data;
- const bool isProgrammable = (data.sizeMode == QPointSize::Programmable);
- return StateVariant::createState<PointSize>(isProgrammable, data.value);
+ const QPointSize *pointSize = static_cast<const QPointSize *>(node);
+ const bool isProgrammable = (pointSize->sizeMode() == QPointSize::Programmable);
+ return StateVariant::createState<PointSize>(isProgrammable, pointSize->value());
}
case PolygonOffsetStateMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QPolygonOffsetData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<PolygonOffset>(data.scaleFactor, data.depthSteps);
+ const QPolygonOffset *offset = static_cast<const QPolygonOffset *>(node);
+ return StateVariant::createState<PolygonOffset>(offset->scaleFactor(), offset->depthSteps());
}
case ColorStateMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QColorMaskData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<ColorMask>(data.redMasked, data.greenMasked,
- data.blueMasked, data.alphaMasked);
+ const QColorMask *colorMask = static_cast<const QColorMask *>(node);
+ return StateVariant::createState<ColorMask>(colorMask->isRedMasked(), colorMask->isGreenMasked(),
+ colorMask->isBlueMasked(), colorMask->isAlphaMasked());
}
case ClipPlaneMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QClipPlaneData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<ClipPlane>(data.planeIndex,
- data.normal,
- data.distance);
+ const QClipPlane *clipPlane = static_cast<const QClipPlane *>(node);
+ return StateVariant::createState<ClipPlane>(clipPlane->planeIndex(),
+ clipPlane->normal(),
+ clipPlane->distance());
}
case SeamlessCubemapMask: {
@@ -193,21 +195,19 @@ StateVariant createStateImplementation(const Qt3DRender::QRenderStateCreatedChan
}
case StencilOpMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QStencilOperationData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<StencilOp>(data.front.stencilTestFailureOperation,
- data.front.depthTestFailureOperation,
- data.front.allTestsPassOperation,
- data.back.stencilTestFailureOperation,
- data.back.depthTestFailureOperation,
- data.back.allTestsPassOperation);
+ const QStencilOperation *stencilOp = static_cast<const QStencilOperation *>(node);
+ return StateVariant::createState<StencilOp>(stencilOp->front()->stencilTestFailureOperation(),
+ stencilOp->front()->depthTestFailureOperation(),
+ stencilOp->front()->allTestsPassOperation(),
+ stencilOp->back()->stencilTestFailureOperation(),
+ stencilOp->back()->depthTestFailureOperation(),
+ stencilOp->back()->allTestsPassOperation());
}
case StencilWriteStateMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QStencilMaskData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<StencilMask>(data.frontOutputMask,
- data.backOutputMask);
+ const QStencilMask *stencilMask = static_cast<const QStencilMask *>(node);
+ return StateVariant::createState<StencilMask>(stencilMask->frontOutputMask(),
+ stencilMask->backOutputMask());
}
case DitheringStateMask: {
@@ -215,9 +215,8 @@ StateVariant createStateImplementation(const Qt3DRender::QRenderStateCreatedChan
}
case LineWidthMask: {
- const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QLineWidthData>>(renderStateChange);
- const auto &data = typedChange->data;
- return StateVariant::createState<LineWidth>(data.value, data.smooth);
+ const QLineWidth *lineWidth = static_cast<const QLineWidth *>(node);
+ return StateVariant::createState<LineWidth>(lineWidth->value(), lineWidth->smooth());
}
default:
@@ -242,21 +241,19 @@ void RenderStateNode::cleanup()
{
}
-void RenderStateNode::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chang3)
+void RenderStateNode::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime)
{
- cleanup();
- const auto renderStateChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChangeBase>(chang3);
- m_impl = createStateImplementation(renderStateChange);
-}
+ const QRenderState *node = qobject_cast<const QRenderState *>(frontEnd);
+ if (!node)
+ return;
-void RenderStateNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- if (e->type() == Qt3DCore::PropertyUpdated) {
- Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- m_impl.state()->updateProperty(propertyChange->propertyName(), propertyChange->value());
- markDirty(AbstractRenderer::AllDirty);
- }
- BackendNode::sceneChangeEvent(e);
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+
+ if (firstTime)
+ m_impl = createStateImplementation(node);
+
+ m_impl.state()->updateProperties(node);
+ markDirty(AbstractRenderer::AllDirty);
}
} // namespace Render
diff --git a/src/render/renderstates/renderstatenode_p.h b/src/render/renderstates/renderstatenode_p.h
index 277b8a7c8..e0258112f 100644
--- a/src/render/renderstates/renderstatenode_p.h
+++ b/src/render/renderstates/renderstatenode_p.h
@@ -63,8 +63,7 @@ public:
RenderStateNode();
virtual ~RenderStateNode();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
-
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
StateMask type() const { return m_impl.type; }
StateVariant impl() const { return m_impl; }
@@ -72,7 +71,6 @@ protected:
void cleanup();
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
StateVariant m_impl;
};
diff --git a/src/render/renderstates/renderstates.cpp b/src/render/renderstates/renderstates.cpp
index d6be80b1c..5e238c010 100644
--- a/src/render/renderstates/renderstates.cpp
+++ b/src/render/renderstates/renderstates.cpp
@@ -40,7 +40,6 @@
#include "renderstates_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qrenderstate.h>
#include <Qt3DRender/qcullface.h>
#include <Qt3DRender/qpointsize.h>
@@ -48,140 +47,181 @@
#include <Qt3DRender/private/graphicscontext_p.h>
#include <Qt3DRender/private/qstenciloperation_p.h>
#include <Qt3DRender/private/qstenciltest_p.h>
+#include <Qt3DRender/qblendequationarguments.h>
+#include <Qt3DRender/qblendequation.h>
+#include <Qt3DRender/qalphatest.h>
+#include <Qt3DRender/qdepthrange.h>
+#include <Qt3DRender/qdepthtest.h>
+#include <Qt3DRender/qrastermode.h>
+#include <Qt3DRender/qfrontface.h>
+#include <Qt3DRender/qscissortest.h>
+#include <Qt3DRender/qpolygonoffset.h>
+#include <Qt3DRender/qcolormask.h>
+#include <Qt3DRender/qclipplane.h>
+#include <Qt3DRender/qstencilmask.h>
+#include <Qt3DRender/qlinewidth.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
-void RenderStateImpl::updateProperty(const char *name, const QVariant &value)
+void RenderStateImpl::updateProperties(const QRenderState *)
{
- Q_UNUSED(name);
- Q_UNUSED(value);
}
-void BlendEquationArguments::updateProperty(const char *name, const QVariant &value)
+void BlendEquationArguments::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("sourceRgb")) std::get<0>(m_values) = value.toInt();
- else if (name == QByteArrayLiteral("destinationRgb")) std::get<1>(m_values) = value.toInt();
- else if (name == QByteArrayLiteral("sourceAlpha")) std::get<2>(m_values) = value.toInt();
- else if (name == QByteArrayLiteral("destinationAlpha")) std::get<3>(m_values) = value.toInt();
- else if (name == QByteArrayLiteral("enabled")) std::get<4>(m_values) = value.toBool();
- else if (name == QByteArrayLiteral("bufferIndex")) std::get<5>(m_values) = value.toInt();
+ const QBlendEquationArguments *args = static_cast<const QBlendEquationArguments *>(node);
+
+ std::get<0>(m_values) = args->sourceRgb();
+ std::get<1>(m_values) = args->destinationRgb();
+ std::get<2>(m_values) = args->sourceAlpha();
+ std::get<3>(m_values) = args->destinationAlpha();
+ std::get<4>(m_values) = args->isEnabled();
+ std::get<5>(m_values) = args->bufferIndex();
}
-void BlendEquation::updateProperty(const char *name, const QVariant &value)
+void BlendEquation::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("blendFunction")) std::get<0>(m_values) = value.toInt();
+ const QBlendEquation *equation = static_cast<const QBlendEquation *>(node);
+ std::get<0>(m_values) = equation->blendFunction();
}
-void AlphaFunc::updateProperty(const char *name, const QVariant &value)
+void AlphaFunc::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("alphaFunction"))
- std::get<0>(m_values) = value.toInt();
- if (name == QByteArrayLiteral("referenceValue"))
- std::get<1>(m_values) = value.toFloat();
+ const QAlphaTest *alphaTest = static_cast<const QAlphaTest *>(node);
+ std::get<0>(m_values) = alphaTest->alphaFunction();
+ std::get<1>(m_values) = alphaTest->referenceValue();
}
-void MSAAEnabled::updateProperty(const char *name, const QVariant &value)
+void MSAAEnabled::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("enabled"))
- std::get<0>(m_values) = value.toBool();
+ std::get<0>(m_values) = node->isEnabled();
+}
+
+void DepthRange::updateProperties(const QRenderState *node)
+{
+ const QDepthRange *depthRange = static_cast<const QDepthRange *>(node);
+
+ std::get<0>(m_values) = depthRange->nearValue();
+ std::get<1>(m_values) = depthRange->farValue();
+}
+
+void DepthTest::updateProperties(const QRenderState *node)
+{
+ const QDepthTest *depthTest = static_cast<const QDepthTest *>(node);
+
+ std::get<0>(m_values) = depthTest->depthFunction();
}
-void DepthTest::updateProperty(const char *name, const QVariant &value)
+void RasterMode::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("depthFunction")) std::get<0>(m_values) = value.toInt();
+ const QRasterMode *rasterMode = static_cast<const QRasterMode *>(node);
+
+ std::get<0>(m_values) = rasterMode->faceMode();
+ std::get<1>(m_values) = rasterMode->rasterMode();
}
-void CullFace::updateProperty(const char *name, const QVariant &value)
+void CullFace::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("mode")) std::get<0>(m_values) = value.toInt();
+ const QCullFace *cullFace = static_cast<const QCullFace *>(node);
+
+ std::get<0>(m_values) = cullFace->mode();
}
-void FrontFace::updateProperty(const char *name, const QVariant &value)
+void FrontFace::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("direction")) std::get<0>(m_values) = value.toInt();
+ const QFrontFace *frontFace = static_cast<const QFrontFace *>(node);
+
+ std::get<0>(m_values) = frontFace->direction();
}
-void NoDepthMask::updateProperty(const char *name, const QVariant &value)
+void NoDepthMask::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("mask")) std::get<0>(m_values) = value.toBool();
+ std::get<0>(m_values) = !node->isEnabled();
}
-void ScissorTest::updateProperty(const char *name, const QVariant &value)
+void ScissorTest::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("left")) std::get<0>(m_values) = value.toInt();
- else if (name == QByteArrayLiteral("bottom")) std::get<1>(m_values) = value.toInt();
- else if (name == QByteArrayLiteral("width")) std::get<2>(m_values) = value.toInt();
- else if (name == QByteArrayLiteral("height")) std::get<3>(m_values) = value.toInt();
+ const QScissorTest *scissorTest = static_cast<const QScissorTest *>(node);
+
+ std::get<0>(m_values) = scissorTest->left();
+ std::get<1>(m_values) = scissorTest->bottom();
+ std::get<2>(m_values) = scissorTest->width();
+ std::get<3>(m_values) = scissorTest->height();
}
-void StencilTest::updateProperty(const char *name, const QVariant &value)
+void StencilTest::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("arguments")) {
- const QStencilTestData data = value.value<QStencilTestData>();
- std::get<0>(m_values) = data.front.stencilFunction;
- std::get<1>(m_values) = data.front.referenceValue;
- std::get<2>(m_values) = data.front.comparisonMask;
- std::get<3>(m_values) = data.back.stencilFunction;
- std::get<4>(m_values) = data.back.referenceValue;
- std::get<5>(m_values) = data.back.comparisonMask;
- }
+ const QStencilTest *stencilTest = static_cast<const QStencilTest *>(node);
+ std::get<0>(m_values) = stencilTest->front()->stencilFunction();
+ std::get<1>(m_values) = stencilTest->front()->referenceValue();
+ std::get<2>(m_values) = stencilTest->front()->comparisonMask();
+ std::get<3>(m_values) = stencilTest->back()->stencilFunction();
+ std::get<4>(m_values) = stencilTest->back()->referenceValue();
+ std::get<5>(m_values) = stencilTest->back()->comparisonMask();
}
-void PointSize::updateProperty(const char *name, const QVariant &value)
+void PointSize::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("sizeMode")) std::get<0>(m_values) = (value.toInt() == QPointSize::Programmable);
- else if (name == QByteArrayLiteral("value")) std::get<1>(m_values) = value.toFloat();
+ const QPointSize *pointSize = static_cast<const QPointSize *>(node);
+
+ std::get<0>(m_values) = (pointSize->sizeMode() == QPointSize::Programmable);
+ std::get<1>(m_values) = pointSize->value();
}
-void PolygonOffset::updateProperty(const char *name, const QVariant &value)
+void PolygonOffset::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("scaleFactor")) std::get<0>(m_values) = value.toFloat();
- else if (name == QByteArrayLiteral("depthSteps")) std::get<1>(m_values) = value.toFloat();
+ const QPolygonOffset *offset = static_cast<const QPolygonOffset *>(node);
+
+ std::get<0>(m_values) = offset->scaleFactor();
+ std::get<1>(m_values) = offset->depthSteps();
}
-void ColorMask::updateProperty(const char *name, const QVariant &value)
+void ColorMask::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("redMasked")) std::get<0>(m_values) = value.toBool();
- else if (name == QByteArrayLiteral("greenMasked")) std::get<1>(m_values) = value.toBool();
- else if (name == QByteArrayLiteral("blueMasked")) std::get<2>(m_values) = value.toBool();
- else if (name == QByteArrayLiteral("alphaMasked")) std::get<3>(m_values) = value.toBool();
+ const QColorMask *colorMask = static_cast<const QColorMask *>(node);
+
+ std::get<0>(m_values) = colorMask->isRedMasked();
+ std::get<1>(m_values) = colorMask->isGreenMasked();
+ std::get<2>(m_values) = colorMask->isBlueMasked();
+ std::get<3>(m_values) = colorMask->isAlphaMasked();
}
-void ClipPlane::updateProperty(const char *name, const QVariant &value)
+void ClipPlane::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("planeIndex")) std::get<0>(m_values) = value.toInt();
- else if (name == QByteArrayLiteral("normal")) std::get<1>(m_values) = value.value<QVector3D>();
- else if (name == QByteArrayLiteral("distance")) std::get<2>(m_values) = value.toFloat();
+ const QClipPlane *clipPlane = static_cast<const QClipPlane *>(node);
+
+ std::get<0>(m_values) = clipPlane->planeIndex();
+ std::get<1>(m_values) = clipPlane->normal();
+ std::get<2>(m_values) = clipPlane->distance();
}
-void StencilOp::updateProperty(const char *name, const QVariant &value)
+void StencilOp::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("arguments")) {
- const QStencilOperationData data = value.value<QStencilOperationData>();
- std::get<0>(m_values) = data.front.stencilTestFailureOperation;
- std::get<1>(m_values) = data.front.depthTestFailureOperation;
- std::get<2>(m_values) = data.front.allTestsPassOperation;
- std::get<3>(m_values) = data.back.stencilTestFailureOperation;
- std::get<4>(m_values) = data.back.depthTestFailureOperation;
- std::get<5>(m_values) = data.back.allTestsPassOperation;
- }
+ const QStencilOperation *stencilOp = static_cast<const QStencilOperation *>(node);
+
+ std::get<0>(m_values) = stencilOp->front()->stencilTestFailureOperation();
+ std::get<1>(m_values) = stencilOp->front()->depthTestFailureOperation();
+ std::get<2>(m_values) = stencilOp->front()->allTestsPassOperation();
+ std::get<3>(m_values) = stencilOp->back()->stencilTestFailureOperation();
+ std::get<4>(m_values) = stencilOp->back()->depthTestFailureOperation();
+ std::get<5>(m_values) = stencilOp->back()->allTestsPassOperation();
}
-void StencilMask::updateProperty(const char *name, const QVariant &value)
+void StencilMask::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("frontOutputMask")) std::get<0>(m_values) = value.toInt();
- else if (name == QByteArrayLiteral("backOutputMask")) std::get<1>(m_values) = value.toInt();
+ const QStencilMask *stencilMask = static_cast<const QStencilMask *>(node);
+ std::get<0>(m_values) = stencilMask->frontOutputMask();
+ std::get<1>(m_values) = stencilMask->backOutputMask();
}
-void LineWidth::updateProperty(const char *name, const QVariant &value)
+void LineWidth::updateProperties(const QRenderState *node)
{
- if (name == QByteArrayLiteral("value"))
- std::get<0>(m_values) = value.toFloat();
- else if (name == QByteArrayLiteral("smooth"))
- std::get<1>(m_values) = value.toBool();
+ const QLineWidth *lineWidth = static_cast<const QLineWidth *>(node);
+ std::get<0>(m_values) = lineWidth->value();
+ std::get<1>(m_values) = lineWidth->smooth();
}
} // namespace Render
diff --git a/src/render/renderstates/renderstates.pri b/src/render/renderstates/renderstates.pri
index c6a041bd9..06ba53a41 100644
--- a/src/render/renderstates/renderstates.pri
+++ b/src/render/renderstates/renderstates.pri
@@ -24,6 +24,7 @@ HEADERS += \
$$PWD/renderstates_p.h \
$$PWD/qpointsize.h \
$$PWD/qseamlesscubemap.h \
+ $$PWD/qdepthrange.h \
$$PWD/qdepthtest.h \
$$PWD/qnodepthmask.h \
$$PWD/qlinewidth.h \
@@ -33,6 +34,7 @@ HEADERS += \
$$PWD/qclipplane_p.h \
$$PWD/qcolormask_p.h \
$$PWD/qcullface_p.h \
+ $$PWD/qdepthrange_p.h \
$$PWD/qdepthtest_p.h \
$$PWD/qfrontface_p.h \
$$PWD/qpointsize_p.h \
@@ -47,7 +49,9 @@ HEADERS += \
$$PWD/renderstatenode_p.h \
$$PWD/qmultisampleantialiasing.h \
$$PWD/statemask_p.h \
- $$PWD/statevariant_p.h
+ $$PWD/statevariant_p.h \
+ $$PWD/qrastermode.h \
+ $$PWD/qrastermode_p.h
SOURCES += \
$$PWD/qalphacoverage.cpp \
@@ -57,6 +61,7 @@ SOURCES += \
$$PWD/qclipplane.cpp \
$$PWD/qcolormask.cpp \
$$PWD/qcullface.cpp \
+ $$PWD/qdepthrange.cpp \
$$PWD/qdepthtest.cpp \
$$PWD/qdithering.cpp \
$$PWD/qfrontface.cpp \
@@ -76,4 +81,5 @@ SOURCES += \
$$PWD/qrenderstatecreatedchange.cpp \
$$PWD/renderstatenode.cpp \
$$PWD/statevariant.cpp \
- $$PWD/qmultisampleantialiasing.cpp
+ $$PWD/qmultisampleantialiasing.cpp \
+ $$PWD/qrastermode.cpp
diff --git a/src/render/renderstates/renderstates_p.h b/src/render/renderstates/renderstates_p.h
index eafaeb25f..6c8e9d551 100644
--- a/src/render/renderstates/renderstates_p.h
+++ b/src/render/renderstates/renderstates_p.h
@@ -62,49 +62,61 @@ namespace Render {
class Q_AUTOTEST_EXPORT BlendEquationArguments : public GenericState<BlendEquationArguments, BlendEquationArgumentsMask, GLenum, GLenum, GLenum, GLenum, bool, int>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT BlendEquation : public GenericState<BlendEquation, BlendStateMask, GLenum>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT AlphaFunc : public GenericState<AlphaFunc, AlphaTestMask, GLenum, GLclampf>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT MSAAEnabled : public GenericState<MSAAEnabled, MSAAEnabledStateMask, GLboolean>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
+};
+
+class Q_AUTOTEST_EXPORT DepthRange : public GenericState<DepthRange, DepthRangeMask, double, double>
+{
+public:
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT DepthTest : public GenericState<DepthTest, DepthTestStateMask, GLenum>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
+};
+
+class Q_AUTOTEST_EXPORT RasterMode : public GenericState<RasterMode, RasterModeMask, GLenum, GLenum>
+{
+public:
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT NoDepthMask : public GenericState<NoDepthMask, DepthWriteStateMask, GLboolean>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT CullFace : public GenericState<CullFace, CullFaceStateMask, GLenum>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT FrontFace : public GenericState<FrontFace, FrontFaceStateMask, GLenum>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT Dithering : public GenericState<Dithering, DitheringStateMask>
@@ -114,13 +126,13 @@ class Q_AUTOTEST_EXPORT Dithering : public GenericState<Dithering, DitheringStat
class Q_AUTOTEST_EXPORT ScissorTest : public GenericState<ScissorTest, ScissorStateMask, int, int, int, int>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT StencilTest : public GenericState<StencilTest, StencilTestStateMask, GLenum, int, uint, GLenum, int, uint>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT AlphaCoverage : public GenericState<AlphaCoverage, AlphaCoverageStateMask>
@@ -130,26 +142,26 @@ class Q_AUTOTEST_EXPORT AlphaCoverage : public GenericState<AlphaCoverage, Alpha
class Q_AUTOTEST_EXPORT PointSize : public GenericState<PointSize, PointSizeMask, bool, GLfloat>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT PolygonOffset : public GenericState<PolygonOffset, PolygonOffsetStateMask, GLfloat, GLfloat>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT ColorMask : public GenericState<ColorMask, ColorStateMask, GLboolean, GLboolean, GLboolean, GLboolean>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT ClipPlane : public GenericState<ClipPlane, ClipPlaneMask, int, QVector3D, float>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT SeamlessCubemap : public GenericState<SeamlessCubemap, SeamlessCubemapMask>
@@ -159,19 +171,19 @@ class Q_AUTOTEST_EXPORT SeamlessCubemap : public GenericState<SeamlessCubemap, S
class Q_AUTOTEST_EXPORT StencilOp : public GenericState<StencilOp, StencilOpMask, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT StencilMask : public GenericState<StencilMask, StencilWriteStateMask, uint, uint>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
class Q_AUTOTEST_EXPORT LineWidth : public GenericState<LineWidth, LineWidthMask, GLfloat, bool>
{
public:
- void updateProperty(const char *name, const QVariant &value) override;
+ void updateProperties(const QRenderState *node) override;
};
} // namespace Render
diff --git a/src/render/renderstates/statemask_p.h b/src/render/renderstates/statemask_p.h
index 1f3305747..ca64e30cd 100644
--- a/src/render/renderstates/statemask_p.h
+++ b/src/render/renderstates/statemask_p.h
@@ -81,6 +81,8 @@ enum StateMask
MSAAEnabledStateMask = 1 << 17,
BlendEquationArgumentsMask = 1 << 18,
LineWidthMask = 1 << 19,
+ DepthRangeMask = 1 << 20,
+ RasterModeMask = 1 << 21
};
} // namespace Render
diff --git a/src/render/renderstates/statevariant.cpp b/src/render/renderstates/statevariant.cpp
index 8161cba0b..47b3fd0a7 100644
--- a/src/render/renderstates/statevariant.cpp
+++ b/src/render/renderstates/statevariant.cpp
@@ -51,6 +51,7 @@ RenderStateImpl *StateVariant::state()
case BlendStateMask:
case AlphaTestMask:
case MSAAEnabledStateMask:
+ case DepthRangeMask:
case DepthTestStateMask:
case DepthWriteStateMask:
case CullFaceStateMask:
@@ -67,6 +68,7 @@ RenderStateImpl *StateVariant::state()
case StencilOpMask:
case StencilWriteStateMask:
case LineWidthMask:
+ case RasterModeMask:
return &data.blendEquationArguments;
default:
Q_UNREACHABLE();
@@ -80,6 +82,7 @@ const RenderStateImpl *StateVariant::constState() const
case BlendStateMask:
case AlphaTestMask:
case MSAAEnabledStateMask:
+ case DepthRangeMask:
case DepthTestStateMask:
case DepthWriteStateMask:
case CullFaceStateMask:
@@ -96,6 +99,7 @@ const RenderStateImpl *StateVariant::constState() const
case StencilOpMask:
case StencilWriteStateMask:
case LineWidthMask:
+ case RasterModeMask:
return &data.blendEquationArguments;
default:
Q_UNREACHABLE();
diff --git a/src/render/renderstates/statevariant_p.h b/src/render/renderstates/statevariant_p.h
index ac3c12682..ef6c80744 100644
--- a/src/render/renderstates/statevariant_p.h
+++ b/src/render/renderstates/statevariant_p.h
@@ -67,6 +67,7 @@ struct Q_AUTOTEST_EXPORT StateVariant
BlendEquation blendEquation;
AlphaFunc alphaFunc;
MSAAEnabled msaaEnabled;
+ DepthRange depthRange;
DepthTest depthTest;
NoDepthMask noDepthMask;
CullFace cullFace;
diff --git a/src/render/services/vsyncframeadvanceservice.cpp b/src/render/services/vsyncframeadvanceservice.cpp
index 8749a54ab..b49870e68 100644
--- a/src/render/services/vsyncframeadvanceservice.cpp
+++ b/src/render/services/vsyncframeadvanceservice.cpp
@@ -80,16 +80,7 @@ qint64 VSyncFrameAdvanceService::waitForNextFrame()
{
Q_D(VSyncFrameAdvanceService);
- // When rendering with Scene3D, we always want to acquire the available
- // amount + 1 to handle the cases where for some reason proceedToNextFrame
- // is being called more than once between calls to waitForNextFrame This
- // could be the case when resizing the window
-
- // When Qt3D is driving rendering however, this shouldn't happen
- if (d->m_drivenByRenderThread)
- d->m_semaphore.acquire(1);
- else
- d->m_semaphore.acquire(d->m_semaphore.available() + 1);
+ d->m_semaphore.acquire(std::max(d->m_semaphore.available(), 1));
const quint64 currentTime = d->m_elapsed.nsecsElapsed();
qCDebug(VSyncAdvanceService) << "Elapsed nsecs since last call " << currentTime - d->m_elapsedTimeSincePreviousFrame;
diff --git a/src/render/texture/apitexturemanager_p.h b/src/render/texture/apitexturemanager_p.h
deleted file mode 100644
index 79dc9af94..000000000
--- a/src/render/texture/apitexturemanager_p.h
+++ /dev/null
@@ -1,411 +0,0 @@
-/****************************************************************************
-**
-** 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) const
- {
- return m_nodeIdToGLTexture.value(textureId);
- }
-
- Qt3DCore::QNodeIdVector referencedTextureIds(APITexture *apiTexture) const
- {
- return m_sharedTextures.value(apiTexture);
- }
-
- // 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 Qt3DCore::QNodeId nodeId)
- {
- APITexture *apiTexture = m_nodeIdToGLTexture.take(nodeId);
- 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(nodeId);
-
- // If no texture nodes is referencing the shared APITexture, remove it
- if (referencedTextureNodes.empty()) {
- m_abandonedTextures.push_back(apiTexture);
- m_sharedTextures.remove(apiTexture);
- tex->destroyResources();
- }
- }
- }
-
- // 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 Qt3DCore::QNodeIdVector &imageIds)
- {
- Q_ASSERT(tex);
-
- if (isShared(tex))
- return false;
-
- // create Image structs
- QVector<APITextureImage> texImgs = texImgsFromNodes(imageIds);
- if (texImgs.size() != imageIds.size())
- return false;
-
- tex->setImages(texImgs);
- m_updatedTextures.push_back(tex);
-
- return true;
- }
-
- // Change the texture data generator for given texture, if it is a non-shared texture
- // Return true, if it was changed successfully, false otherwise
- bool setGenerator(APITexture *tex, const QTextureGeneratorPtr &generator)
- {
- Q_ASSERT(tex);
-
- if (isShared(tex))
- return false;
-
- tex->setGenerator(generator);
- m_updatedTextures.push_back(tex);
-
- return true;
- }
-
- // Change the texture's referenced texture Id from a shared context
- bool setSharedTextureId(APITexture *tex, int textureId)
- {
- Q_ASSERT(tex);
-
- if (isShared(tex))
- return false;
-
- tex->setSharedTextureId(textureId);
- 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.constFind(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 Qt3DCore::QNodeIdVector texImgs = texNode->textureImageIds();
- if (texImgGens.size() != texImgs.size())
- return false;
- for (int i = 0; i < texImgGens.size(); ++i) {
- const TextureImage *img = m_textureImageManager->lookupResource(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->textureImageIds());
- if (texImgs.empty() && !node->textureImageIds().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);
- newTex->setSharedTextureId(node->sharedTextureId());
-
- m_updatedTextures.push_back(newTex);
-
- return newTex;
- }
-
- QVector<APITextureImage> texImgsFromNodes(const Qt3DCore::QNodeIdVector &imageIds) const
- {
- QVector<APITextureImage> ret;
- ret.resize(imageIds.size());
-
- for (int i = 0; i < imageIds.size(); ++i) {
- const TextureImage *img = m_textureImageManager->lookupResource(imageIds[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/qabstracttexture.cpp b/src/render/texture/qabstracttexture.cpp
index 3d7d751a1..7fca2ba3f 100644
--- a/src/render/texture/qabstracttexture.cpp
+++ b/src/render/texture/qabstracttexture.cpp
@@ -81,10 +81,40 @@ void QAbstractTexturePrivate::setDataFunctor(const QTextureGeneratorPtr &generat
{
if (generator != m_dataFunctor) {
m_dataFunctor = generator;
- auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(m_id);
- change->setPropertyName("generator");
- change->setValue(QVariant::fromValue(generator));
- notifyObservers(change);
+ update();
+ }
+}
+
+void QAbstractTexturePrivate::setStatus(QAbstractTexture::Status status)
+{
+ Q_Q(QAbstractTexture);
+ if (m_status != status) {
+ m_status = status;
+ const bool blocked = q->blockNotifications(true);
+ q->statusChanged(status);
+ q->blockNotifications(blocked);
+ }
+}
+
+void QAbstractTexturePrivate::setHandle(const QVariant &handle)
+{
+ Q_Q(QAbstractTexture);
+ if (m_handle != handle) {
+ m_handle = handle;
+ const bool blocked = q->blockNotifications(true);
+ emit q->handleChanged(handle);
+ q->blockNotifications(blocked);
+ }
+}
+
+void QAbstractTexturePrivate::setHandleType(QAbstractTexture::HandleType type)
+{
+ Q_Q(QAbstractTexture);
+ if (m_handleType != type) {
+ m_handleType = type;
+ const bool blocked = q->blockNotifications(true);
+ emit q->handleTypeChanged(type);
+ q->blockNotifications(blocked);
}
}
@@ -94,12 +124,18 @@ void QAbstractTexturePrivate::setDataFunctor(const QTextureGeneratorPtr &generat
\since 5.5
\brief A base class to be used to provide textures.
- The QAbstractTexture class shouldn't be used directly but rather
- through one of its subclasses. Each subclass implements a given texture
- target (2D, 2DArray, 3D, CubeMap ...) Each subclass provides a set of
- functors for each layer, cube map face and mipmap level. In turn the
- backend uses those functor to properly fill a corresponding OpenGL texture
- with data.
+ The QAbstractTexture class shouldn't be used directly but rather through
+ one of its subclasses. Each subclass implements a given texture target (2D,
+ 2DArray, 3D, CubeMap ...) Each subclass provides a set of functors for each
+ layer, cube map face and mipmap level. In turn the backend uses those
+ functor to properly fill a corresponding OpenGL texture with data. It is
+ expected the functor does as minimal processing as possible so as not
+ to slow down textures generation and upload. If the content of a texture is
+ the result of a slow procedural generation process, it is recommended not
+ to implement this directly in a functor.
+
+ All textures are unique. If you instantiate twice the same texture this
+ will create 2 identical textures on the GPU, no sharing will take place.
*/
/*!
@@ -261,6 +297,8 @@ void QAbstractTexturePrivate::setDataFunctor(const QTextureGeneratorPtr &generat
\value RGBA4
GL_RGBA4
\value RGB10A2
+ GL_RGB10_A2
+ \value RGB10A2U
GL_RGB10_A2UI
\value D16
GL_DEPTH_COMPONENT16
@@ -624,7 +662,9 @@ void QAbstractTexture::setStatus(Status status)
Q_D(QAbstractTexture);
if (status != d->m_status) {
d->m_status = status;
+ const bool blocked = blockNotifications(true);
emit statusChanged(status);
+ blockNotifications(blocked);
}
}
@@ -740,11 +780,7 @@ void QAbstractTexture::addTextureImage(QAbstractTextureImage *textureImage)
if (!textureImage->parent())
textureImage->setParent(this);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeAddedChangePtr::create(id(), textureImage);
- change->setPropertyName("textureImage");
- d->notifyObservers(change);
- }
+ d->updateNode(textureImage, "textureImage", PropertyValueAdded);
}
}
@@ -755,11 +791,7 @@ void QAbstractTexture::removeTextureImage(QAbstractTextureImage *textureImage)
{
Q_ASSERT(textureImage);
Q_D(QAbstractTexture);
- if (d->m_changeArbiter != nullptr) {
- const auto change = QPropertyNodeRemovedChangePtr::create(id(), textureImage);
- change->setPropertyName("textureImage");
- d->notifyObservers(change);
- }
+ d->updateNode(textureImage, "textureImage", PropertyValueRemoved);
d->m_textureImages.removeOne(textureImage);
// Remove bookkeeping connection
d->unregisterDestructionHelper(textureImage);
@@ -895,24 +927,15 @@ void QAbstractTexture::setWrapMode(const QTextureWrapMode &wrapMode)
Q_D(QAbstractTexture);
if (d->m_wrapMode.x() != wrapMode.x()) {
d->m_wrapMode.setX(wrapMode.x());
- auto e = QPropertyUpdatedChangePtr::create(d->m_id);
- e->setPropertyName("wrapModeX");
- e->setValue(static_cast<int>(d->m_wrapMode.x()));
- d->notifyObservers(e);
+ d->update();
}
if (d->m_wrapMode.y() != wrapMode.y()) {
d->m_wrapMode.setY(wrapMode.y());
- auto e = QPropertyUpdatedChangePtr::create(d->m_id);
- e->setPropertyName("wrapModeY");
- e->setValue(static_cast<int>(d->m_wrapMode.y()));
- d->notifyObservers(e);
+ d->update();
}
if (d->m_wrapMode.z() != wrapMode.z()) {
d->m_wrapMode.setZ(wrapMode.z());
- auto e = QPropertyUpdatedChangePtr::create(d->m_id);
- e->setPropertyName("wrapModeZ");
- e->setValue(static_cast<int>(d->m_wrapMode.z()));
- d->notifyObservers(e);
+ d->update();
}
}
@@ -1074,6 +1097,19 @@ QVariant QAbstractTexture::handle() const
return d->m_handle;
}
+/*!
+ * Allow to update a sub region of the texture without having to change the data
+ * generator or rely on adding or removing texture images.
+ * \since 5.14
+ */
+void QAbstractTexture::updateData(const QTextureDataUpdate &update)
+{
+ Q_D(QAbstractTexture);
+
+ d->m_pendingDataUpdates.push_back(update);
+ d->update();
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QAbstractTexture::createNodeCreationChange() const
{
auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QAbstractTextureData>::create(this);
@@ -1098,7 +1134,8 @@ Qt3DCore::QNodeCreatedChangeBasePtr QAbstractTexture::createNodeCreationChange()
data.samples = d->m_samples;
data.dataFunctor = d->m_dataFunctor;
data.sharedTextureId = d->m_sharedTextureId;
- return creationChange;
+ data.initialDataUpdates = d->m_pendingDataUpdates;
+ return std::move(creationChange);
}
/*!
diff --git a/src/render/texture/qabstracttexture.h b/src/render/texture/qabstracttexture.h
index 6097e4449..b3d5efb34 100644
--- a/src/render/texture/qabstracttexture.h
+++ b/src/render/texture/qabstracttexture.h
@@ -52,7 +52,7 @@ class QAbstractTexturePrivate;
class QTextureWrapMode;
class QAbstractTextureImage;
class QTextureGenerator;
-
+class QTextureDataUpdate;
typedef QSharedPointer<QTextureGenerator> QTextureGeneratorPtr;
class Q_3DRENDERSHARED_EXPORT QAbstractTexture : public Qt3DCore::QNode
@@ -178,7 +178,8 @@ public:
R5G6B5 = 0x8D62, // GL_RGB565
RGB5A1 = 0x8057, // GL_RGB5_A1
RGBA4 = 0x8056, // GL_RGBA4
- RGB10A2 = 0x906F, // GL_RGB10_A2UI
+ RGB10A2 = 0x8059, // GL_RGB10_A2
+ RGB10A2U = 0x906F, // GL_RGB10_A2UI
// Depth formats
D16 = 0x81A5, // GL_DEPTH_COMPONENT16
@@ -309,6 +310,9 @@ public:
HandleType handleType() const;
QVariant handle() const;
+ Q_INVOKABLE void updateData(const QTextureDataUpdate &update);
+
+
public Q_SLOTS:
void setFormat(TextureFormat format);
void setGenerateMipMaps(bool gen);
@@ -346,6 +350,7 @@ protected:
explicit QAbstractTexture(QAbstractTexturePrivate &dd, Qt3DCore::QNode *parent = nullptr);
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
+ // TO DO Qt6, should be on private class
void setStatus(Status status);
void setHandle(const QVariant &handle);
void setHandleType(HandleType type);
diff --git a/src/render/texture/qabstracttexture_p.h b/src/render/texture/qabstracttexture_p.h
index f4bdecacc..5b2945f73 100644
--- a/src/render/texture/qabstracttexture_p.h
+++ b/src/render/texture/qabstracttexture_p.h
@@ -56,6 +56,7 @@
#include <Qt3DRender/qabstracttexture.h>
#include <Qt3DRender/qtexturewrapmode.h>
#include <Qt3DRender/qtexturegenerator.h>
+#include <Qt3DRender/qtexturedataupdate.h>
#include <Qt3DRender/private/qt3drender_global_p.h>
QT_BEGIN_NAMESPACE
@@ -95,6 +96,12 @@ public :
QTextureGeneratorPtr dataFunctor() const;
void setDataFunctor(const QTextureGeneratorPtr &generator);
+ void setStatus(QAbstractTexture::Status status);
+ void setHandle(const QVariant &handle);
+ void setHandleType(QAbstractTexture::HandleType type);
+
+ QVector<QTextureDataUpdate> m_pendingDataUpdates;
+
private:
QTextureGeneratorPtr m_dataFunctor;
};
@@ -120,6 +127,7 @@ struct QAbstractTextureData
int samples;
int sharedTextureId;
QTextureGeneratorPtr dataFunctor;
+ QVector<QTextureDataUpdate> initialDataUpdates;
};
} // QT3D
diff --git a/src/render/texture/qabstracttextureimage.cpp b/src/render/texture/qabstracttextureimage.cpp
index a95e1fffd..9ca4599c5 100644
--- a/src/render/texture/qabstracttextureimage.cpp
+++ b/src/render/texture/qabstracttextureimage.cpp
@@ -39,7 +39,6 @@
#include "qabstracttextureimage.h"
#include "qabstracttextureimage_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qtextureimagedatagenerator.h>
QT_BEGIN_NAMESPACE
@@ -94,6 +93,12 @@ QAbstractTextureImagePrivate::~QAbstractTextureImagePrivate()
{
}
+QTextureImageDataGeneratorPtr QAbstractTextureImagePrivate::dataGenerator() const
+{
+ Q_Q(const QAbstractTextureImage);
+ return q->dataGenerator();
+}
+
/*!
\qmltype AbstractTextureImage
\instantiates Qt3DRender::QAbstractTextureImage
@@ -255,12 +260,7 @@ void QAbstractTextureImage::setFace(QAbstractTexture::CubeMapFace face)
void QAbstractTextureImage::notifyDataGeneratorChanged()
{
Q_D(QAbstractTextureImage);
- if (d->m_changeArbiter != nullptr) {
- auto change = QPropertyUpdatedChangePtr::create(d->m_id);
- change->setPropertyName("dataGenerator");
- change->setValue(QVariant::fromValue(dataGenerator()));
- d->notifyObservers(change);
- }
+ d->update();
}
/*! \internal */
diff --git a/src/render/texture/qabstracttextureimage_p.h b/src/render/texture/qabstracttextureimage_p.h
index a5299acd7..f93d0e3ca 100644
--- a/src/render/texture/qabstracttextureimage_p.h
+++ b/src/render/texture/qabstracttextureimage_p.h
@@ -54,6 +54,7 @@
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DRender/private/qt3drender_global_p.h>
#include <Qt3DRender/qabstracttexture.h>
+#include <Qt3DRender/qtextureimagedatagenerator.h>
QT_BEGIN_NAMESPACE
@@ -72,6 +73,7 @@ public:
int m_mipLevel;
int m_layer;
QAbstractTexture::CubeMapFace m_face;
+ QTextureImageDataGeneratorPtr dataGenerator() const;
};
struct QAbstractTextureImageData
diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp
index 78a995b5d..bca66e630 100644
--- a/src/render/texture/qtexture.cpp
+++ b/src/render/texture/qtexture.cpp
@@ -40,6 +40,7 @@
#include "qtextureimage.h"
#include "qabstracttextureimage.h"
#include "qtextureimage_p.h"
+#include "qtextureimagedata_p.h"
#include "qtexturedata.h"
#include "qtexture.h"
#include "qtexture_p.h"
@@ -56,7 +57,6 @@
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/texture_p.h>
#include <Qt3DRender/private/qurlhelper_p.h>
-#include <Qt3DRender/private/texturedatamanager_p.h>
#include <Qt3DRender/private/gltexturemanager_p.h>
QT_BEGIN_NAMESPACE
@@ -452,7 +452,8 @@ enum ImageFormat {
GenericImageFormat = 0,
DDS,
PKM,
- HDR
+ HDR,
+ KTX
};
ImageFormat imageFormatFromSuffix(const QString &suffix)
@@ -463,9 +464,144 @@ ImageFormat imageFormatFromSuffix(const QString &suffix)
return DDS;
if (suffix == QStringLiteral("hdr"))
return HDR;
+ if (suffix == QStringLiteral("ktx"))
+ return KTX;
return GenericImageFormat;
}
+// NOTE: the ktx loading code is a near-duplication of the code in qt3d-runtime, and changes
+// should be kept up to date in both locations.
+quint32 blockSizeForTextureFormat(QOpenGLTexture::TextureFormat format)
+{
+ switch (format) {
+ case QOpenGLTexture::RGB8_ETC1:
+ case QOpenGLTexture::RGB8_ETC2:
+ case QOpenGLTexture::SRGB8_ETC2:
+ case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2:
+ case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2:
+ case QOpenGLTexture::R11_EAC_UNorm:
+ case QOpenGLTexture::R11_EAC_SNorm:
+ case QOpenGLTexture::RGB_DXT1:
+ return 8;
+
+ default:
+ return 16;
+ }
+}
+
+QTextureImageDataPtr setKtxFile(QIODevice *source)
+{
+ static const int KTX_IDENTIFIER_LENGTH = 12;
+ static const char ktxIdentifier[KTX_IDENTIFIER_LENGTH] = { '\xAB', 'K', 'T', 'X', ' ', '1', '1', '\xBB', '\r', '\n', '\x1A', '\n' };
+ static const quint32 platformEndianIdentifier = 0x04030201;
+ static const quint32 inversePlatformEndianIdentifier = 0x01020304;
+
+ struct KTXHeader {
+ quint8 identifier[KTX_IDENTIFIER_LENGTH];
+ quint32 endianness;
+ quint32 glType;
+ quint32 glTypeSize;
+ quint32 glFormat;
+ quint32 glInternalFormat;
+ quint32 glBaseInternalFormat;
+ quint32 pixelWidth;
+ quint32 pixelHeight;
+ quint32 pixelDepth;
+ quint32 numberOfArrayElements;
+ quint32 numberOfFaces;
+ quint32 numberOfMipmapLevels;
+ quint32 bytesOfKeyValueData;
+ };
+
+ KTXHeader header;
+ QTextureImageDataPtr imageData;
+ if (source->read(reinterpret_cast<char *>(&header), sizeof(header)) != sizeof(header)
+ || qstrncmp(reinterpret_cast<char *>(header.identifier), ktxIdentifier, KTX_IDENTIFIER_LENGTH) != 0
+ || (header.endianness != platformEndianIdentifier && header.endianness != inversePlatformEndianIdentifier))
+ {
+ return imageData;
+ }
+
+ const bool isInverseEndian = (header.endianness == inversePlatformEndianIdentifier);
+ auto decode = [isInverseEndian](quint32 val) {
+ return isInverseEndian ? qbswap<quint32>(val) : val;
+ };
+
+ const bool isCompressed = decode(header.glType) == 0 && decode(header.glFormat) == 0 && decode(header.glTypeSize) == 1;
+ if (!isCompressed) {
+ qWarning("Uncompressed ktx texture data is not supported");
+ return imageData;
+ }
+
+ if (decode(header.numberOfArrayElements) != 0) {
+ qWarning("Array ktx textures not supported");
+ return imageData;
+ }
+
+ if (decode(header.pixelDepth) != 0) {
+ qWarning("Only 2D and cube ktx textures are supported");
+ return imageData;
+ }
+
+ const int bytesToSkip = decode(header.bytesOfKeyValueData);
+ if (source->read(bytesToSkip).count() != bytesToSkip) {
+ qWarning("Unexpected end of ktx data");
+ return imageData;
+ }
+
+ const int level0Width = decode(header.pixelWidth);
+ const int level0Height = decode(header.pixelHeight);
+ const int faceCount = decode(header.numberOfFaces);
+ const int mipMapLevels = decode(header.numberOfMipmapLevels);
+ const QOpenGLTexture::TextureFormat format = QOpenGLTexture::TextureFormat(decode(header.glInternalFormat));
+ const int blockSize = blockSizeForTextureFormat(format);
+
+ // now for each mipmap level we have (arrays and 3d textures not supported here)
+ // uint32 imageSize
+ // for each array element
+ // for each face
+ // for each z slice
+ // compressed data
+ // padding so that each face data starts at an offset that is a multiple of 4
+ // padding so that each imageSize starts at an offset that is a multiple of 4
+
+ // assumes no depth or uncompressed textures (per above)
+ auto computeMipMapLevelSize = [&] (int level) {
+ const int w = qMax(level0Width >> level, 1);
+ const int h = qMax(level0Height >> level, 1);
+ return ((w + 3) / 4) * ((h + 3) / 4) * blockSize;
+ };
+
+ int dataSize = 0;
+ for (auto i = 0; i < mipMapLevels; ++i)
+ dataSize += computeMipMapLevelSize(i) * faceCount + 4; // assumes a single layer (per above)
+
+ const QByteArray rawData = source->read(dataSize);
+ if (rawData.size() < dataSize) {
+ qWarning() << "Unexpected end of data in" << source;
+ return imageData;
+ }
+
+ if (!source->atEnd())
+ qWarning() << "Unrecognized data in" << source;
+
+ imageData = QTextureImageDataPtr::create();
+ imageData->setTarget(faceCount == 6 ? QOpenGLTexture::TargetCubeMap : QOpenGLTexture::Target2D);
+ imageData->setFormat(format);
+ imageData->setWidth(level0Width);
+ imageData->setHeight(level0Height);
+ imageData->setLayers(1);
+ imageData->setDepth(1);
+ imageData->setFaces(faceCount);
+ imageData->setMipLevels(mipMapLevels);
+ imageData->setPixelFormat(QOpenGLTexture::NoSourceFormat);
+ imageData->setPixelType(QOpenGLTexture::NoPixelType);
+ imageData->setData(rawData, blockSize, true);
+ QTextureImageDataPrivate::get(imageData.data())->m_isKtx = true; // see note in QTextureImageDataPrivate
+
+ return imageData;
+}
+
QTextureImageDataPtr setPkmFile(QIODevice *source)
{
QTextureImageDataPtr imageData;
@@ -890,6 +1026,10 @@ QTextureImageDataPtr TextureLoadingHelper::loadTextureData(QIODevice *data, cons
case HDR:
textureData = setHdrFile(data);
break;
+ case KTX: {
+ textureData = setKtxFile(data);
+ break;
+ }
default: {
QImage img;
if (img.load(data, suffix.toLatin1())) {
@@ -925,7 +1065,8 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()()
auto downloadService = Qt3DCore::QDownloadHelperService::getService(m_engine);
Qt3DCore::QDownloadRequestPtr request(new TextureDownloadRequest(sharedFromThis(),
m_url,
- m_engine));
+ m_engine,
+ m_texture));
downloadService->submitRequest(request);
}
return generatedData;
@@ -974,10 +1115,12 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()()
TextureDownloadRequest::TextureDownloadRequest(const QTextureFromSourceGeneratorPtr &functor,
const QUrl &source,
- Qt3DCore::QAspectEngine *engine)
+ Qt3DCore::QAspectEngine *engine,
+ Qt3DCore::QNodeId texNodeId)
: Qt3DCore::QDownloadRequest(source)
, m_functor(functor)
, m_engine(engine)
+ , m_texNodeId(texNodeId)
{
}
@@ -992,46 +1135,23 @@ void TextureDownloadRequest::onCompleted()
if (!d_aspect)
return;
- // Find all textures which share the same functor
- // Note: this should be refactored to not pull in API specific managers
- // but texture sharing forces us to do that currently
- Render::TextureDataManager *textureDataManager = d_aspect->m_nodeManagers->textureDataManager();
- const QVector<Render::GLTexture *> referencedGLTextures = textureDataManager->referencesForGenerator(m_functor);
-
- // We should have at most 1 GLTexture referencing this
- // Since all textures having the same source should have the same functor == same GLTexture
- Q_ASSERT(referencedGLTextures.size() <= 1);
-
- Render::GLTexture *glTex = referencedGLTextures.size() > 0 ? referencedGLTextures.first() : nullptr;
- if (glTex == nullptr)
- return;
-
- Render::GLTextureManager *glTextureManager = d_aspect->m_nodeManagers->glTextureManager();
- Qt3DCore::QNodeIdVector referencingTexturesIds = glTextureManager->referencedTextureIds(glTex);
-
-
Render::TextureManager *textureManager = d_aspect->m_nodeManagers->textureManager();
- for (const Qt3DCore::QNodeId texId : referencingTexturesIds) {
- Render::Texture *texture = textureManager->lookupResource(texId);
- if (texture != nullptr) {
- // Each texture has a QTextureFunctor which matches m_functor;
- // Update m_sourceData on each functor as we don't know which one
- // is used as the reference for texture sharing
+ Render::Texture *texture = textureManager->lookupResource(m_texNodeId);
+ if (texture == nullptr)
+ return;
- QTextureFromSourceGeneratorPtr oldGenerator = qSharedPointerCast<QTextureFromSourceGenerator>(texture->dataGenerator());
+ QTextureFromSourceGeneratorPtr oldGenerator = qSharedPointerCast<QTextureFromSourceGenerator>(texture->dataGenerator());
- // We create a new functor
- // Which is a copy of the old one + the downloaded sourceData
- auto newGenerator = QTextureFromSourceGeneratorPtr::create(*oldGenerator);
+ // We create a new functor
+ // Which is a copy of the old one + the downloaded sourceData
+ auto newGenerator = QTextureFromSourceGeneratorPtr::create(*oldGenerator);
- // Set raw data on functor so that it can really load something
- newGenerator->m_sourceData = m_data;
+ // Set raw data on functor so that it can really load something
+ newGenerator->m_sourceData = m_data;
- // Set new generator on texture
- // it implictely marks the texture as dirty so that the functor runs again with the downloaded data
- texture->setDataGenerator(newGenerator);
- }
- }
+ // Set new generator on texture
+ // it implictely marks the texture as dirty so that the functor runs again with the downloaded data
+ texture->setDataGenerator(newGenerator);
}
/*!
@@ -1440,6 +1560,11 @@ void QTextureLoader::setSource(const QUrl& source)
Q_D(QTextureLoader);
if (source != d->m_source) {
d->m_source = source;
+
+ // Reset target and format
+ d->m_target = TargetAutomatic;
+ setFormat(NoFormat);
+
d->updateGenerator();
const bool blocked = blockNotifications(true);
emit sourceChanged(source);
diff --git a/src/render/texture/qtexture_p.h b/src/render/texture/qtexture_p.h
index 012b719ff..6b06aecd1 100644
--- a/src/render/texture/qtexture_p.h
+++ b/src/render/texture/qtexture_p.h
@@ -84,13 +84,15 @@ class Q_AUTOTEST_EXPORT TextureDownloadRequest : public Qt3DCore::QDownloadReque
public:
TextureDownloadRequest(const QTextureFromSourceGeneratorPtr &functor,
const QUrl &url,
- Qt3DCore::QAspectEngine *engine);
+ Qt3DCore::QAspectEngine *engine,
+ Qt3DCore::QNodeId texNodeId);
void onCompleted() override;
private:
QTextureFromSourceGeneratorPtr m_functor;
Qt3DCore::QAspectEngine *m_engine;
+ Qt3DCore::QNodeId m_texNodeId;
};
class Q_AUTOTEST_EXPORT QTextureFromSourceGenerator : public QTextureGenerator,
diff --git a/src/render/texture/qtexturedataupdate.cpp b/src/render/texture/qtexturedataupdate.cpp
new file mode 100644
index 000000000..e3d5220f0
--- /dev/null
+++ b/src/render/texture/qtexturedataupdate.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qtexturedataupdate.h"
+#include "qtexturedataupdate_p.h"
+#include <iostream>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender
+{
+
+static bool operator==(const QTextureDataUpdatePrivate &lhs, const QTextureDataUpdatePrivate &rhs) noexcept
+{
+ return lhs.m_x == rhs.m_x &&
+ lhs.m_y == rhs.m_y &&
+ lhs.m_z == rhs.m_z &&
+ lhs.m_layer == rhs.m_layer &&
+ lhs.m_mipLevel == rhs.m_mipLevel &&
+ lhs.m_face == rhs.m_face &&
+ lhs.m_data == rhs.m_data;
+}
+
+/*!
+ \class Qt3DRender::QTextureDataUpdate
+ \inmodule Qt3DRender
+ \brief QTextureDataUpdate holds content and information required to perform
+ partial updates of a texture content.
+
+ The actual data content is contained in a QTextureImageDataPtr member.
+ Additional members allow to specify the x, y, z offset of the content update
+ as well as the eventual layer, mipLevel and face.
+
+ \sa QAbstractTexture
+ \since 5.14
+ */
+
+QTextureDataUpdate::QTextureDataUpdate()
+ : d_ptr(new QTextureDataUpdatePrivate())
+{
+}
+
+QTextureDataUpdate::QTextureDataUpdate(const QTextureDataUpdate &other)
+ = default;
+
+QTextureDataUpdate &QTextureDataUpdate::operator=(const QTextureDataUpdate &other)
+ = default;
+
+QTextureDataUpdate::~QTextureDataUpdate()
+ = default;
+
+bool operator==(const QTextureDataUpdate &lhs, const QTextureDataUpdate &rhs) noexcept
+{
+ return *lhs.d_func() == *rhs.d_func();
+}
+
+int QTextureDataUpdate::x() const
+{
+ Q_D(const QTextureDataUpdate);
+ return d->m_x;
+}
+
+int QTextureDataUpdate::y() const
+{
+ Q_D(const QTextureDataUpdate);
+ return d->m_y;
+}
+
+int QTextureDataUpdate::z() const
+{
+ Q_D(const QTextureDataUpdate);
+ return d->m_z;
+}
+
+int QTextureDataUpdate::layer() const
+{
+ Q_D(const QTextureDataUpdate);
+ return d->m_layer;
+}
+
+int QTextureDataUpdate::mipLevel() const
+{
+ Q_D(const QTextureDataUpdate);
+ return d->m_mipLevel;
+}
+
+QAbstractTexture::CubeMapFace QTextureDataUpdate::face() const
+{
+ Q_D(const QTextureDataUpdate);
+ return d->m_face;
+}
+
+QTextureImageDataPtr QTextureDataUpdate::data() const
+{
+ Q_D(const QTextureDataUpdate);
+ return d->m_data;
+}
+
+void QTextureDataUpdate::setX(int x)
+{
+ d_ptr.detach();
+ Q_D(QTextureDataUpdate);
+ d->m_x = x;
+}
+
+void QTextureDataUpdate::setY(int y)
+{
+ d_ptr.detach();
+ Q_D(QTextureDataUpdate);
+ d->m_y = y;
+}
+
+void QTextureDataUpdate::setZ(int z)
+{
+ d_ptr.detach();
+ Q_D(QTextureDataUpdate);
+ d->m_z = z;
+}
+
+void QTextureDataUpdate::setLayer(int layer)
+{
+ d_ptr.detach();
+ Q_D(QTextureDataUpdate);
+ d->m_layer = layer;
+}
+
+void QTextureDataUpdate::setMipLevel(int mipLevel)
+{
+ d_ptr.detach();
+ Q_D(QTextureDataUpdate);
+ d->m_mipLevel = mipLevel;
+}
+
+void QTextureDataUpdate::setFace(QAbstractTexture::CubeMapFace face)
+{
+ d_ptr.detach();
+ Q_D(QTextureDataUpdate);
+ d->m_face = face;
+}
+
+void QTextureDataUpdate::setData(const QTextureImageDataPtr &data)
+{
+ d_ptr.detach();
+ Q_D(QTextureDataUpdate);
+ d->m_data = data;
+}
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/texture/qtexturedataupdate.h b/src/render/texture/qtexturedataupdate.h
new file mode 100644
index 000000000..3505d85fa
--- /dev/null
+++ b/src/render/texture/qtexturedataupdate.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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_QTEXTUREDATAUPDATE_H
+#define QT3DRENDER_QTEXTUREDATAUPDATE_H
+
+#include <Qt3DRender/qt3drender_global.h>
+#include <Qt3DRender/qabstracttexture.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender
+{
+
+class QTextureDataUpdate;
+class QTextureDataUpdatePrivate;
+
+Q_3DRENDERSHARED_EXPORT bool operator==(const QTextureDataUpdate &lhs, const QTextureDataUpdate &rhs) noexcept;
+
+class Q_3DRENDERSHARED_EXPORT QTextureDataUpdate
+{
+public:
+ QTextureDataUpdate();
+ QTextureDataUpdate(const QTextureDataUpdate &other);
+ QTextureDataUpdate &operator=(const QTextureDataUpdate &other);
+ QTextureDataUpdate &operator=(QTextureDataUpdate &&other) noexcept
+ { swap(other); return *this; }
+ ~QTextureDataUpdate();
+
+ void swap(QTextureDataUpdate &other) noexcept { qSwap(d_ptr, other.d_ptr); }
+
+ int x() const;
+ int y() const;
+ int z() const;
+ int layer() const;
+ int mipLevel() const;
+ QAbstractTexture::CubeMapFace face() const;
+ QTextureImageDataPtr data() const;
+
+ void setX(int x);
+ void setY(int y);
+ void setZ(int z);
+ void setLayer(int layer);
+ void setMipLevel(int mipLevel);
+ void setFace(QAbstractTexture::CubeMapFace face);
+ void setData(const QTextureImageDataPtr &data);
+
+private:
+ friend Q_3DRENDERSHARED_EXPORT bool operator==(const QTextureDataUpdate &lhs, const QTextureDataUpdate &rhs) noexcept;
+ Q_DECLARE_PRIVATE(QTextureDataUpdate)
+ QExplicitlySharedDataPointer<QTextureDataUpdatePrivate> d_ptr;
+};
+QT3D_DECLARE_TYPEINFO(Qt3DRender, QTextureDataUpdate, Q_MOVABLE_TYPE)
+
+inline bool operator!=(const QTextureDataUpdate &lhs, const QTextureDataUpdate &rhs) noexcept
+{ return !operator==(lhs, rhs); }
+
+inline void swap(QTextureDataUpdate &lhs, QTextureDataUpdate &rhs) noexcept { return lhs.swap(rhs); }
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Qt3DRender::QTextureDataUpdate)
+
+
+#endif // QT3DRENDER_QTEXTUREDATAUPDATE_H
diff --git a/src/render/texture/qtexturedataupdate_p.h b/src/render/texture/qtexturedataupdate_p.h
new file mode 100644
index 000000000..e6be170e9
--- /dev/null
+++ b/src/render/texture/qtexturedataupdate_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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_QTEXTUREDATAUPDATE_P_H
+#define QT3DRENDER_QTEXTUREDATAUPDATE_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/qtextureimagedata.h>
+#include <Qt3DRender/qabstracttexture.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QTextureDataUpdatePrivate : public QSharedData
+{
+public:
+ int m_x = 0;
+ int m_y = 0;
+ int m_z = 0;
+ int m_layer = 0;
+ int m_mipLevel = 0;
+ QAbstractTexture::CubeMapFace m_face = QAbstractTexture::CubeMapPositiveX;
+ QTextureImageDataPtr m_data;
+};
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QTEXTUREDATAUPDATE_P_H
diff --git a/src/render/texture/qtextureimage.cpp b/src/render/texture/qtextureimage.cpp
index 6bcdaba7d..b4e9ed46f 100644
--- a/src/render/texture/qtextureimage.cpp
+++ b/src/render/texture/qtextureimage.cpp
@@ -289,10 +289,12 @@ QImageTextureDataFunctor::QImageTextureDataFunctor(const QUrl &url, bool mirrore
QTextureImageDataPtr QImageTextureDataFunctor::operator ()()
{
+ if (!m_url.isValid())
+ return QTextureImageDataPtr();
+
// 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
-
if (!Qt3DCore::QDownloadHelperService::isLocal(m_url))
qWarning() << "QTextureImage only supports local url";
diff --git a/src/render/texture/qtextureimagedata.cpp b/src/render/texture/qtextureimagedata.cpp
index bf43a6e16..28d296feb 100644
--- a/src/render/texture/qtextureimagedata.cpp
+++ b/src/render/texture/qtextureimagedata.cpp
@@ -59,9 +59,25 @@ QTextureImageDataPrivate::QTextureImageDataPrivate()
, m_pixelFormat(QOpenGLTexture::RGBA)
, m_pixelType(QOpenGLTexture::UInt8)
, m_isCompressed(false)
+ , m_isKtx(false)
{
}
+QByteArray QTextureImageDataPrivate::ktxData(int layer, int face, int mipmapLevel) const
+{
+ Q_ASSERT(layer >= 0 && layer < m_layers &&
+ face >= 0 && face < m_faces &&
+ mipmapLevel >= 0 && mipmapLevel < m_mipLevels);
+
+ int offset = 0;
+ for (int i = 0; i < mipmapLevel; i++)
+ offset += (mipmapLevelSize(i) * m_faces * m_layers) + 4;
+ const int selectedMipmapLevelSize = mipmapLevelSize(mipmapLevel);
+ offset += (selectedMipmapLevelSize * m_faces * layer) + (selectedMipmapLevelSize * face) + 4;
+
+ return QByteArray::fromRawData(m_data.constData() + offset, selectedMipmapLevelSize);
+}
+
QByteArray QTextureImageDataPrivate::data(int layer, int face, int mipmapLevel) const
{
if (layer < 0 || layer >= m_layers ||
@@ -71,7 +87,10 @@ QByteArray QTextureImageDataPrivate::data(int layer, int face, int mipmapLevel)
return QByteArray();
}
- int offset = layer * layerSize() + face * faceSize();
+ if (m_isKtx)
+ return ktxData(layer, face, mipmapLevel);
+
+ int offset = layer * ddsLayerSize() + face * ddsFaceSize();
for (int i = 0; i < mipmapLevel; i++)
offset += mipmapLevelSize(i);
@@ -93,12 +112,12 @@ void QTextureImageDataPrivate::setData(const QByteArray &data,
m_blockSize = blockSize;
}
-int QTextureImageDataPrivate::layerSize() const
+int QTextureImageDataPrivate::ddsLayerSize() const
{
- return m_faces * faceSize();
+ return m_faces * ddsFaceSize();
}
-int QTextureImageDataPrivate::faceSize() const
+int QTextureImageDataPrivate::ddsFaceSize() const
{
int size = 0;
diff --git a/src/render/texture/qtextureimagedata_p.h b/src/render/texture/qtextureimagedata_p.h
index 8bb836d5b..d9a0952de 100644
--- a/src/render/texture/qtextureimagedata_p.h
+++ b/src/render/texture/qtextureimagedata_p.h
@@ -82,17 +82,20 @@ public:
QOpenGLTexture::PixelType m_pixelType;
bool m_isCompressed;
+ // ### Qt 6
+ // QTextureImageData was originally written with assumptions around the internal data format
+ // matching dds layout. This is an ugly, but easy, way to add basic ktx support without any
+ // public API changes. Consider https://codereview.qt-project.org/#/c/178474/ for Qt 6.
+ bool m_isKtx;
QByteArray m_data;
static QTextureImageDataPrivate *get(QTextureImageData *imageData);
private:
- int layerSize() const;
- int faceSize() const;
+ int ddsLayerSize() const;
+ int ddsFaceSize() const;
int mipmapLevelSize(int level) const;
-
- bool setPkmFile(const QString &source);
- bool setDdsFile(const QString &source);
+ QByteArray ktxData(int layer, int face, int mipmapLevel) const;
};
} // namespace Qt3DRender
diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp
index 17fd47be3..d120c2b39 100644
--- a/src/render/texture/texture.cpp
+++ b/src/render/texture/texture.cpp
@@ -47,7 +47,6 @@
#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>
@@ -62,6 +61,7 @@ Texture::Texture()
// We need backend -> frontend notifications to update the status of the texture
: BackendNode(ReadWrite)
, m_dirty(DirtyImageGenerators|DirtyProperties|DirtyParameters|DirtyDataGenerator)
+ , m_sharedTextureId(-1)
{
}
@@ -93,20 +93,6 @@ void Texture::unsetDirty()
m_dirty = Texture::NotDirty;
}
-void Texture::addTextureImage(Qt3DCore::QNodeId id)
-{
- if (!m_textureImageIds.contains(id)) {
- m_textureImageIds.push_back(id);
- addDirtyFlag(DirtyImageGenerators);
- }
-}
-
-void Texture::removeTextureImage(Qt3DCore::QNodeId id)
-{
- m_textureImageIds.removeAll(id);
- addDirtyFlag(DirtyImageGenerators);
-}
-
// This is called by Renderer::updateGLResources
// when the texture has been marked for cleanup
void Texture::cleanup()
@@ -115,6 +101,7 @@ void Texture::cleanup()
// texture is being referenced by a shared API specific texture (GLTexture)
m_dataFunctor.reset();
m_textureImageIds.clear();
+ m_pendingTextureDataUpdates.clear();
m_sharedTextureId = -1;
// set default values
@@ -124,94 +111,64 @@ void Texture::cleanup()
m_dirty = NotDirty;
}
-// ChangeArbiter/Aspect Thread
-void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+void Texture::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- DirtyFlags dirty;
-
- switch (e->type()) {
- case PropertyUpdated: {
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("width")) {
- m_properties.width = propertyChange->value().toInt();
- dirty = DirtyProperties;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("height")) {
- m_properties.height = propertyChange->value().toInt();
- dirty = DirtyProperties;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("depth")) {
- m_properties.depth = 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")) {
- m_properties.generateMipMaps = propertyChange->value().toBool();
- dirty = DirtyProperties;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("minificationFilter")) {
- m_parameters.minificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt());
- dirty = DirtyParameters;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("magnificationFilter")) {
- m_parameters.magnificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt());
- dirty = DirtyParameters;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeX")) {
- m_parameters.wrapModeX = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt());
- dirty = DirtyParameters;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeY")) {
- m_parameters.wrapModeY = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt());
- dirty = DirtyParameters;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeZ")) {
- m_parameters.wrapModeZ =static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt());
- dirty = DirtyParameters;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("maximumAnisotropy")) {
- m_parameters.maximumAnisotropy = propertyChange->value().toFloat();
- dirty = DirtyParameters;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("comparisonFunction")) {
- m_parameters.comparisonFunction = propertyChange->value().value<QAbstractTexture::ComparisonFunction>();
- dirty = DirtyParameters;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("comparisonMode")) {
- 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;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("generator")) {
- setDataGenerator(propertyChange->value().value<QTextureGeneratorPtr>());
- } else if (propertyChange->propertyName() == QByteArrayLiteral("textureId")) {
- m_sharedTextureId = propertyChange->value().toInt();
- dirty = DirtySharedTextureId;
- }
- }
- break;
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ const QAbstractTexture *node = qobject_cast<const QAbstractTexture *>(frontEnd);
+ if (!node)
+ return;
- case PropertyValueAdded: {
- const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("textureImage")) {
- addTextureImage(change->addedNodeId());
- }
+ TextureProperties p = m_properties;
+ p.width = node->width();
+ p.height = node->height();
+ p.depth = node->depth();
+ p.format = node->format();
+ p.target = node->target();
+ p.generateMipMaps = node->generateMipMaps();
+ p.layers = node->layers();
+ p.samples = node->samples();
+ if (p != m_properties) {
+ m_properties = p;
+ addDirtyFlag(DirtyProperties);
}
- break;
- case PropertyValueRemoved: {
- const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("textureImage")) {
- removeTextureImage(change->removedNodeId());
- }
+ TextureParameters q = m_parameters;
+ q.magnificationFilter = node->magnificationFilter();
+ q.minificationFilter = node->minificationFilter();
+ q.wrapModeX = const_cast<QAbstractTexture *>(node)->wrapMode()->x();
+ q.wrapModeY = const_cast<QAbstractTexture *>(node)->wrapMode()->y();
+ q.wrapModeZ = const_cast<QAbstractTexture *>(node)->wrapMode()->z();
+ q.maximumAnisotropy = node->maximumAnisotropy();
+ q.comparisonFunction = node->comparisonFunction();
+ q.comparisonMode = node->comparisonMode();
+ if (q != m_parameters) {
+ m_parameters = q;
+ addDirtyFlag(DirtyParameters);
}
- break;
- default:
- break;
+ auto newGenerator = node->dataGenerator();
+ if (newGenerator != m_dataFunctor) {
+ setDataGenerator(newGenerator);
+ }
+ QAbstractTexturePrivate *dnode = dynamic_cast<QAbstractTexturePrivate *>(QAbstractTexturePrivate::get(const_cast<QAbstractTexture *>(node)));
+ if (dnode) {
+ for (const QTextureDataUpdate &pendingUpdate : dnode->m_pendingDataUpdates)
+ addTextureDataUpdate(pendingUpdate);
+ dnode->m_pendingDataUpdates.clear();
+
+ auto ids = Qt3DCore::qIdsForNodes(dnode->m_textureImages);
+ std::sort(std::begin(ids), std::end(ids));
+ if (ids != m_textureImageIds) {
+ m_textureImageIds = ids;
+ addDirtyFlag(DirtyImageGenerators);
+ }
}
- addDirtyFlag(dirty);
- BackendNode::sceneChangeEvent(e);
+ if (dnode->m_sharedTextureId != m_sharedTextureId) {
+ m_sharedTextureId = dnode->m_sharedTextureId;
+ addDirtyFlag(DirtySharedTextureId);
+ }
}
// Called by sceneChangeEvent or TextureDownloadRequest (both in AspectThread context)
@@ -221,91 +178,9 @@ void Texture::setDataGenerator(const QTextureGeneratorPtr &generator)
addDirtyFlag(DirtyDataGenerator);
}
-// Called by sendTextureChangesToFrontendJob once GLTexture and sharing
-// has been performed
-void Texture::updatePropertiesAndNotify(const TextureUpdateInfo &updateInfo)
-{
- // If we are Dirty, some property has changed and the properties we have
- // received are potentially already outdated
- if (m_dirty != NotDirty)
- return;
-
- // Note we don't update target has it is constant for frontend nodes
-
- if (updateInfo.properties.width != m_properties.width) {
- m_properties.width = updateInfo.properties.width;
- auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- change->setPropertyName("width");
- change->setValue(updateInfo.properties.width);
- notifyObservers(change);
- }
-
- if (updateInfo.properties.height != m_properties.height) {
- m_properties.height = updateInfo.properties.height;
- auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- change->setPropertyName("height");
- change->setValue(updateInfo.properties.height);
- notifyObservers(change);
- }
-
- if (updateInfo.properties.depth != m_properties.depth) {
- m_properties.depth = updateInfo.properties.depth;
- auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- change->setPropertyName("depth");
- change->setValue(updateInfo.properties.depth);
- notifyObservers(change);
- }
-
- if (updateInfo.properties.layers != m_properties.layers) {
- m_properties.layers = updateInfo.properties.layers;
- auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- change->setPropertyName("layers");
- change->setValue(updateInfo.properties.layers);
- notifyObservers(change);
- }
-
- if (updateInfo.properties.format != m_properties.format) {
- m_properties.format = updateInfo.properties.format;
- auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- change->setPropertyName("format");
- change->setValue(updateInfo.properties.format);
- notifyObservers(change);
- }
-
- if (updateInfo.properties.status != m_properties.status) {
- m_properties.status = updateInfo.properties.status;
- auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- change->setPropertyName("status");
- change->setValue(updateInfo.properties.status);
- notifyObservers(change);
- }
-
- {
- auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- change->setPropertyName("handleType");
- change->setValue(updateInfo.handleType);
- notifyObservers(change);
- }
-
- {
- auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
- change->setPropertyName("handle");
- change->setValue(updateInfo.handle);
- notifyObservers(change);
- }
-}
-
bool Texture::isValid(TextureImageManager *manager) const
{
- for (const QNodeId id : m_textureImageIds) {
+ for (const QNodeId &id : m_textureImageIds) {
TextureImage *img = manager->lookupResource(id);
if (img == nullptr)
return false;
@@ -337,14 +212,25 @@ void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan
m_dataFunctor = data.dataFunctor;
m_sharedTextureId = data.sharedTextureId;
- for (const QNodeId imgId : data.textureImageIds)
- addTextureImage(imgId);
+ m_textureImageIds = data.textureImageIds;
+ if (m_textureImageIds.size())
+ addDirtyFlag(DirtyImageGenerators);
+
+ const QVector<QTextureDataUpdate> initialDataUpdates = data.initialDataUpdates;
+ for (const QTextureDataUpdate &initialUpdate : initialDataUpdates)
+ addTextureDataUpdate(initialUpdate);
addDirtyFlag(DirtyFlags(DirtyImageGenerators|DirtyProperties|DirtyParameters));
if (m_sharedTextureId > 0)
addDirtyFlag(DirtySharedTextureId);
}
+void Texture::addTextureDataUpdate(const QTextureDataUpdate &update)
+{
+ m_pendingTextureDataUpdates.push_back(update);
+ addDirtyFlag(DirtyPendingDataUpdates);
+}
+
TextureFunctor::TextureFunctor(AbstractRenderer *renderer,
TextureManager *textureNodeManager)
diff --git a/src/render/texture/texture.pri b/src/render/texture/texture.pri
index 0d520a9ec..87c77a2ff 100644
--- a/src/render/texture/texture.pri
+++ b/src/render/texture/texture.pri
@@ -8,7 +8,6 @@ HEADERS += \
$$PWD/qtextureimage_p.h \
$$PWD/qtexturewrapmode.h \
$$PWD/texture_p.h \
- $$PWD/texturedatamanager_p.h \
$$PWD/textureimage_p.h \
$$PWD/qabstracttexture.h \
$$PWD/qabstracttexture_p.h \
@@ -21,7 +20,8 @@ HEADERS += \
$$PWD/qtexture_p.h \
$$PWD/qpaintedtextureimage.h \
$$PWD/qpaintedtextureimage_p.h \
- $$PWD/apitexturemanager_p.h
+ $$PWD/qtexturedataupdate.h \
+ $$PWD/qtexturedataupdate_p.h
SOURCES += \
$$PWD/qabstracttextureimage.cpp \
@@ -34,4 +34,5 @@ SOURCES += \
$$PWD/qtextureimagedata.cpp \
$$PWD/qtexturedata.cpp \
$$PWD/qtexturegenerator.cpp \
- $$PWD/qpaintedtextureimage.cpp
+ $$PWD/qpaintedtextureimage.cpp \
+ $$PWD/qtexturedataupdate.cpp
diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h
index c60e90181..9e347243e 100644
--- a/src/render/texture/texture_p.h
+++ b/src/render/texture/texture_p.h
@@ -53,6 +53,7 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/handle_types_p.h>
+#include <Qt3DRender/private/qabstracttexture_p.h>
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qtexturedata.h>
#include <Qt3DRender/qtexturegenerator.h>
@@ -83,7 +84,7 @@ struct TextureProperties
int layers = 1;
int mipLevels = 1;
int samples = 1;
- QAbstractTexture::Target target = QAbstractTexture::Target2D;
+ QAbstractTexture::Target target = QAbstractTexture::TargetAutomatic;
QAbstractTexture::TextureFormat format = QAbstractTexture::NoFormat;
bool generateMipMaps = false;
QAbstractTexture::Status status = QAbstractTexture::None;
@@ -97,6 +98,7 @@ struct TextureProperties
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
@@ -134,11 +136,12 @@ public:
enum DirtyFlag {
NotDirty = 0,
- DirtyProperties = 0x1,
- DirtyParameters = 0x2,
- DirtyImageGenerators = 0x4,
- DirtyDataGenerator = 0x8,
- DirtySharedTextureId = 0x16
+ DirtyProperties = (1 << 0),
+ DirtyParameters = (1 << 1),
+ DirtyImageGenerators = (1 << 2),
+ DirtyDataGenerator = (1 << 3),
+ DirtySharedTextureId = (1 << 4),
+ DirtyPendingDataUpdates = (1 << 5),
};
Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
@@ -153,11 +156,12 @@ public:
DirtyFlags dirtyFlags();
void unsetDirty();
- void addTextureImage(Qt3DCore::QNodeId id);
- void removeTextureImage(Qt3DCore::QNodeId id);
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void addTextureDataUpdate(const QTextureDataUpdate &update);
+ QVector<QTextureDataUpdate> takePendingTextureDataUpdates() { return std::move(m_pendingTextureDataUpdates); }
+
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
inline const TextureProperties& properties() const { return m_properties; }
inline const TextureParameters& parameters() const { return m_parameters; }
@@ -166,7 +170,6 @@ public:
inline int sharedTextureId() const { return m_sharedTextureId; }
void setDataGenerator(const QTextureGeneratorPtr &generator);
- void updatePropertiesAndNotify(const TextureUpdateInfo &updateInfo);
bool isValid(TextureImageManager *manager) const;
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
@@ -180,6 +183,7 @@ private:
Qt3DCore::QNodeIdVector m_textureImageIds;
QMutex m_flagsMutex;
+ QVector<QTextureDataUpdate> m_pendingTextureDataUpdates;
};
class Q_AUTOTEST_EXPORT TextureFunctor : public Qt3DCore::QBackendNodeMapper
@@ -211,5 +215,6 @@ inline QDebug operator<<(QDebug dbg, const Texture &texture)
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Qt3DRender::Render::Texture*) // LCOV_EXCL_LINE
+Q_DECLARE_METATYPE(Qt3DRender::Render::TextureProperties) // LCOV_EXCL_LINE
#endif // QT3DRENDER_RENDER_TEXTURE_H
diff --git a/src/render/texture/texturedatamanager_p.h b/src/render/texture/texturedatamanager_p.h
deleted file mode 100644
index 9319a64e0..000000000
--- a/src/render/texture/texturedatamanager_p.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/****************************************************************************
-**
-** 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_TEXTUREDATAMANAGER_H
-#define QT3DRENDER_RENDER_TEXTUREDATAMANAGER_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 <QMutex>
-#include <QMutexLocker>
-#include <Qt3DRender/qtexture.h>
-#include <Qt3DRender/qtextureimagedata.h>
-#include <Qt3DRender/qtexturegenerator.h>
-#include <Qt3DRender/qtextureimagedatagenerator.h>
-#include <Qt3DRender/private/gltexture_p.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace Qt3DRender {
-namespace Render {
-
-/**
- * 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 ReferencedType>
-class GeneratorDataManager
-{
-public:
- GeneratorDataManager() {}
-
- /*!
- * If no data for the given generator exists, make sure that the
- * generators are executed the next frame. Reference generator by
- * given texture
- *
- * Returns true if the Entry for a given generator had to be created
- */
- bool requestData(const GeneratorPtr &generator, ReferencedType r)
- {
- QMutexLocker lock(&m_mutex);
-
- Entry *entry = findEntry(generator);
- const bool needsToBeCreated = (entry == nullptr);
- if (needsToBeCreated)
- entry = createEntry(generator);
- Q_ASSERT(entry);
- if (!entry->referencingObjects.contains(r))
- entry->referencingObjects.push_back(r);
- return needsToBeCreated;
- }
-
- QVector<ReferencedType> referencesForGenerator(const GeneratorPtr &generator)
- {
- QMutexLocker lock(&m_mutex);
-
- Entry *entry = findEntry(generator);
- if (entry == nullptr)
- return {};
- return entry->referencingObjects;
- }
-
-
- /*!
- * Dereference given generator from texture. If no other textures still reference
- * the generator, the associated data will be deleted
- */
- void releaseData(const GeneratorPtr &generator, ReferencedType r)
- {
- 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.referencingObjects.removeAll(r);
- // delete, if that was the last reference
- if (entry.referencingObjects.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";
- return;
- }
- entry->data = data;
- }
-
- bool contains(const GeneratorPtr &generator)
- {
- return findEntry(generator) != nullptr;
- }
-
-private:
-
- struct Entry {
- GeneratorPtr generator;
- QVector<ReferencedType> referencingObjects;
- 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;
-};
-
-class Q_AUTOTEST_EXPORT TextureDataManager
- : public GeneratorDataManager<QTextureGeneratorPtr, QTextureDataPtr, GLTexture*>
-{
-};
-
-class Q_AUTOTEST_EXPORT TextureImageDataManager
- : public GeneratorDataManager<QTextureImageDataGeneratorPtr, QTextureImageDataPtr, Qt3DCore::QNodeId>
-{
-};
-
-} // namespace Render
-} // namespace Qt3DRender
-
-QT_END_NAMESPACE
-
-#endif // TEXTUREDATAMANAGER_H
diff --git a/src/render/texture/textureimage.cpp b/src/render/texture/textureimage.cpp
index 880562b87..25001b9df 100644
--- a/src/render/texture/textureimage.cpp
+++ b/src/render/texture/textureimage.cpp
@@ -38,11 +38,9 @@
****************************************************************************/
#include "textureimage_p.h"
-#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qtextureimage.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/qabstracttextureimage_p.h>
-#include <Qt3DRender/private/texturedatamanager_p.h>
QT_BEGIN_NAMESPACE
@@ -57,7 +55,6 @@ TextureImage::TextureImage()
, m_layer(0)
, m_mipLevel(0)
, m_face(QAbstractTexture::CubeMapPositiveX)
- , m_textureImageDataManager(nullptr)
{
}
@@ -67,56 +64,46 @@ TextureImage::~TextureImage()
void TextureImage::cleanup()
{
- if (m_generator) {
- m_textureImageDataManager->releaseData(m_generator, peerId());
- m_generator.reset();
- }
+ m_generator.reset();
m_dirty = false;
m_layer = 0;
m_mipLevel = 0;
m_face = QAbstractTexture::CubeMapPositiveX;
}
-void TextureImage::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+void TextureImage::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAbstractTextureImageData>>(change);
- const auto &data = typedChange->data;
- m_mipLevel = data.mipLevel;
- m_layer = data.layer;
- m_face = data.face;
- m_generator = data.generator;
- m_dirty = true;
-
- // Request functor upload
- if (m_generator)
- m_textureImageDataManager->requestData(m_generator, peerId());
-}
+ const QAbstractTextureImage *node = qobject_cast<const QAbstractTextureImage *>(frontEnd);
+ if (!node)
+ return;
-void TextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
-{
- QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
-
- if (e->type() == PropertyUpdated) {
- if (propertyChange->propertyName() == QByteArrayLiteral("layer")) {
- m_layer = propertyChange->value().toInt();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("mipLevel")) {
- m_mipLevel = propertyChange->value().toInt();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("face")) {
- m_face = static_cast<QAbstractTexture::CubeMapFace>(propertyChange->value().toInt());
- } else if (propertyChange->propertyName() == QByteArrayLiteral("dataGenerator")) {
- // Release ref to generator
- if (m_generator)
- m_textureImageDataManager->releaseData(m_generator, peerId());
- m_generator = propertyChange->value().value<QTextureImageDataGeneratorPtr>();
- // Request functor upload
- if (m_generator)
- m_textureImageDataManager->requestData(m_generator, peerId());
- }
+ const bool oldEnabled = isEnabled();
+ BackendNode::syncFromFrontEnd(frontEnd, firstTime);
+ m_dirty |= (oldEnabled != isEnabled());
+
+ if (node->layer() != m_layer) {
+ m_layer = node->layer();
+ m_dirty = true;
+ }
+
+ if (node->mipLevel() != m_mipLevel) {
+ m_mipLevel = node->mipLevel();
+ m_dirty = true;
+ }
+
+ if (node->face() != m_face) {
+ m_face = node->face();
+ m_dirty = true;
+ }
+
+ const QAbstractTextureImagePrivate *d = static_cast<const QAbstractTextureImagePrivate *>(QNodePrivate::get(node));
+ if (d->dataGenerator() != m_generator) {
+ m_generator = d->dataGenerator();
m_dirty = true;
}
- markDirty(AbstractRenderer::AllDirty);
- BackendNode::sceneChangeEvent(e);
+ if (m_dirty)
+ markDirty(AbstractRenderer::AllDirty);
}
void TextureImage::unsetDirty()
@@ -125,18 +112,15 @@ void TextureImage::unsetDirty()
}
TextureImageFunctor::TextureImageFunctor(AbstractRenderer *renderer,
- TextureImageManager *textureImageManager,
- TextureImageDataManager *textureImageDataManager)
+ TextureImageManager *textureImageManager)
: m_renderer(renderer)
, m_textureImageManager(textureImageManager)
- , m_textureImageDataManager(textureImageDataManager)
{
}
Qt3DCore::QBackendNode *TextureImageFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const
{
TextureImage *backend = m_textureImageManager->getOrCreateResource(change->subjectId());
- backend->setTextureImageDataManager(m_textureImageDataManager);
backend->setRenderer(m_renderer);
return backend;
}
diff --git a/src/render/texture/textureimage_p.h b/src/render/texture/textureimage_p.h
index 19801ee77..57bbdea75 100644
--- a/src/render/texture/textureimage_p.h
+++ b/src/render/texture/textureimage_p.h
@@ -77,12 +77,7 @@ public:
~TextureImage();
void cleanup();
-
- void setTextureImageDataManager(TextureImageDataManager *dataManager) { m_textureImageDataManager = dataManager; }
-
- TextureImageDataManager *textureImageDataManager() const { return m_textureImageDataManager; }
-
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+ void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override;
inline int layer() const { return m_layer; }
inline int mipLevel() const { return m_mipLevel; }
@@ -92,23 +87,18 @@ public:
void unsetDirty();
private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
-
bool m_dirty;
int m_layer;
int m_mipLevel;
QAbstractTexture::CubeMapFace m_face;
QTextureImageDataGeneratorPtr m_generator;
-
- TextureImageDataManager *m_textureImageDataManager;
};
class TextureImageFunctor : public Qt3DCore::QBackendNodeMapper
{
public:
explicit TextureImageFunctor(AbstractRenderer *renderer,
- TextureImageManager *textureImageManager,
- TextureImageDataManager *textureImageDataManager);
+ TextureImageManager *textureImageManager);
Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const final;
Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const final;
@@ -117,7 +107,6 @@ public:
private:
AbstractRenderer *m_renderer;
TextureImageManager *m_textureImageManager;
- TextureImageDataManager *m_textureImageDataManager;
};
#ifndef QT_NO_DEBUG_STREAM