summaryrefslogtreecommitdiffstats
path: root/src/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/render')
-rw-r--r--src/render/backend/abstractrenderer_p.h1
-rw-r--r--src/render/backend/computecommand.cpp30
-rw-r--r--src/render/backend/computecommand_p.h8
-rw-r--r--src/render/backend/managers_p.h5
-rw-r--r--src/render/backend/nodemanagers.cpp2
-rw-r--r--src/render/backend/nodemanagers_p.h3
-rw-r--r--src/render/framegraph/blitframebuffer.cpp8
-rw-r--r--src/render/framegraph/cameraselectornode.cpp5
-rw-r--r--src/render/framegraph/clearbuffers.cpp6
-rw-r--r--src/render/framegraph/dispatchcompute.cpp11
-rw-r--r--src/render/framegraph/framegraph.pri14
-rw-r--r--src/render/framegraph/framegraphnode.cpp19
-rw-r--r--src/render/framegraph/framegraphnode_p.h4
-rw-r--r--src/render/framegraph/layerfilternode.cpp5
-rw-r--r--src/render/framegraph/memorybarrier.cpp2
-rw-r--r--src/render/framegraph/proximityfilter.cpp8
-rw-r--r--src/render/framegraph/qsetfence.cpp174
-rw-r--r--src/render/framegraph/qsetfence.h86
-rw-r--r--src/render/framegraph/qsetfence_p.h82
-rw-r--r--src/render/framegraph/qwaitfence.cpp219
-rw-r--r--src/render/framegraph/qwaitfence.h98
-rw-r--r--src/render/framegraph/qwaitfence_p.h85
-rw-r--r--src/render/framegraph/rendercapture.cpp1
-rw-r--r--src/render/framegraph/renderpassfilternode.cpp8
-rw-r--r--src/render/framegraph/rendersurfaceselector.cpp17
-rw-r--r--src/render/framegraph/rendertargetselectornode.cpp8
-rw-r--r--src/render/framegraph/setfence.cpp79
-rw-r--r--src/render/framegraph/setfence_p.h80
-rw-r--r--src/render/framegraph/sortpolicy.cpp2
-rw-r--r--src/render/framegraph/statesetnode.cpp4
-rw-r--r--src/render/framegraph/techniquefilternode.cpp8
-rw-r--r--src/render/framegraph/viewportnode.cpp3
-rw-r--r--src/render/framegraph/waitfence.cpp107
-rw-r--r--src/render/framegraph/waitfence_p.h85
-rw-r--r--src/render/frontend/qcomputecommand.cpp102
-rw-r--r--src/render/frontend/qcomputecommand.h13
-rw-r--r--src/render/frontend/qcomputecommand_p.h7
-rw-r--r--src/render/frontend/qpickingsettings.cpp8
-rw-r--r--src/render/frontend/qpickingsettings.h3
-rw-r--r--src/render/frontend/qrenderaspect.cpp15
-rw-r--r--src/render/geometry/geometry.cpp39
-rw-r--r--src/render/geometry/geometry_p.h10
-rw-r--r--src/render/geometry/qgeometry.cpp56
-rw-r--r--src/render/geometry/qgeometry.h8
-rw-r--r--src/render/geometry/qgeometry_p.h3
-rw-r--r--src/render/jobs/calcboundingvolumejob.cpp58
-rw-r--r--src/render/jobs/job_common_p.h3
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp16
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp132
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h14
-rw-r--r--src/render/jobs/raycastingjob.cpp6
-rw-r--r--src/render/jobs/sendbuffercapturejob.cpp6
-rw-r--r--src/render/jobs/sendbuffercapturejob_p.h1
-rw-r--r--src/render/materialsystem/qshaderprogrambuilder.cpp155
-rw-r--r--src/render/materialsystem/qshaderprogrambuilder.h19
-rw-r--r--src/render/materialsystem/qshaderprogrambuilder_p.h6
-rw-r--r--src/render/materialsystem/shaderbuilder.cpp33
-rw-r--r--src/render/picking/objectpicker.cpp15
-rw-r--r--src/render/picking/objectpicker_p.h5
-rw-r--r--src/render/picking/qobjectpicker.cpp37
-rw-r--r--src/render/picking/qobjectpicker.h5
-rw-r--r--src/render/picking/qobjectpicker_p.h3
-rw-r--r--src/render/renderers/opengl/graphicshelpers/glfence_p.h73
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp27
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h6
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp52
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h6
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp28
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h6
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp32
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h6
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp32
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h6
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp35
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h6
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h9
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri3
-rw-r--r--src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp47
-rw-r--r--src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h9
-rw-r--r--src/render/renderers/opengl/jobs/renderviewjobutils.cpp12
-rw-r--r--src/render/renderers/opengl/renderer/renderer.cpp159
-rw-r--r--src/render/renderers/opengl/renderer/renderer_p.h15
-rw-r--r--src/render/renderers/opengl/renderer/renderview.cpp5
-rw-r--r--src/render/renderers/opengl/renderer/renderview_p.h10
-rw-r--r--src/render/renderers/opengl/textures/gltexture.cpp260
-rw-r--r--src/render/renderers/opengl/textures/gltexture_p.h8
-rw-r--r--src/render/texture/apitexturemanager_p.h14
-rw-r--r--src/render/texture/qabstracttexture.cpp85
-rw-r--r--src/render/texture/qabstracttexture.h14
-rw-r--r--src/render/texture/qabstracttexture_p.h6
-rw-r--r--src/render/texture/qtexture.cpp63
-rw-r--r--src/render/texture/qtexture.h17
-rw-r--r--src/render/texture/texture.cpp61
-rw-r--r--src/render/texture/texture_p.h14
94 files changed, 2966 insertions, 215 deletions
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index f1bdca7be..f19db066c 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -153,6 +153,7 @@ public:
virtual bool shouldRender() = 0;
virtual void skipNextFrame() = 0;
+ virtual QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() = 0;
virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0;
virtual Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() = 0;
virtual Qt3DCore::QAspectJobPtr rayCastingJob() = 0;
diff --git a/src/render/backend/computecommand.cpp b/src/render/backend/computecommand.cpp
index 2b23df9aa..349941965 100644
--- a/src/render/backend/computecommand.cpp
+++ b/src/render/backend/computecommand.cpp
@@ -40,7 +40,6 @@
#include "computecommand_p.h"
#include <Qt3DCore/qnode.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DRender/qcomputecommand.h>
#include <Qt3DRender/private/qcomputecommand_p.h>
#include <Qt3DRender/private/abstractrenderer_p.h>
@@ -51,7 +50,9 @@ namespace Qt3DRender {
namespace Render {
ComputeCommand::ComputeCommand()
- : BackendNode(ReadOnly)
+ : BackendNode(ReadWrite)
+ , m_frameCount(0)
+ , m_runType(QComputeCommand::Continuous)
{
m_workGroups[0] = 1;
m_workGroups[1] = 1;
@@ -68,6 +69,8 @@ void ComputeCommand::cleanup()
m_workGroups[0] = 1;
m_workGroups[1] = 1;
m_workGroups[2] = 1;
+ m_frameCount = 0;
+ m_runType = QComputeCommand::Continuous;
}
void ComputeCommand::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
@@ -77,6 +80,8 @@ void ComputeCommand::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePt
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);
}
@@ -91,11 +96,30 @@ void ComputeCommand::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_workGroups[1] = propertyChange->value().toInt();
else if (propertyChange->propertyName() == QByteArrayLiteral("workGroupZ"))
m_workGroups[2] = propertyChange->value().toInt();
- markDirty(AbstractRenderer::AllDirty);
+ 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());
+ markDirty(AbstractRenderer::ComputeDirty);
}
BackendNode::sceneChangeEvent(e);
}
+// Called from buildComputeRenderCommands in a job
+void ComputeCommand::updateFrameCount()
+{
+ // Disable frontend node when reaching 0
+ --m_frameCount;
+ if (m_frameCount <= 0) {
+ setEnabled(false);
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("enabled");
+ e->setValue(false);
+ notifyObservers(e);
+ }
+}
+
} // Render
} // Qt3DRender
diff --git a/src/render/backend/computecommand_p.h b/src/render/backend/computecommand_p.h
index fb8ca39ff..10e10fd25 100644
--- a/src/render/backend/computecommand_p.h
+++ b/src/render/backend/computecommand_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DRender/private/backendnode_p.h>
+#include <Qt3DRender/qcomputecommand.h>
QT_BEGIN_NAMESPACE
@@ -73,10 +74,17 @@ public:
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]; }
+ inline int frameCount() const Q_DECL_NOTHROW { return m_frameCount; }
+ inline QComputeCommand::RunType runType() const Q_DECL_NOTHROW { return m_runType; }
+
+ // Called from a job
+ void updateFrameCount();
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) override;
int m_workGroups[3];
+ int m_frameCount;
+ QComputeCommand::RunType m_runType;
};
} // Render
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index b62e2f3e0..eb219fd1e 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -72,6 +72,7 @@
#include <Qt3DRender/private/shaderdata_p.h>
#include <Qt3DRender/private/handle_types_p.h>
#include <Qt3DRender/private/glbuffer_p.h>
+#include <Qt3DRender/private/glfence_p.h>
#include <Qt3DRender/private/textureimage_p.h>
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/geometry_p.h>
@@ -317,6 +318,10 @@ class GLBufferManager : public Qt3DCore::QResourceManager<
{
};
+class GLFenceManager : public QHash<Qt3DCore::QNodeId, GLFence>
+{
+};
+
class TextureImageManager : public Qt3DCore::QResourceManager<
TextureImage,
Qt3DCore::QNodeId,
diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp
index 5db35082d..584ddd65c 100644
--- a/src/render/backend/nodemanagers.cpp
+++ b/src/render/backend/nodemanagers.cpp
@@ -85,6 +85,7 @@ NodeManagers::NodeManagers()
, m_parameterManager(new ParameterManager())
, m_shaderDataManager(new ShaderDataManager())
, m_glBufferManager(new GLBufferManager())
+ , m_glFenceManager(new GLFenceManager())
, m_bufferManager(new BufferManager())
, m_attributeManager(new AttributeManager())
, m_geometryManager(new GeometryManager())
@@ -128,6 +129,7 @@ NodeManagers::~NodeManagers()
delete m_parameterManager;
delete m_shaderDataManager;
delete m_glBufferManager;
+ delete m_glFenceManager;
delete m_textureImageManager;
delete m_bufferManager;
delete m_attributeManager;
diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h
index 9277d4385..2c4926894 100644
--- a/src/render/backend/nodemanagers_p.h
+++ b/src/render/backend/nodemanagers_p.h
@@ -87,6 +87,7 @@ class AttachmentManager;
class ParameterManager;
class ShaderDataManager;
class GLBufferManager;
+class GLFenceManager;
class TextureImageManager;
class FilterKeyManager;
class FrameGraphManager;
@@ -210,6 +211,7 @@ public:
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; }
@@ -255,6 +257,7 @@ private:
ParameterManager *m_parameterManager;
ShaderDataManager *m_shaderDataManager;
GLBufferManager *m_glBufferManager;
+ GLFenceManager *m_glFenceManager;
BufferManager *m_bufferManager;
AttributeManager *m_attributeManager;
GeometryManager *m_geometryManager;
diff --git a/src/render/framegraph/blitframebuffer.cpp b/src/render/framegraph/blitframebuffer.cpp
index b9ff4bea3..342594baf 100644
--- a/src/render/framegraph/blitframebuffer.cpp
+++ b/src/render/framegraph/blitframebuffer.cpp
@@ -66,20 +66,26 @@ void BlitFramebuffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
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);
}
- markDirty(AbstractRenderer::AllDirty);
}
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/src/render/framegraph/cameraselectornode.cpp b/src/render/framegraph/cameraselectornode.cpp
index e21fdf02c..357611c7c 100644
--- a/src/render/framegraph/cameraselectornode.cpp
+++ b/src/render/framegraph/cameraselectornode.cpp
@@ -70,9 +70,10 @@ 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"))
+ if (propertyChange->propertyName() == QByteArrayLiteral("camera")) {
m_cameraUuid = propertyChange->value().value<QNodeId>();
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/src/render/framegraph/clearbuffers.cpp b/src/render/framegraph/clearbuffers.cpp
index d730123c3..ab6225a4b 100644
--- a/src/render/framegraph/clearbuffers.cpp
+++ b/src/render/framegraph/clearbuffers.cpp
@@ -80,17 +80,21 @@ void ClearBuffers::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
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);
}
- markDirty(AbstractRenderer::AllDirty);
}
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/src/render/framegraph/dispatchcompute.cpp b/src/render/framegraph/dispatchcompute.cpp
index 6ffb42e71..f7e9dcff4 100644
--- a/src/render/framegraph/dispatchcompute.cpp
+++ b/src/render/framegraph/dispatchcompute.cpp
@@ -80,13 +80,16 @@ void DispatchCompute::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
if (e->type() == Qt3DCore::PropertyUpdated) {
Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("workGroupX"))
+ if (propertyChange->propertyName() == QByteArrayLiteral("workGroupX")) {
m_workGroups[0] = propertyChange->value().toInt();
- else if (propertyChange->propertyName() == QByteArrayLiteral("workGroupY"))
+ markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::ComputeDirty);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("workGroupY")) {
m_workGroups[1] = propertyChange->value().toInt();
- else if (propertyChange->propertyName() == QByteArrayLiteral("workGroupZ"))
+ markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::ComputeDirty);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("workGroupZ")) {
m_workGroups[2] = propertyChange->value().toInt();
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::ComputeDirty);
+ }
}
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/src/render/framegraph/framegraph.pri b/src/render/framegraph/framegraph.pri
index 9784a193c..b969c85e5 100644
--- a/src/render/framegraph/framegraph.pri
+++ b/src/render/framegraph/framegraph.pri
@@ -58,7 +58,13 @@ HEADERS += \
$$PWD/proximityfilter_p.h \
$$PWD/qblitframebuffer.h \
$$PWD/qblitframebuffer_p.h \
- $$PWD/blitframebuffer_p.h
+ $$PWD/blitframebuffer_p.h \
+ $$PWD/qsetfence.h \
+ $$PWD/qwaitfence.h \
+ $$PWD/qwaitfence_p.h \
+ $$PWD/qsetfence_p.h \
+ $$PWD/setfence_p.h \
+ $$PWD/waitfence_p.h
SOURCES += \
$$PWD/cameraselectornode.cpp \
@@ -100,4 +106,8 @@ SOURCES += \
$$PWD/qproximityfilter.cpp \
$$PWD/proximityfilter.cpp \
$$PWD/qblitframebuffer.cpp \
- $$PWD/blitframebuffer.cpp
+ $$PWD/blitframebuffer.cpp \
+ $$PWD/qsetfence.cpp \
+ $$PWD/qwaitfence.cpp \
+ $$PWD/setfence.cpp \
+ $$PWD/waitfence.cpp
diff --git a/src/render/framegraph/framegraphnode.cpp b/src/render/framegraph/framegraphnode.cpp
index f2ce1a50a..562548e46 100644
--- a/src/render/framegraph/framegraphnode.cpp
+++ b/src/render/framegraph/framegraphnode.cpp
@@ -157,23 +157,32 @@ void FrameGraphNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
case Qt3DCore::PropertyValueAdded: {
Qt3DCore::QPropertyNodeAddedChangePtr change = qSharedPointerCast<Qt3DCore::QPropertyNodeAddedChange>(e);
- if (change->metaObject()->inherits(&QFrameGraphNode::staticMetaObject))
+ if (change->metaObject()->inherits(&QFrameGraphNode::staticMetaObject)) {
appendChildId(change->addedNodeId());
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
break;
}
case Qt3DCore::PropertyValueRemoved: {
Qt3DCore::QPropertyNodeRemovedChangePtr change = qSharedPointerCast<Qt3DCore::QPropertyNodeRemovedChange>(e);
- if (change->metaObject()->inherits(&QFrameGraphNode::staticMetaObject))
+ if (change->metaObject()->inherits(&QFrameGraphNode::staticMetaObject)) {
removeChildId(change->removedNodeId());
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
+ break;
+ }
+ 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);
+ }
break;
}
default:
break;
}
-
- markDirty(AbstractRenderer::AllDirty);
- BackendNode::sceneChangeEvent(e);
}
} // namespace Render
diff --git a/src/render/framegraph/framegraphnode_p.h b/src/render/framegraph/framegraphnode_p.h
index 19165f56f..87d5c79e8 100644
--- a/src/render/framegraph/framegraphnode_p.h
+++ b/src/render/framegraph/framegraphnode_p.h
@@ -101,7 +101,9 @@ public:
BufferCapture,
MemoryBarrier,
ProximityFilter,
- BlitFramebuffer
+ BlitFramebuffer,
+ SetFence,
+ WaitFence
};
FrameGraphNodeType nodeType() const { return m_nodeType; }
diff --git a/src/render/framegraph/layerfilternode.cpp b/src/render/framegraph/layerfilternode.cpp
index 4b6842015..f9881be0d 100644
--- a/src/render/framegraph/layerfilternode.cpp
+++ b/src/render/framegraph/layerfilternode.cpp
@@ -73,7 +73,7 @@ void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
if (change->propertyName() == QByteArrayLiteral("layer"))
m_layerIds.append(change->addedNodeId());
- markDirty(AbstractRenderer::LayersDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::LayersDirty);
break;
}
@@ -81,7 +81,7 @@ void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
if (change->propertyName() == QByteArrayLiteral("layer"))
m_layerIds.removeOne(change->removedNodeId());
- markDirty(AbstractRenderer::LayersDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty|AbstractRenderer::LayersDirty);
break;
}
@@ -89,6 +89,7 @@ void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
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;
}
}
diff --git a/src/render/framegraph/memorybarrier.cpp b/src/render/framegraph/memorybarrier.cpp
index ee8f156e3..59b3071ab 100644
--- a/src/render/framegraph/memorybarrier.cpp
+++ b/src/render/framegraph/memorybarrier.cpp
@@ -68,7 +68,7 @@ void MemoryBarrier::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
if (propertyChange->propertyName() == QByteArrayLiteral("waitOperations")) {
m_waitOperations = propertyChange->value().value<QMemoryBarrier::Operations>();
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
}
FrameGraphNode::sceneChangeEvent(e);
diff --git a/src/render/framegraph/proximityfilter.cpp b/src/render/framegraph/proximityfilter.cpp
index aed19828b..cdfd7e51e 100644
--- a/src/render/framegraph/proximityfilter.cpp
+++ b/src/render/framegraph/proximityfilter.cpp
@@ -67,11 +67,13 @@ 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"))
+ if (propertyChange->propertyName() == QByteArrayLiteral("entity")) {
m_entityId = propertyChange->value().value<Qt3DCore::QNodeId>();
- else if (propertyChange->propertyName() == QByteArrayLiteral("distanceThreshold"))
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("distanceThreshold")) {
m_distanceThreshold = propertyChange->value().toFloat();
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/src/render/framegraph/qsetfence.cpp b/src/render/framegraph/qsetfence.cpp
new file mode 100644
index 000000000..5cb82f3db
--- /dev/null
+++ b/src/render/framegraph/qsetfence.cpp
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** 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 "qsetfence.h"
+#include "qsetfence_p.h"
+#include <Qt3DRender/private/qframegraphnodecreatedchange_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QSetFencePrivate::QSetFencePrivate()
+ : QFrameGraphNodePrivate()
+ , m_handleType(QSetFence::NoHandle)
+ , m_handle(QVariant())
+{
+}
+
+/*!
+ \class QSetFence
+ \brief FrameGraphNode used to insert a fence in the graphics command stream.
+
+ Fence allow to synchronosize GPU and CPU workloads. GPU commands usually
+ are non-blocking. When issued, commands are inserted in command buffers
+ which will be read at a later time by the GPU. In some cases, you want to
+ continue processing or issue specific command only when you are sure a
+ command has been executed by the hardware. Fences are a way to do so. This
+ is especially important when using 3rd party engines with Qt3D, Qt3D should
+ only access shared resources when we know the other engine command are done
+ modifying the resource.
+
+ QSetFence is a FrameGraph node that inserts a fence into the command
+ stream. It can then be used in conjunction with \l QWaitFence or by
+ extracting the underlying handle.
+
+ The handle property will be updated once the renderer has created the
+ underlying fence resource. The handle will remain valid as long as it
+ remains in the unsignaled state. Once it has reached the signaled state, it
+ will be destroyed and a new handle will be created. That means that
+ depending on how long it takes for the fence to be signaled, the same
+ handle could be used over several frames.
+
+ \since 5.13
+ */
+QSetFence::QSetFence(Qt3DCore::QNode *parent)
+ : QFrameGraphNode(*new QSetFencePrivate(), parent)
+{
+}
+
+QSetFence::~QSetFence()
+{
+}
+
+QSetFence::QSetFence(QSetFencePrivate &dd, Qt3DCore::QNode *parent)
+ : QFrameGraphNode(dd, parent)
+{
+}
+
+/*!
+ \qmlproperty HandleType SetFence::handleType
+
+ Specifies the type of handle being used. Currently only OpenGL Fence ids
+ are supported.
+*/
+/*!
+ \property QSetFence::handleType
+
+ Specifies the type of handle being used. Currently only OpenGL Fence ids
+ are supported.
+*/
+QSetFence::HandleType QSetFence::handleType() const
+{
+ Q_D(const QSetFence);
+ return d->m_handleType;
+}
+
+void QSetFencePrivate::setHandleType(QSetFence::HandleType type)
+{
+ Q_Q(QSetFence);
+ if (m_handleType != type) {
+ const bool blocked = q->blockNotifications(true);
+ m_handleType = type;
+ emit q->handleTypeChanged(type);
+ q->blockNotifications(blocked);
+ }
+}
+
+/*!
+ \qmlproperty variant AbstractFence::handle
+
+ Holds the underlying fence handle wrapped in a variant.
+*/
+/*!
+ \property QAbstractFence::handle
+
+ Holds the underlying fence handle wrapped in a QVariant.
+*/
+QVariant QSetFence::handle() const
+{
+ Q_D(const QSetFence);
+ return d->m_handle;
+}
+
+void QSetFencePrivate::setHandle(QVariant handle)
+{
+ Q_Q(QSetFence);
+ if (m_handle != handle) {
+ const bool blocked = q->blockNotifications(true);
+ m_handle = handle;
+ emit q->handleChanged(handle);
+ q->blockNotifications(blocked);
+ }
+}
+
+void QSetFence::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+{
+ Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
+ if (e->type() == Qt3DCore::PropertyUpdated) {
+ Q_D(QSetFence);
+ if (e->propertyName() == QByteArrayLiteral("handle"))
+ d->setHandle(e->value());
+ else if (e->propertyName() == QByteArrayLiteral("handleType"))
+ d->setHandleType(static_cast<Qt3DRender::QSetFence::HandleType>(e->value().toInt()));
+ }
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QSetFence::createNodeCreationChange() const
+{
+ auto creationChange = QFrameGraphNodeCreatedChangePtr<QSetFenceData>::create(this);
+ QSetFenceData &data = creationChange->data;
+ Q_UNUSED(data); // Might be of use later
+ return creationChange;
+}
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/qsetfence.h b/src/render/framegraph/qsetfence.h
new file mode 100644
index 000000000..4834601ea
--- /dev/null
+++ b/src/render/framegraph/qsetfence.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** 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 <Qt3DRender/QFrameGraphNode>
+
+#ifndef QT3DRENDER_QSETFENCE_H
+#define QT3DRENDER_QSETFENCE_H
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QSetFencePrivate;
+
+class QT3DRENDERSHARED_EXPORT QSetFence : public QFrameGraphNode
+{
+ Q_OBJECT
+ Q_PROPERTY(HandleType handleType READ handleType NOTIFY handleTypeChanged)
+ Q_PROPERTY(QVariant handle READ handle NOTIFY handleChanged)
+public:
+ enum HandleType {
+ NoHandle,
+ OpenGLFenceId
+ };
+ Q_ENUM(HandleType) // LCOV_EXCL_LINE
+
+ explicit QSetFence(Qt3DCore::QNode *parent = nullptr);
+ ~QSetFence();
+
+ HandleType handleType() const;
+ QVariant handle() const;
+
+Q_SIGNALS:
+ void handleTypeChanged(HandleType handleType);
+ void handleChanged(QVariant handle);
+
+protected:
+ explicit QSetFence(QSetFencePrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
+
+private:
+ Q_DECLARE_PRIVATE(QSetFence)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSETFENCE_H
diff --git a/src/render/framegraph/qsetfence_p.h b/src/render/framegraph/qsetfence_p.h
new file mode 100644
index 000000000..026afffa5
--- /dev/null
+++ b/src/render/framegraph/qsetfence_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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_QSETFENCE_P_H
+#define QT3DRENDER_QSETFENCE_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/qframegraphnode_p.h>
+#include <Qt3DRender/qsetfence.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QSetFencePrivate : public QFrameGraphNodePrivate
+{
+public:
+ QSetFencePrivate();
+ void setHandleType(QSetFence::HandleType type);
+ void setHandle(QVariant handle);
+
+ QSetFence::HandleType m_handleType;
+ QVariant m_handle;
+
+ Q_DECLARE_PUBLIC(QSetFence)
+};
+
+struct QSetFenceData
+{
+};
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSETFENCE_P_H
diff --git a/src/render/framegraph/qwaitfence.cpp b/src/render/framegraph/qwaitfence.cpp
new file mode 100644
index 000000000..5195653ce
--- /dev/null
+++ b/src/render/framegraph/qwaitfence.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** 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 "qwaitfence.h"
+#include "qwaitfence_p.h"
+#include <Qt3DRender/private/qframegraphnode_p.h>
+#include <Qt3DRender/private/qframegraphnodecreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QWaitFencePrivate::QWaitFencePrivate()
+ : QFrameGraphNodePrivate()
+ , m_handleType(QWaitFence::NoHandle)
+ , m_handle(QVariant())
+ , m_waitOnCPU(false)
+ , m_timeout(std::numeric_limits<quint64>::max())
+{
+}
+
+/*!
+ \class QWaitFence
+
+ \brief FrameGraphNode used to wait for a fence in the graphics command
+ stream to become signaled.
+
+ Fence allow to synchronosize GPU and CPU workloads. GPU commands usually
+ are non-blocking. When issued, commands are inserted in command buffers
+ which will be read at a later time by the GPU. In some cases, you want to
+ continue processing or issue specific command only when you are sure a
+ command has been executed by the hardware. Fences are a way to do so. This
+ is especially important when using 3rd party engines with Qt3D, Qt3D should
+ only access shared resources when we know the other engine command are done
+ modifying the resource.
+
+ QWaitFence is a FrameGraph node that will force to wait for it to become
+ signaled before subsequent commands are inserted into the command stream.
+ It can then be used in conjunction with \l QSetFence and contains
+ properties to configure how long it should wait and whether it should block
+ on the CPU side.
+
+ \note Qt 3D uploads GPU resources (Texture, Shaders, Buffers) before
+ issuing draw calls.
+
+ \since 5.13
+ */
+
+QWaitFence::QWaitFence(Qt3DCore::QNode *parent)
+ : QFrameGraphNode(*new QWaitFencePrivate(), parent)
+{
+}
+
+QWaitFence::~QWaitFence()
+{
+}
+
+/*!
+ \qmlproperty bool WaitFence::waitOnCPU
+
+ Specifies whether the CPU should be block while waiting for the fence to
+ become signaled. This is false by default.
+*/
+/*!
+ \property QWaitFence::waitOnCPU
+
+ Specifies whether the CPU should be block while waiting for the fence to
+ become signaled. This is false by default.
+*/
+bool QWaitFence::waitOnCPU() const
+{
+ Q_D(const QWaitFence);
+ return d->m_waitOnCPU;
+}
+
+void QWaitFence::setWaitOnCPU(bool waitOnCPU)
+{
+ Q_D(QWaitFence);
+ if (d->m_waitOnCPU == waitOnCPU)
+ return;
+ d->m_waitOnCPU = waitOnCPU;
+ emit waitOnCPUChanged(waitOnCPU);
+}
+
+/*!
+ \qmlproperty int WaitFence::timeout
+
+ Specifies the maximum amount of time in nanoseconds to wait for the fence
+ to become signaled.
+*/
+/*!
+ \property QWaitFence::timeout
+
+ Specifies the maximum amount of time in nanoseconds to wait for the fence
+ to become signaled.
+*/
+quint64 QWaitFence::timeout() const
+{
+ Q_D(const QWaitFence);
+ return d->m_timeout;
+}
+
+void QWaitFence::setTimeout(quint64 timeout)
+{
+ Q_D(QWaitFence);
+ if (d->m_timeout == timeout)
+ return;
+ d->m_timeout = timeout;
+ emit timeoutChanged(timeout);
+}
+
+QWaitFence::QWaitFence(QWaitFencePrivate &dd, Qt3DCore::QNode *parent)
+ : QFrameGraphNode(dd, parent)
+{
+}
+
+/*!
+ \qmlproperty HandleType WaitFence::handleType
+
+ Specifies the type of handle being used. Currently only OpenGL Fence ids
+ are supported.
+*/
+/*!
+ \property QWaitFence::handleType
+
+ Specifies the type of handle being used. Currently only OpenGL Fence ids
+ are supported.
+*/
+QWaitFence::HandleType QWaitFence::handleType() const
+{
+ Q_D(const QWaitFence);
+ return d->m_handleType;
+}
+
+void QWaitFence::setHandleType(QWaitFence::HandleType type)
+{
+ Q_D(QWaitFence);
+ if (d->m_handleType != type) {
+ d->m_handleType = type;
+ emit handleTypeChanged(type);
+ }
+}
+
+/*!
+ \qmlproperty variant WaitFence::handle
+
+ Holds the underlying fence handle wrapped in a variant.
+*/
+/*!
+ \property QWaitFence::handle
+
+ Holds the underlying fence handle wrapped in a QVariant.
+*/
+QVariant QWaitFence::handle() const
+{
+ Q_D(const QWaitFence);
+ return d->m_handle;
+}
+
+void QWaitFence::setHandle(QVariant handle)
+{
+ Q_D(QWaitFence);
+ if (d->m_handle != handle) {
+ d->m_handle = handle;
+ emit handleChanged(handle);
+ }
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QWaitFence::createNodeCreationChange() const
+{
+ auto creationChange = QFrameGraphNodeCreatedChangePtr<QWaitFenceData>::create(this);
+ QWaitFenceData &data = creationChange->data;
+ Q_D(const QWaitFence);
+ data.handleType = d->m_handleType;
+ data.handle = d->m_handle;
+ data.timeout = d->m_timeout;
+ data.waitOnCPU = d->m_waitOnCPU;
+ return creationChange;
+}
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/qwaitfence.h b/src/render/framegraph/qwaitfence.h
new file mode 100644
index 000000000..4f3e7ae8b
--- /dev/null
+++ b/src/render/framegraph/qwaitfence.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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_QWAITFENCE_H
+#define QT3DRENDER_QWAITFENCE_H
+
+#include <Qt3DRender/QFrameGraphNode>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QWaitFencePrivate;
+
+class QT3DRENDERSHARED_EXPORT QWaitFence : public QFrameGraphNode
+{
+ Q_OBJECT
+ Q_PROPERTY(HandleType handleType READ handleType WRITE setHandleType NOTIFY handleTypeChanged)
+ Q_PROPERTY(QVariant handle READ handle WRITE setHandle NOTIFY handleChanged)
+ Q_PROPERTY(bool waitOnCPU READ waitOnCPU WRITE setWaitOnCPU NOTIFY waitOnCPUChanged)
+ Q_PROPERTY(quint64 timeout READ timeout WRITE setTimeout NOTIFY timeoutChanged)
+
+public:
+ enum HandleType {
+ NoHandle,
+ OpenGLFenceId
+ };
+ Q_ENUM(HandleType) // LCOV_EXCL_LINE
+ explicit QWaitFence(Qt3DCore::QNode *parent = nullptr);
+ ~QWaitFence();
+
+ void setHandleType(HandleType type);
+ void setHandle(QVariant handle);
+
+ HandleType handleType() const;
+ QVariant handle() const;
+
+ bool waitOnCPU() const;
+ void setWaitOnCPU(bool waitOnCPU);
+
+ quint64 timeout() const;
+ void setTimeout(quint64 timeout);
+
+Q_SIGNALS:
+ void waitOnCPUChanged(bool waitOnCPU);
+ void timeoutChanged(quint64 timeoutChanged);
+ void handleTypeChanged(HandleType handleType);
+ void handleChanged(QVariant handle);
+
+protected:
+ explicit QWaitFence(QWaitFencePrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QWaitFence)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QWAITFENCE_H
diff --git a/src/render/framegraph/qwaitfence_p.h b/src/render/framegraph/qwaitfence_p.h
new file mode 100644
index 000000000..480d69cad
--- /dev/null
+++ b/src/render/framegraph/qwaitfence_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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_QWAITFENCE_P_H
+#define QT3DRENDER_QWAITFENCE_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/qframegraphnode_p.h>
+#include <Qt3DRender/qwaitfence.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QWaitFencePrivate : public QFrameGraphNodePrivate
+{
+public:
+ QWaitFencePrivate();
+
+ QWaitFence::HandleType m_handleType;
+ QVariant m_handle;
+ bool m_waitOnCPU;
+ quint64 m_timeout;
+};
+
+struct QWaitFenceData
+{
+ QWaitFence::HandleType handleType;
+ QVariant handle;
+ bool waitOnCPU;
+ quint64 timeout;
+};
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_QWAITFENCE_P_H
diff --git a/src/render/framegraph/rendercapture.cpp b/src/render/framegraph/rendercapture.cpp
index d25a01b1f..166294889 100644
--- a/src/render/framegraph/rendercapture.cpp
+++ b/src/render/framegraph/rendercapture.cpp
@@ -76,6 +76,7 @@ void RenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
if (propertyChange->propertyName() == QByteArrayLiteral("renderCaptureRequest")) {
requestCapture(propertyChange->value().value<QRenderCaptureRequest>());
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
}
FrameGraphNode::sceneChangeEvent(e);
diff --git a/src/render/framegraph/renderpassfilternode.cpp b/src/render/framegraph/renderpassfilternode.cpp
index c9277b951..e3da1e36d 100644
--- a/src/render/framegraph/renderpassfilternode.cpp
+++ b/src/render/framegraph/renderpassfilternode.cpp
@@ -97,10 +97,10 @@ void RenderPassFilter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
if (change->propertyName() == QByteArrayLiteral("match")) {
appendFilter(change->addedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
} else if (change->propertyName() == QByteArrayLiteral("parameter")) {
m_parameterPack.appendParameter(change->addedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
break;
}
@@ -109,10 +109,10 @@ void RenderPassFilter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
if (change->propertyName() == QByteArrayLiteral("match")) {
removeFilter(change->removedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
} else if (change->propertyName() == QByteArrayLiteral("parameter")) {
m_parameterPack.removeParameter(change->removedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
break;
}
diff --git a/src/render/framegraph/rendersurfaceselector.cpp b/src/render/framegraph/rendersurfaceselector.cpp
index 7f2fd6170..16a1199b5 100644
--- a/src/render/framegraph/rendersurfaceselector.cpp
+++ b/src/render/framegraph/rendersurfaceselector.cpp
@@ -101,17 +101,22 @@ 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"))
+ if (propertyChange->propertyName() == QByteArrayLiteral("surface")) {
m_surface = surfaceFromQObject(propertyChange->value().value<QObject *>());
- else if (propertyChange->propertyName() == QByteArrayLiteral("externalRenderTargetSize"))
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("externalRenderTargetSize")) {
setRenderTargetSize(propertyChange->value().toSize());
- else if (propertyChange->propertyName() == QByteArrayLiteral("width"))
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("width")) {
m_width = propertyChange->value().toInt();
- else if (propertyChange->propertyName() == QByteArrayLiteral("height"))
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("height")) {
m_height = propertyChange->value().toInt();
- else if (propertyChange->propertyName() == QByteArrayLiteral("surfacePixelRatio"))
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("surfacePixelRatio")) {
m_devicePixelRatio = propertyChange->value().toFloat();
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/src/render/framegraph/rendertargetselectornode.cpp b/src/render/framegraph/rendertargetselectornode.cpp
index 4b6e2da84..615608bd2 100644
--- a/src/render/framegraph/rendertargetselectornode.cpp
+++ b/src/render/framegraph/rendertargetselectornode.cpp
@@ -73,11 +73,13 @@ 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"))
+ if (propertyChange->propertyName() == QByteArrayLiteral("target")) {
m_renderTargetUuid = propertyChange->value().value<QNodeId>();
- else if (propertyChange->propertyName() == QByteArrayLiteral("outputs"))
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("outputs")) {
m_outputs = propertyChange->value().value<QVector<Qt3DRender::QRenderTargetOutput::AttachmentPoint> >();
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
+ }
}
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/src/render/framegraph/setfence.cpp b/src/render/framegraph/setfence.cpp
new file mode 100644
index 000000000..b2e995b25
--- /dev/null
+++ b/src/render/framegraph/setfence.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** 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 "setfence_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+SetFence::SetFence()
+ : FrameGraphNode(FrameGraphNode::SetFence, QBackendNode::ReadWrite)
+{
+}
+
+SetFence::~SetFence()
+{
+}
+
+void SetFence::setHandle(const QVariant &handle)
+{
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("handle");
+ change->setValue(handle);
+ notifyObservers(change);
+}
+
+void SetFence::setHandleType(QSetFence::HandleType type)
+{
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("handleType");
+ change->setValue(QVariant::fromValue(type));
+ notifyObservers(change);
+}
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/setfence_p.h b/src/render/framegraph/setfence_p.h
new file mode 100644
index 000000000..31072581c
--- /dev/null
+++ b/src/render/framegraph/setfence_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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_RENDER_SETFENCE_P_H
+#define QT3DRENDER_RENDER_SETFENCE_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/framegraphnode_p.h>
+#include <Qt3DRender/qsetfence.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Q_AUTOTEST_EXPORT SetFence : public FrameGraphNode
+{
+public:
+ SetFence();
+ ~SetFence();
+
+ // Called by a job
+ void setHandle(const QVariant &handle);
+ void setHandleType(QSetFence::HandleType type);
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_SETFENCE_P_H
diff --git a/src/render/framegraph/sortpolicy.cpp b/src/render/framegraph/sortpolicy.cpp
index 9631ebeab..b81d1f6cb 100644
--- a/src/render/framegraph/sortpolicy.cpp
+++ b/src/render/framegraph/sortpolicy.cpp
@@ -61,9 +61,9 @@ void SortPolicy::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
auto sortTypesInt = propertyChange->value().value<QVector<int>>();
m_sortTypes.clear();
transformVector(sortTypesInt, m_sortTypes);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
}
- markDirty(AbstractRenderer::AllDirty);
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/src/render/framegraph/statesetnode.cpp b/src/render/framegraph/statesetnode.cpp
index 2ffbb70c7..96551684e 100644
--- a/src/render/framegraph/statesetnode.cpp
+++ b/src/render/framegraph/statesetnode.cpp
@@ -84,7 +84,7 @@ void StateSetNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
if (change->propertyName() == QByteArrayLiteral("renderState")) {
addRenderState(change->addedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
break;
}
@@ -93,7 +93,7 @@ void StateSetNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto propertyChange = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
if (propertyChange->propertyName() == QByteArrayLiteral("renderState")) {
removeRenderState(propertyChange->removedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
break;
}
diff --git a/src/render/framegraph/techniquefilternode.cpp b/src/render/framegraph/techniquefilternode.cpp
index 59f49af02..8816984ee 100644
--- a/src/render/framegraph/techniquefilternode.cpp
+++ b/src/render/framegraph/techniquefilternode.cpp
@@ -96,10 +96,10 @@ void TechniqueFilter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
if (change->propertyName() == QByteArrayLiteral("matchAll")) {
appendFilter(change->addedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
} else if (change->propertyName() == QByteArrayLiteral("parameter")) {
m_parameterPack.appendParameter(change->addedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
break;
}
@@ -108,10 +108,10 @@ void TechniqueFilter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
if (change->propertyName() == QByteArrayLiteral("matchAll")) {
removeFilter(change->removedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
} else if (change->propertyName() == QByteArrayLiteral("parameter")) {
m_parameterPack.removeParameter(change->removedNodeId());
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::FrameGraphDirty);
}
break;
}
diff --git a/src/render/framegraph/viewportnode.cpp b/src/render/framegraph/viewportnode.cpp
index bed87a13f..b3b53b0f9 100644
--- a/src/render/framegraph/viewportnode.cpp
+++ b/src/render/framegraph/viewportnode.cpp
@@ -128,10 +128,11 @@ void ViewportNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
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);
}
- markDirty(AbstractRenderer::AllDirty);
}
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/src/render/framegraph/waitfence.cpp b/src/render/framegraph/waitfence.cpp
new file mode 100644
index 000000000..9480fb7a0
--- /dev/null
+++ b/src/render/framegraph/waitfence.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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 "waitfence_p.h"
+#include <Qt3DRender/private/qwaitfence_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.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 {
+
+WaitFence::WaitFence()
+ : FrameGraphNode(FrameGraphNode::WaitFence)
+{
+ m_data.handleType = QWaitFence::NoHandle;
+ m_data.waitOnCPU = false;
+ m_data.timeout = std::numeric_limits<quint64>::max();
+}
+
+WaitFence::~WaitFence()
+{
+}
+
+void WaitFence::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ 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);
+}
+
+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;
+}
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/waitfence_p.h b/src/render/framegraph/waitfence_p.h
new file mode 100644
index 000000000..dd48e0efa
--- /dev/null
+++ b/src/render/framegraph/waitfence_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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_RENDER_WAITFENCE_P_H
+#define QT3DRENDER_RENDER_WAITFENCE_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/qwaitfence.h>
+#include <Qt3DRender/private/framegraphnode_p.h>
+#include <Qt3DRender/private/qwaitfence_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Q_AUTOTEST_EXPORT WaitFence : public FrameGraphNode
+{
+public:
+ WaitFence();
+ ~WaitFence();
+
+ inline QWaitFenceData data() const { return m_data; }
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) override;
+
+ QWaitFenceData m_data;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_WAITFENCE_P_H
diff --git a/src/render/frontend/qcomputecommand.cpp b/src/render/frontend/qcomputecommand.cpp
index 5cb72a6ce..8b176cd4f 100644
--- a/src/render/frontend/qcomputecommand.cpp
+++ b/src/render/frontend/qcomputecommand.cpp
@@ -39,6 +39,7 @@
#include "qcomputecommand.h"
#include "qcomputecommand_p.h"
+#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -75,12 +76,14 @@ namespace Qt3DRender {
The compute shader is specified in the Material component of the same entity the
ComputeCommand is added to. The workGroupX, workGroupY and workGroupZ properties
specify the work group sizes for the compute shader invocation. DispatchCompute
- node needs to be present in the FrameGraph to actually issue the commands.
+ node needs to be present in the FrameGraph to actually issue the commands. The execution behavior
+ of the compute command can be controlled with the run type property.
- \note If the rendering policy is set to RenderSettings.OnDemand and there are no changes to the
- scene, the ComputeCommand will not be invoked repeatedly.
- The RenderSettings.Always render policy must be set for the ComputeCommand to be
- repeatedly invoked if there are no other changes to the scene that triggers rendering a new
+ \note If the rendering policy is set to RenderSettings.OnDemand, the run
+ type is set to Continuous and there are no changes to the scene, the
+ ComputeCommand will not be invoked repeatedly. The RenderSettings.Always
+ render policy must be set for the ComputeCommand to be repeatedly invoked
+ if there are no other changes to the scene that triggers rendering a new
frame.
*/
@@ -90,6 +93,19 @@ namespace Qt3DRender {
*/
/*!
+ \qmlproperty QComputeCommand::runType
+
+ Specifies whether the compute command should be performed every frame or
+ manually triggered.
+
+ \value Continuous Compute command is executed everyframe. This is the
+ default.
+
+ \value Manual CompouteCommand is executed for a given number of frames and
+ then the component disables itself.
+ */
+
+/*!
\qmlproperty int ComputeCommand::workGroupY
Specifies Y workgroup size.
*/
@@ -114,12 +130,36 @@ namespace Qt3DRender {
Specifies Z workgroup size.
*/
+/*!
+ \property QComputeCommand::runType
+
+ Specifies whether the compute command should be performed every frame or
+ manually triggered.
+
+ If set to Continuous, Compute command is executed everyframe. This is the
+ default.
+
+ If set to Manual CompouteCommand is executed for a given number of frames
+ and then the component disables itself.
+ */
+
QComputeCommandPrivate::QComputeCommandPrivate()
: Qt3DCore::QComponentPrivate()
, m_workGroupX(1)
, m_workGroupY(1)
, m_workGroupZ(1)
+ , m_runType(QComputeCommand::Continuous)
+ , m_frameCount(0)
+{
+}
+
+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);
}
/*!
@@ -154,6 +194,12 @@ int QComputeCommand::workGroupZ() const
return d->m_workGroupZ;
}
+QComputeCommand::RunType QComputeCommand::runType() const
+{
+ Q_D(const QComputeCommand);
+ return d->m_runType;
+}
+
/*!
Sets the workgroup for the first dimension to \a workGroupX.
*/
@@ -190,6 +236,50 @@ void QComputeCommand::setWorkGroupZ(int workGroupZ)
}
}
+void QComputeCommand::setRunType(QComputeCommand::RunType runType)
+{
+ Q_D(QComputeCommand);
+ if (d->m_runType != runType) {
+ d->m_runType = runType;
+ emit runTypeChanged();
+ }
+}
+
+/*!
+ When the run type is set to Manual, calling trigger will make the compute
+ command be executed for the next \a frameCount frames. Upon completion of
+ the execution, the enabled property will be set to false.
+ */
+void QComputeCommand::trigger(int frameCount)
+{
+ if (isEnabled())
+ qWarning() << Q_FUNC_INFO << "is triggered while it hasn't finished executing";
+
+ Q_D(QComputeCommand);
+ d->setFrameCount(frameCount);
+ setEnabled(true);
+}
+
+/*!
+ When the run type is set to Manual, calling trigger will make the compute
+ command be executed for the next \a frameCount frames. Upon completion of
+ the execution, the enabled property will be set to false. The size of the
+ workgroup previously set will be overridden with \a workGroupX, \a
+ workGroupY, \a workGroupZ.
+ */
+void QComputeCommand::trigger(int workGroupX, int workGroupY, int workGroupZ, int frameCount)
+{
+ if (isEnabled())
+ qWarning() << Q_FUNC_INFO << "is triggered while it hasn't finished executing";
+
+ setWorkGroupX(workGroupX);
+ setWorkGroupY(workGroupY);
+ setWorkGroupZ(workGroupZ);
+ Q_D(QComputeCommand);
+ d->setFrameCount(frameCount);
+ setEnabled(true);
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QComputeCommand::createNodeCreationChange() const
{
auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QComputeCommandData>::create(this);
@@ -198,6 +288,8 @@ Qt3DCore::QNodeCreatedChangeBasePtr QComputeCommand::createNodeCreationChange()
data.workGroupX = d->m_workGroupX;
data.workGroupY = d->m_workGroupY;
data.workGroupZ = d->m_workGroupZ;
+ data.runType = d->m_runType;
+ data.frameCount = d->m_frameCount;
return creationChange;
}
diff --git a/src/render/frontend/qcomputecommand.h b/src/render/frontend/qcomputecommand.h
index c31082197..ad7f89a4d 100644
--- a/src/render/frontend/qcomputecommand.h
+++ b/src/render/frontend/qcomputecommand.h
@@ -55,24 +55,37 @@ class QT3DRENDERSHARED_EXPORT QComputeCommand : public Qt3DCore::QComponent
Q_PROPERTY(int workGroupX READ workGroupX WRITE setWorkGroupX NOTIFY workGroupXChanged)
Q_PROPERTY(int workGroupY READ workGroupY WRITE setWorkGroupY NOTIFY workGroupYChanged)
Q_PROPERTY(int workGroupZ READ workGroupZ WRITE setWorkGroupZ NOTIFY workGroupZChanged)
+ Q_PROPERTY(RunType runType READ runType WRITE setRunType NOTIFY runTypeChanged REVISION 13)
public:
+ enum RunType {
+ Continuous = 0,
+ Manual
+ };
+ Q_ENUM(RunType)
+
explicit QComputeCommand(Qt3DCore::QNode *parent = nullptr);
~QComputeCommand();
int workGroupX() const;
int workGroupY() const;
int workGroupZ() const;
+ RunType runType() const;
public Q_SLOTS:
void setWorkGroupX(int workGroupX);
void setWorkGroupY(int workGroupY);
void setWorkGroupZ(int workGroupZ);
+ void setRunType(RunType runType);
+
+ void trigger(int frameCount = 1);
+ void trigger(int workGroupX, int workGroupY, int workGroupZ, int frameCount = 1);
Q_SIGNALS:
void workGroupXChanged();
void workGroupYChanged();
void workGroupZChanged();
+ void runTypeChanged();
private:
Q_DECLARE_PRIVATE(QComputeCommand)
diff --git a/src/render/frontend/qcomputecommand_p.h b/src/render/frontend/qcomputecommand_p.h
index 874edb1fc..fc3376d5b 100644
--- a/src/render/frontend/qcomputecommand_p.h
+++ b/src/render/frontend/qcomputecommand_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DCore/private/qcomponent_p.h>
+#include <Qt3DRender/qcomputecommand.h>
#include <Qt3DRender/private/qt3drender_global_p.h>
QT_BEGIN_NAMESPACE
@@ -66,6 +67,10 @@ public:
int m_workGroupX;
int m_workGroupY;
int m_workGroupZ;
+ QComputeCommand::RunType m_runType;
+ int m_frameCount;
+
+ void setFrameCount(int frameCount);
};
struct QComputeCommandData
@@ -73,6 +78,8 @@ struct QComputeCommandData
int workGroupX;
int workGroupY;
int workGroupZ;
+ QComputeCommand::RunType runType;
+ int frameCount;
};
} // Qt3DRender
diff --git a/src/render/frontend/qpickingsettings.cpp b/src/render/frontend/qpickingsettings.cpp
index 66d3fc912..84e61e141 100644
--- a/src/render/frontend/qpickingsettings.cpp
+++ b/src/render/frontend/qpickingsettings.cpp
@@ -199,6 +199,9 @@ 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. If several object pickers have the same priority, the closest one on
+ * the ray is selected.
*
* \sa Qt3DRender::QPickEvent
*/
@@ -211,6 +214,7 @@ void QPickingSettings::setPickMethod(QPickingSettings::PickMethod pickMethod)
\list
\li PickingSettings.NearestPick
\li PickingSettings.AllPicks
+ \li PickingSettings.NearestPriorityPick
\endlist
\sa Qt3DRender::QPickingSettings::PickResultMode
@@ -225,6 +229,10 @@ void QPickingSettings::setPickMethod(QPickingSettings::PickMethod pickMethod)
When setting the pick method to AllPicks, events will be triggered for all the
entities with a QObjectPicker along the ray.
+ When setting the pick method to NearestPriorityPick, events will be
+ triggered for the nearest highest priority picker. This can be used when a
+ given element should always be selected even if others are in front of it.
+
If a QObjectPicker is assigned to an entity with multiple children, an event will
be triggered for each child entity that intersects the ray.
*/
diff --git a/src/render/frontend/qpickingsettings.h b/src/render/frontend/qpickingsettings.h
index 9c8a2c856..741f918b0 100644
--- a/src/render/frontend/qpickingsettings.h
+++ b/src/render/frontend/qpickingsettings.h
@@ -73,7 +73,8 @@ public:
enum PickResultMode {
NearestPick,
- AllPicks
+ AllPicks,
+ NearestPriorityPick
};
Q_ENUM(PickResultMode) // LCOV_EXCL_LINE
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index ae84599e8..14fbe1754 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -88,6 +88,8 @@
#include <Qt3DRender/qproximityfilter.h>
#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qblitframebuffer.h>
+#include <Qt3DRender/qsetfence.h>
+#include <Qt3DRender/qwaitfence.h>
#include <Qt3DCore/qarmature.h>
#include <Qt3DCore/qjoint.h>
#include <Qt3DCore/qskeletonloader.h>
@@ -150,6 +152,8 @@
#include <Qt3DRender/private/joint_p.h>
#include <Qt3DRender/private/loadskeletonjob_p.h>
#include <Qt3DRender/private/proximityfilter_p.h>
+#include <Qt3DRender/private/setfence_p.h>
+#include <Qt3DRender/private/waitfence_p.h>
#include <private/qrenderpluginfactory_p.h>
#include <private/qrenderplugin_p.h>
@@ -298,6 +302,8 @@ void QRenderAspectPrivate::registerBackendTypes()
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));
// Picking
q->registerBackendType<QObjectPicker>(QSharedPointer<Render::NodeFunctor<Render::ObjectPicker, Render::ObjectPickerManager> >::create(m_renderer));
@@ -368,6 +374,8 @@ void QRenderAspectPrivate::unregisterBackendTypes()
unregisterBackendType<QRenderCapture>();
unregisterBackendType<QBufferCapture>();
unregisterBackendType<QMemoryBarrier>();
+ unregisterBackendType<QSetFence>();
+ unregisterBackendType<QWaitFence>();
// Picking
unregisterBackendType<QObjectPicker>();
@@ -509,11 +517,8 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
const QVector<QAspectJobPtr> geometryJobs = d->createGeometryRendererJobs();
jobs.append(geometryJobs);
-
- // Add all jobs to queue
- // Note: the getter is also responsible for returning a job ready to run
- jobs.append(d->m_renderer->pickBoundingVolumeJob());
- jobs.append(d->m_renderer->rayCastingJob());
+ const QVector<QAspectJobPtr> preRenderingJobs = d->m_renderer->preRenderingJobs();
+ jobs.append(preRenderingJobs);
// Don't spawn any rendering jobs, if the renderer decides to skip this frame
// Note: this only affects rendering jobs (jobs that load buffers,
diff --git a/src/render/geometry/geometry.cpp b/src/render/geometry/geometry.cpp
index d87b4d8eb..4ee02a74d 100644
--- a/src/render/geometry/geometry.cpp
+++ b/src/render/geometry/geometry.cpp
@@ -53,8 +53,10 @@ namespace Qt3DRender {
namespace Render {
Geometry::Geometry()
- : BackendNode(ReadOnly)
+ : BackendNode(ReadWrite)
, m_geometryDirty(false)
+ , m_shouldNotifyMinExtentChanged(false)
+ , m_shouldNotifyMaxExtentChanged(false)
{
}
@@ -68,6 +70,10 @@ void Geometry::cleanup()
m_attributes.clear();
m_geometryDirty = false;
m_boundingPositionAttribute = Qt3DCore::QNodeId();
+ m_min = QVector3D();
+ m_max = QVector3D();
+ m_shouldNotifyMinExtentChanged = false;
+ m_shouldNotifyMaxExtentChanged = false;
}
void Geometry::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
@@ -122,6 +128,37 @@ void Geometry::unsetDirty()
m_geometryDirty = false;
}
+// Called from calcboundingvolumejob (in a QtConcurrent thead (can't send
+// update changes from such a thread))
+void Geometry::updateExtent(const QVector3D &min, const QVector3D &max)
+{
+ // Send notification to frontend
+ if (m_min != min) {
+ m_min = min;
+ m_shouldNotifyMinExtentChanged = true;
+ }
+
+ if (m_max != max) {
+ m_max = max;
+ m_shouldNotifyMaxExtentChanged = true;
+ }
+}
+
+// Called from calcboundingvolumejob after all bounding volumes have been
+// updated (in an aspect thread)
+void Geometry::notifyExtentChanged()
+{
+ if (m_shouldNotifyMinExtentChanged || m_shouldNotifyMaxExtentChanged) {
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("extent");
+ change->setValue(QVariant::fromValue(QPair<QVector3D, QVector3D>(m_min, m_max)));
+ notifyObservers(change);
+ m_shouldNotifyMinExtentChanged = false;
+ m_shouldNotifyMaxExtentChanged = false;
+ }
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/geometry/geometry_p.h b/src/render/geometry/geometry_p.h
index b158648ad..e66524787 100644
--- a/src/render/geometry/geometry_p.h
+++ b/src/render/geometry/geometry_p.h
@@ -75,12 +75,22 @@ public:
inline Qt3DCore::QNodeId boundingPositionAttribute() const { return m_boundingPositionAttribute; }
void unsetDirty();
+ inline QVector3D min() const { return m_min; }
+ inline QVector3D max() const { return m_max; }
+
+ void updateExtent(const QVector3D &min, const QVector3D &max);
+ void notifyExtentChanged();
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
QVector<Qt3DCore::QNodeId> m_attributes;
bool m_geometryDirty;
Qt3DCore::QNodeId m_boundingPositionAttribute;
+ QVector3D m_min;
+ QVector3D m_max;
+ bool m_shouldNotifyMinExtentChanged;
+ bool m_shouldNotifyMaxExtentChanged;
};
} // namespace Render
diff --git a/src/render/geometry/qgeometry.cpp b/src/render/geometry/qgeometry.cpp
index c49dde822..ec80e2657 100644
--- a/src/render/geometry/qgeometry.cpp
+++ b/src/render/geometry/qgeometry.cpp
@@ -153,6 +153,28 @@ QGeometry::QGeometry(QGeometryPrivate &dd, QNode *parent)
{
}
+void QGeometry::sceneChangeEvent(const QSceneChangePtr &change)
+{
+ Q_D(QGeometry);
+ QPropertyUpdatedChangePtr e = qSharedPointerCast<QPropertyUpdatedChange>(change);
+ if (e->type() == PropertyUpdated) {
+ const bool blocked = blockNotifications(true);
+ if (e->propertyName() == QByteArrayLiteral("extent")) {
+ const QPair<QVector3D, QVector3D> extent = e->value().value<QPair<QVector3D, QVector3D>>();
+
+ if (extent.first != d->m_minExtent) {
+ d->m_minExtent = extent.first;
+ emit minExtentChanged(extent.first);
+ }
+ if (extent.second != d->m_maxExtent) {
+ d->m_maxExtent = extent.second;
+ emit maxExtentChanged(d->m_maxExtent);
+ }
+ }
+ blockNotifications(blocked);
+ }
+}
+
/*!
\fn void Qt3DRender::QGeometry::addAttribute(Qt3DRender::QAttribute *attribute)
Adds an \a attribute to this geometry.
@@ -216,6 +238,40 @@ QAttribute *QGeometry::boundingVolumePositionAttribute() const
}
/*!
+ \qmlproperty vector3d Geometry::minExtent
+
+ Holds the vertex with the lowest x, y, z position values.
+ */
+
+/*!
+ \property QGeometry::minExtent
+
+ Holds the vertex with the lowest x, y, z position values.
+ */
+QVector3D QGeometry::minExtent() const
+{
+ Q_D(const QGeometry);
+ return d->m_minExtent;
+}
+
+/*!
+ \qmlproperty vector3d Geometry::maxExtent
+
+ Holds the vertex with the highest x, y, z position values.
+ */
+
+/*!
+ \property QGeometry::maxExtent
+
+ Holds the vertex with the highest x, y, z position values.
+ */
+QVector3D QGeometry::maxExtent() const
+{
+ Q_D(const QGeometry);
+ return d->m_maxExtent;
+}
+
+/*!
Returns the list of attributes in this geometry.
*/
QVector<QAttribute *> QGeometry::attributes() const
diff --git a/src/render/geometry/qgeometry.h b/src/render/geometry/qgeometry.h
index 0e6f7d68e..61508c7d2 100644
--- a/src/render/geometry/qgeometry.h
+++ b/src/render/geometry/qgeometry.h
@@ -54,6 +54,8 @@ class QT3DRENDERSHARED_EXPORT QGeometry : public Qt3DCore::QNode
{
Q_OBJECT
Q_PROPERTY(Qt3DRender::QAttribute *boundingVolumePositionAttribute READ boundingVolumePositionAttribute WRITE setBoundingVolumePositionAttribute NOTIFY boundingVolumePositionAttributeChanged)
+ Q_PROPERTY(QVector3D minExtent READ minExtent NOTIFY minExtentChanged REVISION 13)
+ Q_PROPERTY(QVector3D maxExtent READ maxExtent NOTIFY maxExtentChanged REVISION 13)
public:
explicit QGeometry(Qt3DCore::QNode *parent = nullptr);
~QGeometry();
@@ -63,15 +65,19 @@ public:
Q_INVOKABLE void removeAttribute(Qt3DRender::QAttribute *attribute);
QAttribute *boundingVolumePositionAttribute() const;
+ QVector3D minExtent() const;
+ QVector3D maxExtent() const;
public Q_SLOTS:
void setBoundingVolumePositionAttribute(QAttribute *boundingVolumePositionAttribute);
Q_SIGNALS:
void boundingVolumePositionAttributeChanged(QAttribute *boundingVolumePositionAttribute);
-
+ void minExtentChanged(const QVector3D &minExtent);
+ void maxExtentChanged(const QVector3D &maxExtent);
protected:
explicit QGeometry(QGeometryPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
private:
Q_DECLARE_PRIVATE(QGeometry)
diff --git a/src/render/geometry/qgeometry_p.h b/src/render/geometry/qgeometry_p.h
index e07b9ff0d..f53548e43 100644
--- a/src/render/geometry/qgeometry_p.h
+++ b/src/render/geometry/qgeometry_p.h
@@ -53,6 +53,7 @@
#include <Qt3DRender/private/qt3drender_global_p.h>
#include <Qt3DCore/private/qnode_p.h>
+#include <QVector3D>
QT_BEGIN_NAMESPACE
@@ -68,6 +69,8 @@ public:
QVector<QAttribute *> m_attributes;
QAttribute *m_boundingVolumePositionAttribute;
+ QVector3D m_minExtent;
+ QVector3D m_maxExtent;
};
struct QGeometryData
diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp
index 66d59f812..68eb308c5 100644
--- a/src/render/jobs/calcboundingvolumejob.cpp
+++ b/src/render/jobs/calcboundingvolumejob.cpp
@@ -65,14 +65,25 @@ namespace Render {
namespace {
-void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node);
+QVector<Geometry*> calculateLocalBoundingVolume(NodeManagers *manager, Entity *node);
-struct UpdateBoundFunctor {
+struct UpdateBoundFunctor
+{
NodeManagers *manager;
- void operator ()(Qt3DRender::Render::Entity *node)
+ // This define is required to work with QtConcurrent
+ typedef QVector<Geometry *> result_type;
+ QVector<Geometry *> operator ()(Qt3DRender::Render::Entity *node)
+ {
+ return calculateLocalBoundingVolume(manager, node);
+ }
+};
+
+struct ReduceUpdateBoundFunctor
+{
+ void operator ()(QVector<Geometry *> &result, const QVector<Geometry *> &values)
{
- calculateLocalBoundingVolume(manager, node);
+ result += values;
}
};
@@ -82,6 +93,8 @@ public:
BoundingVolumeCalculator(NodeManagers *manager) : m_manager(manager) { }
const Sphere& result() { return m_volume; }
+ const QVector3D min() const { return m_min; }
+ const QVector3D max() const { return m_max; }
bool apply(Qt3DRender::Render::Attribute *positionAttribute,
Qt3DRender::Render::Attribute *indexAttribute,
@@ -95,6 +108,9 @@ public:
return false;
}
+ m_min = QVector3D(findExtremePoints.xMin, findExtremePoints.yMin, findExtremePoints.zMin);
+ m_max = QVector3D(findExtremePoints.xMax, findExtremePoints.yMax, findExtremePoints.zMax);
+
// Calculate squared distance for the pairs of points
const float xDist2 = (findExtremePoints.xMaxPt - findExtremePoints.xMinPt).lengthSquared();
const float yDist2 = (findExtremePoints.yMaxPt - findExtremePoints.yMinPt).lengthSquared();
@@ -127,6 +143,8 @@ public:
private:
Sphere m_volume;
NodeManagers *m_manager;
+ QVector3D m_min;
+ QVector3D m_max;
class FindExtremePoints : public Buffer3fVisitor
{
@@ -191,17 +209,20 @@ private:
};
};
-void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
+QVector<Geometry *> calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
{
// The Bounding volume will only be computed if the position Buffer
// isDirty
+ QVector<Geometry *> updatedGeometries;
+
if (!node->isTreeEnabled())
- return;
+ return updatedGeometries;
GeometryRenderer *gRenderer = node->renderComponent<GeometryRenderer>();
+ GeometryManager *geometryManager = manager->geometryManager();
if (gRenderer && gRenderer->primitiveType() != QGeometryRenderer::Patches) {
- Geometry *geom = manager->lookupResource<Geometry, GeometryManager>(gRenderer->geometryId());
+ Geometry *geom = geometryManager->lookupResource(gRenderer->geometryId());
if (geom) {
int drawVertexCount = gRenderer->vertexCount(); // may be 0, gets changed below if so
@@ -224,14 +245,14 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
|| positionAttribute->vertexBaseType() != QAttribute::Float
|| positionAttribute->vertexSize() < 3) {
qWarning("calculateLocalBoundingVolume: Position attribute not suited for bounding volume computation");
- return;
+ return updatedGeometries;
}
Buffer *buf = manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
// No point in continuing if the positionAttribute doesn't have a suitable buffer
if (!buf) {
qWarning("calculateLocalBoundingVolume: Position attribute not referencing a valid buffer");
- return;
+ return updatedGeometries;
}
// Check if there is an index attribute.
@@ -259,7 +280,7 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
std::end(validIndexTypes),
indexAttribute->vertexBaseType()) == std::end(validIndexTypes)) {
qWarning() << "calculateLocalBoundingVolume: Unsupported index attribute type" << indexAttribute->name() << indexAttribute->vertexBaseType();
- return;
+ return updatedGeometries;
}
break;
@@ -287,6 +308,11 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
node->localBoundingVolume()->setCenter(reader.result().center());
node->localBoundingVolume()->setRadius(reader.result().radius());
node->unsetBoundingVolumeDirty();
+
+ // Record min/max vertex in Geometry
+ geom->updateExtent(reader.min(), reader.max());
+ // Mark geometry as requiring a call to update its frontend
+ updatedGeometries.push_back(geom);
}
}
}
@@ -297,14 +323,16 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
if (children.size() > 1) {
UpdateBoundFunctor functor;
functor.manager = manager;
- QtConcurrent::blockingMap(children, functor);
+ ReduceUpdateBoundFunctor reduceFunctor;
+ updatedGeometries += QtConcurrent::blockingMappedReduced<decltype(updatedGeometries)>(children, functor, reduceFunctor);
} else
#endif
{
const auto children = node->children();
for (Entity *child : children)
- calculateLocalBoundingVolume(manager, child);
+ updatedGeometries += calculateLocalBoundingVolume(manager, child);
}
+ return updatedGeometries;
}
} // anonymous
@@ -318,7 +346,11 @@ CalculateBoundingVolumeJob::CalculateBoundingVolumeJob()
void CalculateBoundingVolumeJob::run()
{
- calculateLocalBoundingVolume(m_manager, m_node);
+ const QVector<Geometry *> updatedGeometries = calculateLocalBoundingVolume(m_manager, m_node);
+
+ // Send extent updates to frontend
+ for (Geometry *geometry : updatedGeometries)
+ geometry->notifyExtentChanged();
}
void CalculateBoundingVolumeJob::setRoot(Entity *node)
diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h
index 2ae7d81ff..e776d452d 100644
--- a/src/render/jobs/job_common_p.h
+++ b/src/render/jobs/job_common_p.h
@@ -107,7 +107,8 @@ namespace JobTypes {
SyncFilterEntityByLayer,
SyncMaterialGatherer,
UpdateLayerEntity,
- SendTextureChangesToFrontend
+ SendTextureChangesToFrontend,
+ SendSetFenceHandlesToFrontend,
};
} // JobTypes
diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index 2050b8772..96ec11b4e 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -211,7 +211,6 @@ bool PickBoundingVolumeJob::runHelper()
const bool edgePickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::LinePicking);
const bool pointPickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::PointPicking);
const bool primitivePickingRequested = pointPickingRequested | edgePickingRequested | trianglePickingRequested;
- const bool allHitsRequested = (m_renderSettings->pickResultMode() == QPickingSettings::AllPicks);
const bool frontFaceRequested =
m_renderSettings->faceOrientationPickingMode() != QPickingSettings::BackFace;
const bool backFaceRequested =
@@ -237,7 +236,7 @@ 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, allHitsRequested);
+ dispatchPickEvents(event.second, PickingUtils::HitList(), eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode());
continue;
}
@@ -249,14 +248,16 @@ bool PickBoundingVolumeJob::runHelper()
gathererFunctor.m_backFaceRequested = backFaceRequested;
gathererFunctor.m_manager = m_manager;
gathererFunctor.m_ray = ray;
- sphereHits << gathererFunctor.computeHits(entityPicker.entities(), allHitsRequested);
+ gathererFunctor.m_entityToPriorityTable = entityPicker.entityToPriorityTable();
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), m_renderSettings->pickResultMode());
}
if (edgePickingRequested) {
PickingUtils::LineCollisionGathererFunctor gathererFunctor;
gathererFunctor.m_manager = m_manager;
gathererFunctor.m_ray = ray;
gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
- sphereHits << gathererFunctor.computeHits(entityPicker.entities(), allHitsRequested);
+ gathererFunctor.m_entityToPriorityTable = entityPicker.entityToPriorityTable();
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), m_renderSettings->pickResultMode());
PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
}
if (pointPickingRequested) {
@@ -264,19 +265,20 @@ bool PickBoundingVolumeJob::runHelper()
gathererFunctor.m_manager = m_manager;
gathererFunctor.m_ray = ray;
gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
- sphereHits << gathererFunctor.computeHits(entityPicker.entities(), allHitsRequested);
+ gathererFunctor.m_entityToPriorityTable = entityPicker.entityToPriorityTable();
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), m_renderSettings->pickResultMode());
PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
}
if (!primitivePickingRequested) {
sphereHits << entityPicker.hits();
PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
- if (!allHitsRequested)
+ if (m_renderSettings->pickResultMode() != QPickingSettings::AllPicks)
sphereHits = { sphereHits.front() };
}
}
// Dispatch events based on hit results
- dispatchPickEvents(event.second, sphereHits, eventButton, eventButtons, eventModifiers, allHitsRequested);
+ dispatchPickEvents(event.second, sphereHits, eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode());
}
}
diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp
index 5fed946d6..23e495ecb 100644
--- a/src/render/jobs/pickboundingvolumeutils.cpp
+++ b/src/render/jobs/pickboundingvolumeutils.cpp
@@ -55,6 +55,7 @@
#include <vector>
#include <algorithm>
+#include <functional>
QT_BEGIN_NAMESPACE
@@ -418,6 +419,46 @@ HitList reduceToFirstHit(HitList &result, const HitList &intermediate)
return result;
}
+
+struct HighestPriorityHitReducer
+{
+ // No need to protect this from concurrent access as the table
+ // is read only
+ const QHash<Qt3DCore::QNodeId, int> entityToPriorityTable;
+
+ HitList operator()(HitList &result, const HitList &intermediate)
+ {
+ // Sort by priority first
+ // If we have equal priorities, we then sort by distance
+
+ if (!intermediate.empty()) {
+ if (result.empty())
+ result.push_back(intermediate.front());
+ int currentPriority = entityToPriorityTable.value(result.front().m_entityId, 0);
+ float closest = result.front().m_distance;
+
+ for (const auto &v : intermediate) {
+ const int newEntryPriority = entityToPriorityTable.value(v.m_entityId, 0);
+ if (newEntryPriority > currentPriority) {
+ result.push_front(v);
+ currentPriority = newEntryPriority;
+ closest = v.m_distance;
+ } else if (newEntryPriority == currentPriority) {
+ if (v.m_distance < closest) {
+ result.push_front(v);
+ closest = v.m_distance;
+ currentPriority = newEntryPriority;
+ }
+ }
+ }
+
+ while (result.size() > 1)
+ result.pop_back();
+ }
+ return result;
+ }
+};
+
HitList reduceToAllHits(HitList &results, const HitList &intermediate)
{
if (!intermediate.empty())
@@ -492,9 +533,22 @@ struct MapFunctorHolder
} // anonymous
-HitList EntityCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested)
-{
- const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+HitList EntityCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities,
+ Qt3DRender::QPickingSettings::PickResultMode mode)
+{
+ std::function<HitList (HitList &, const HitList &)> reducerOp;
+ switch (mode) {
+ case QPickingSettings::AllPicks:
+ reducerOp = PickingUtils::reduceToAllHits;
+ break;
+ case QPickingSettings::NearestPriorityPick:
+ reducerOp = HighestPriorityHitReducer{ m_entityToPriorityTable };
+ break;
+ case QPickingSettings::NearestPick:
+ reducerOp = PickingUtils::reduceToFirstHit;
+ break;
+ }
+
const MapFunctorHolder holder(this);
#if QT_CONFIG(concurrent)
return QtConcurrent::blockingMappedReduced<HitList>(entities, holder, reducerOp);
@@ -519,9 +573,22 @@ HitList EntityCollisionGathererFunctor::pick(const Entity *entity) const
return result;
}
-HitList TriangleCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested)
-{
- const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+HitList TriangleCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities,
+ Qt3DRender::QPickingSettings::PickResultMode mode)
+{
+ std::function<HitList (HitList &, const HitList &)> reducerOp;
+ switch (mode) {
+ case QPickingSettings::AllPicks:
+ reducerOp = PickingUtils::reduceToAllHits;
+ break;
+ case QPickingSettings::NearestPriorityPick:
+ reducerOp = HighestPriorityHitReducer { m_entityToPriorityTable };
+ break;
+ case QPickingSettings::NearestPick:
+ reducerOp = PickingUtils::reduceToFirstHit;
+ break;
+ }
+
const MapFunctorHolder holder(this);
#if QT_CONFIG(concurrent)
return QtConcurrent::blockingMappedReduced<HitList>(entities, holder, reducerOp);
@@ -553,9 +620,22 @@ HitList TriangleCollisionGathererFunctor::pick(const Entity *entity) const
return result;
}
-HitList LineCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested)
-{
- const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+HitList LineCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities,
+ Qt3DRender::QPickingSettings::PickResultMode mode)
+{
+ std::function<HitList (HitList &, const HitList &)> reducerOp;
+ switch (mode) {
+ case QPickingSettings::AllPicks:
+ reducerOp = PickingUtils::reduceToAllHits;
+ break;
+ case QPickingSettings::NearestPriorityPick:
+ reducerOp = HighestPriorityHitReducer { m_entityToPriorityTable };
+ break;
+ case QPickingSettings::NearestPick:
+ reducerOp = PickingUtils::reduceToFirstHit;
+ break;
+ }
+
const MapFunctorHolder holder(this);
#if QT_CONFIG(concurrent)
return QtConcurrent::blockingMappedReduced<HitList>(entities, holder, reducerOp);
@@ -586,9 +666,22 @@ HitList LineCollisionGathererFunctor::pick(const Entity *entity) const
return result;
}
-HitList PointCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested)
-{
- const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+HitList PointCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities,
+ Qt3DRender::QPickingSettings::PickResultMode mode)
+{
+ std::function<HitList (HitList &, const HitList &)> reducerOp;
+ switch (mode) {
+ case QPickingSettings::AllPicks:
+ reducerOp = PickingUtils::reduceToAllHits;
+ break;
+ case QPickingSettings::NearestPriorityPick:
+ reducerOp = HighestPriorityHitReducer { m_entityToPriorityTable };
+ break;
+ case QPickingSettings::NearestPick:
+ reducerOp = PickingUtils::reduceToFirstHit;
+ break;
+ }
+
const MapFunctorHolder holder(this);
#if QT_CONFIG(concurrent)
return QtConcurrent::blockingMappedReduced<HitList>(entities, holder, reducerOp);
@@ -641,15 +734,17 @@ bool HierarchicalEntityPicker::collectHits(NodeManagers *manager, Entity *root)
{
m_hits.clear();
m_entities.clear();
+ m_entityToPriorityTable.clear();
QRayCastingService rayCasting;
struct EntityData {
Entity* entity;
bool hasObjectPicker;
Qt3DCore::QNodeIdVector recursiveLayers;
+ int priority;
};
std::vector<EntityData> worklist;
- worklist.push_back({root, !root->componentHandle<ObjectPicker>().isNull(), {}});
+ worklist.push_back({root, !root->componentHandle<ObjectPicker>().isNull(), {}, 0});
LayerManager *layerManager = manager->layerManager();
@@ -710,6 +805,8 @@ bool HierarchicalEntityPicker::collectHits(NodeManagers *manager, Entity *root)
if (accepted && queryResult.m_distance >= 0.f && (current.hasObjectPicker || !m_objectPickersRequired)) {
m_entities.push_back(current.entity);
m_hits.push_back(queryResult);
+ // Record entry for entity/priority
+ m_entityToPriorityTable.insert(current.entity->peerId(), current.priority);
}
Qt3DCore::QNodeIdVector recursiveLayers;
@@ -722,9 +819,12 @@ bool HierarchicalEntityPicker::collectHits(NodeManagers *manager, Entity *root)
// and pick children
const auto children = current.entity->children();
- for (auto child: children)
- worklist.push_back({child, current.hasObjectPicker || !child->componentHandle<ObjectPicker>().isNull(),
- current.recursiveLayers + recursiveLayers});
+ for (Entity *child: children) {
+ ObjectPicker *childPicker = child->renderComponent<ObjectPicker>();
+ worklist.push_back({child, current.hasObjectPicker || childPicker,
+ current.recursiveLayers + recursiveLayers,
+ (childPicker ? childPicker->priority() : current.priority)});
+ }
}
return !m_hits.empty();
diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h
index 780c16cc8..3fc4517c3 100644
--- a/src/render/jobs/pickboundingvolumeutils_p.h
+++ b/src/render/jobs/pickboundingvolumeutils_p.h
@@ -55,6 +55,7 @@
#include <Qt3DRender/QAbstractRayCaster>
#include <Qt3DRender/private/qray3d_p.h>
#include <Qt3DRender/private/qraycastingservice_p.h>
+#include <Qt3DRender/qpickingsettings.h>
QT_BEGIN_NAMESPACE
@@ -124,6 +125,7 @@ public:
bool collectHits(NodeManagers *manager, Entity *root);
inline HitList hits() const { return m_hits; }
inline QVector<Entity *> entities() const { return m_entities; }
+ inline QHash<Qt3DCore::QNodeId, int> entityToPriorityTable() const { return m_entityToPriorityTable; }
private:
RayCasting::QRay3D m_ray;
@@ -132,6 +134,7 @@ private:
bool m_objectPickersRequired;
Qt3DCore::QNodeIdVector m_layerIds;
QAbstractRayCaster::FilterMode m_filterMode;
+ QHash<Qt3DCore::QNodeId, int> m_entityToPriorityTable;
};
struct Q_AUTOTEST_EXPORT AbstractCollisionGathererFunctor
@@ -142,8 +145,9 @@ struct Q_AUTOTEST_EXPORT AbstractCollisionGathererFunctor
bool m_objectPickersRequired = true;
NodeManagers *m_manager = nullptr;
RayCasting::QRay3D m_ray;
+ QHash<Qt3DCore::QNodeId, int> m_entityToPriorityTable;
- virtual HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) = 0;
+ virtual HitList computeHits(const QVector<Entity *> &entities, Qt3DRender::QPickingSettings::PickResultMode mode) = 0;
// This define is required to work with QtConcurrent
typedef HitList result_type;
@@ -156,7 +160,7 @@ struct Q_AUTOTEST_EXPORT AbstractCollisionGathererFunctor
struct Q_AUTOTEST_EXPORT EntityCollisionGathererFunctor : public AbstractCollisionGathererFunctor
{
- HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) override;
+ HitList computeHits(const QVector<Entity *> &entities, Qt3DRender::QPickingSettings::PickResultMode mode) override;
HitList pick(const Entity *entity) const override;
};
@@ -165,7 +169,7 @@ struct Q_AUTOTEST_EXPORT TriangleCollisionGathererFunctor : public AbstractColli
bool m_frontFaceRequested;
bool m_backFaceRequested;
- HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) override;
+ HitList computeHits(const QVector<Entity *> &entities, Qt3DRender::QPickingSettings::PickResultMode mode) override;
HitList pick(const Entity *entity) const override;
};
@@ -173,7 +177,7 @@ struct Q_AUTOTEST_EXPORT LineCollisionGathererFunctor : public AbstractCollision
{
float m_pickWorldSpaceTolerance;
- HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) override;
+ HitList computeHits(const QVector<Entity *> &entities, Qt3DRender::QPickingSettings::PickResultMode mode) override;
HitList pick(const Entity *entity) const override;
};
@@ -181,7 +185,7 @@ struct Q_AUTOTEST_EXPORT PointCollisionGathererFunctor : public AbstractCollisio
{
float m_pickWorldSpaceTolerance;
- HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) override;
+ HitList computeHits(const QVector<Entity *> &entities, Qt3DRender::QPickingSettings::PickResultMode mode) override;
HitList pick(const Entity *entity) const override;
};
diff --git a/src/render/jobs/raycastingjob.cpp b/src/render/jobs/raycastingjob.cpp
index e76b9fe8d..70c7ac374 100644
--- a/src/render/jobs/raycastingjob.cpp
+++ b/src/render/jobs/raycastingjob.cpp
@@ -183,7 +183,7 @@ bool RayCastingJob::runHelper()
gathererFunctor.m_manager = m_manager;
gathererFunctor.m_ray = ray;
gathererFunctor.m_objectPickersRequired = false;
- sphereHits << gathererFunctor.computeHits(entityPicker.entities(), true);
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), QPickingSettings::AllPicks);
}
if (edgePickingRequested) {
PickingUtils::LineCollisionGathererFunctor gathererFunctor;
@@ -191,7 +191,7 @@ bool RayCastingJob::runHelper()
gathererFunctor.m_ray = ray;
gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
gathererFunctor.m_objectPickersRequired = false;
- sphereHits << gathererFunctor.computeHits(entityPicker.entities(), true);
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), QPickingSettings::AllPicks);
PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
}
if (pointPickingRequested) {
@@ -200,7 +200,7 @@ bool RayCastingJob::runHelper()
gathererFunctor.m_ray = ray;
gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
gathererFunctor.m_objectPickersRequired = false;
- sphereHits << gathererFunctor.computeHits(entityPicker.entities(), true);
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), QPickingSettings::AllPicks);
PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
}
if (!primitivePickingRequested) {
diff --git a/src/render/jobs/sendbuffercapturejob.cpp b/src/render/jobs/sendbuffercapturejob.cpp
index eae26ba6c..8683ea9f2 100644
--- a/src/render/jobs/sendbuffercapturejob.cpp
+++ b/src/render/jobs/sendbuffercapturejob.cpp
@@ -67,6 +67,12 @@ void SendBufferCaptureJob::addRequest(QPair<Buffer *, QByteArray> request)
m_pendingSendBufferCaptures.push_back(request);
}
+// Called by aspect thread jobs to execute (no concurrency at that point)
+bool SendBufferCaptureJob::hasRequests() const
+{
+ return m_pendingSendBufferCaptures.size() > 0;
+}
+
void SendBufferCaptureJob::run()
{
QMutexLocker locker(&m_mutex);
diff --git a/src/render/jobs/sendbuffercapturejob_p.h b/src/render/jobs/sendbuffercapturejob_p.h
index 771497e2f..854414ec6 100644
--- a/src/render/jobs/sendbuffercapturejob_p.h
+++ b/src/render/jobs/sendbuffercapturejob_p.h
@@ -75,6 +75,7 @@ public:
~SendBufferCaptureJob();
void addRequest(QPair<Buffer*, QByteArray> request);
+ bool hasRequests() const;
void run() final;
diff --git a/src/render/materialsystem/qshaderprogrambuilder.cpp b/src/render/materialsystem/qshaderprogrambuilder.cpp
index 9318f96af..84dd33372 100644
--- a/src/render/materialsystem/qshaderprogrambuilder.cpp
+++ b/src/render/materialsystem/qshaderprogrambuilder.cpp
@@ -94,6 +94,53 @@ 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
@@ -311,6 +358,114 @@ QUrl QShaderProgramBuilder::computeShaderGraph() const
return d->m_computeShaderGraph;
}
+/*!
+ \qmlproperty string ShaderProgramBuilder:vertexShaderCode
+
+ Holds the generated vertex shader code
+ \since 2.13
+*/
+/*!
+ \property QShaderProgram:Builder:vertexShaderCode
+
+ Holds the generate vertex shader code.
+ \since 5.13
+*/
+QByteArray QShaderProgramBuilder::vertexShaderCode() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_vertexShaderCode;
+}
+
+/*!
+ \qmlproperty string ShaderProgramBuilder:tessellationControlShaderCode
+
+ Holds the generated tessellation control shader code
+ \since 2.13
+*/
+/*!
+ \property QShaderProgram:Builder:tessellationControlShaderCode
+
+ Holds the generate tessellation control shader code.
+ \since 5.13
+*/
+QByteArray QShaderProgramBuilder::tessellationControlShaderCode() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_tessControlShaderCode;
+}
+
+/*!
+ \qmlproperty string ShaderProgramBuilder:tessellationEvaluationShaderCode
+
+ Holds the generated tessellation evaluation shader code
+ \since 2.13
+*/
+/*!
+ \property QShaderProgram:Builder:tessellationEvaluationShaderCode
+
+ Holds the generate tessellation evaluation shader code.
+ \since 5.13
+*/
+QByteArray QShaderProgramBuilder::tessellationEvaluationShaderCode() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_tessEvalShaderCode;
+}
+
+/*!
+ \qmlproperty string ShaderProgramBuilder:geometryShaderCode
+
+ Holds the generated geometry shader code
+ \since 2.13
+*/
+/*!
+ \property QShaderProgram:Builder:geometryShaderCode
+
+ Holds the generate geometry shader code.
+ \since 5.13
+*/
+QByteArray QShaderProgramBuilder::geometryShaderCode() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_geometryShaderCode;
+}
+
+/*!
+ \qmlproperty string ShaderProgramBuilder::fragmentShaderCode
+
+ Holds the generated fragment shader code
+ \since 2.13
+*/
+/*!
+ \property QShaderProgram:Builder:fragmentShaderCode
+
+ Holds the generate fragment shader code.
+ \since 5.13
+*/
+QByteArray QShaderProgramBuilder::fragmentShaderCode() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_fragmentShaderCode;
+}
+
+/*!
+ \qmlproperty string ShaderProgramBuilder::computeShaderCode
+
+ Holds the generated compute shader code
+ \since 2.13
+*/
+/*!
+ \property QShaderProgram:Builder:computeShaderCode
+
+ Holds the generate compute shader code.
+ \since 5.13
+*/
+QByteArray QShaderProgramBuilder::computeShaderCode() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_computeShaderCode;
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QShaderProgramBuilder::createNodeCreationChange() const
{
auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QShaderProgramBuilderData>::create(this);
diff --git a/src/render/materialsystem/qshaderprogrambuilder.h b/src/render/materialsystem/qshaderprogrambuilder.h
index fbbf7c752..532aa7d73 100644
--- a/src/render/materialsystem/qshaderprogrambuilder.h
+++ b/src/render/materialsystem/qshaderprogrambuilder.h
@@ -63,6 +63,12 @@ class QT3DRENDERSHARED_EXPORT QShaderProgramBuilder : public Qt3DCore::QNode
Q_PROPERTY(QUrl geometryShaderGraph READ geometryShaderGraph WRITE setGeometryShaderGraph NOTIFY geometryShaderGraphChanged)
Q_PROPERTY(QUrl fragmentShaderGraph READ fragmentShaderGraph WRITE setFragmentShaderGraph NOTIFY fragmentShaderGraphChanged)
Q_PROPERTY(QUrl computeShaderGraph READ computeShaderGraph WRITE setComputeShaderGraph NOTIFY computeShaderGraphChanged)
+ Q_PROPERTY(QByteArray vertexShaderCode READ vertexShaderCode NOTIFY vertexShaderCodeChanged REVISION 13)
+ Q_PROPERTY(QByteArray tessellationControlShaderCode READ tessellationControlShaderCode NOTIFY tessellationControlShaderCodeChanged REVISION 13)
+ Q_PROPERTY(QByteArray tessellationEvaluationShaderCode READ tessellationEvaluationShaderCode NOTIFY tessellationEvaluationShaderCodeChanged REVISION 13)
+ Q_PROPERTY(QByteArray geometryShaderCode READ geometryShaderCode NOTIFY geometryShaderCodeChanged REVISION 13)
+ Q_PROPERTY(QByteArray fragmentShaderCode READ fragmentShaderCode NOTIFY fragmentShaderCodeChanged REVISION 13)
+ Q_PROPERTY(QByteArray computeShaderCode READ computeShaderCode NOTIFY computeShaderCodeChanged REVISION 13)
public:
explicit QShaderProgramBuilder(Qt3DCore::QNode *parent = nullptr);
@@ -76,6 +82,12 @@ public:
QUrl geometryShaderGraph() const;
QUrl fragmentShaderGraph() const;
QUrl computeShaderGraph() const;
+ QByteArray vertexShaderCode() const;
+ QByteArray tessellationControlShaderCode() const;
+ QByteArray tessellationEvaluationShaderCode() const;
+ QByteArray geometryShaderCode() const;
+ QByteArray fragmentShaderCode() const;
+ QByteArray computeShaderCode() const;
public Q_SLOTS:
void setShaderProgram(Qt3DRender::QShaderProgram *program);
@@ -96,9 +108,16 @@ Q_SIGNALS:
void geometryShaderGraphChanged(const QUrl &geometryShaderGraph);
void fragmentShaderGraphChanged(const QUrl &fragmentShaderGraph);
void computeShaderGraphChanged(const QUrl &computeShaderGraph);
+ void vertexShaderCodeChanged(const QByteArray &vertexShaderCode);
+ void tessellationControlShaderCodeChanged(const QByteArray &tessellationControlShaderCode);
+ void tessellationEvaluationShaderCodeChanged(const QByteArray &tessellationEvaluationShaderCode);
+ void geometryShaderCodeChanged(const QByteArray &geometryShaderCode);
+ void fragmentShaderCodeChanged(const QByteArray &fragmentShaderCode);
+ void computeShaderCodeChanged(const QByteArray &computeShaderCode);
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 e1b470229..2ac765a1d 100644
--- a/src/render/materialsystem/qshaderprogrambuilder_p.h
+++ b/src/render/materialsystem/qshaderprogrambuilder_p.h
@@ -74,6 +74,12 @@ public:
QUrl m_geometryShaderGraph;
QUrl m_fragmentShaderGraph;
QUrl m_computeShaderGraph;
+ QByteArray m_vertexShaderCode;
+ QByteArray m_tessControlShaderCode;
+ QByteArray m_tessEvalShaderCode;
+ QByteArray m_geometryShaderCode;
+ QByteArray m_fragmentShaderCode;
+ QByteArray m_computeShaderCode;
};
struct QShaderProgramBuilderData
diff --git a/src/render/materialsystem/shaderbuilder.cpp b/src/render/materialsystem/shaderbuilder.cpp
index 283866d68..e0683332f 100644
--- a/src/render/materialsystem/shaderbuilder.cpp
+++ b/src/render/materialsystem/shaderbuilder.cpp
@@ -40,6 +40,7 @@
#include "shaderbuilder_p.h"
#include <Qt3DRender/private/qshaderprogrambuilder_p.h>
+#include <Qt3DRender/qshaderprogram.h>
#include <Qt3DRender/private/qurlhelper_p.h>
#include <QtGui/private/qshaderformat_p.h>
@@ -111,6 +112,31 @@ 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();
@@ -284,6 +310,13 @@ void ShaderBuilder::generateCode(ShaderBuilder::ShaderType type)
const auto code = generator.createShaderCode(m_enabledLayers);
m_codes.insert(type, 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);
}
void ShaderBuilder::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
diff --git a/src/render/picking/objectpicker.cpp b/src/render/picking/objectpicker.cpp
index 76f00993c..43e308d20 100644
--- a/src/render/picking/objectpicker.cpp
+++ b/src/render/picking/objectpicker.cpp
@@ -53,6 +53,7 @@ namespace Render {
ObjectPicker::ObjectPicker()
: BackendNode(QBackendNode::ReadWrite)
+ , m_priority(0)
, m_isPressed(false)
, m_hoverEnabled(false)
, m_dragEnabled(false)
@@ -70,6 +71,7 @@ void ObjectPicker::cleanup()
m_isPressed = false;
m_hoverEnabled = false;
m_dragEnabled = false;
+ m_priority = 0;
notifyJob();
}
@@ -79,6 +81,7 @@ void ObjectPicker::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr
const auto &data = typedChange->data;
m_hoverEnabled = data.hoverEnabled;
m_dragEnabled = data.dragEnabled;
+ m_priority = data.priority;
notifyJob();
}
@@ -97,6 +100,8 @@ void ObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
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();
}
markDirty(AbstractRenderer::AllDirty);
@@ -175,6 +180,16 @@ void ObjectPicker::onExited()
notifyObservers(e);
}
+void ObjectPicker::setPriority(int priority)
+{
+ m_priority = priority;
+}
+
+int ObjectPicker::priority() const
+{
+ return m_priority;
+}
+
} // Render
} // Qt3DRender
diff --git a/src/render/picking/objectpicker_p.h b/src/render/picking/objectpicker_p.h
index b9c308afb..7389a4b53 100644
--- a/src/render/picking/objectpicker_p.h
+++ b/src/render/picking/objectpicker_p.h
@@ -81,10 +81,15 @@ public:
void onEntered();
void onExited();
+ // Needed for unit tests
+ void setPriority(int priority);
+ int priority() const;
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
void notifyJob();
+ int m_priority;
bool m_isPressed;
bool m_hoverEnabled;
bool m_dragEnabled;
diff --git a/src/render/picking/qobjectpicker.cpp b/src/render/picking/qobjectpicker.cpp
index c3671d018..a0b6d8dcd 100644
--- a/src/render/picking/qobjectpicker.cpp
+++ b/src/render/picking/qobjectpicker.cpp
@@ -266,6 +266,23 @@ void QObjectPicker::setDragEnabled(bool dragEnabled)
}
/*!
+ * Sets the picker's priority to \a priority. This is used when the pick result
+ * mode on QPickingSettings is set to QPickingSettings::NearestPriorityPick.
+ * Picking results are sorted by highest priority and shortest picking
+ * distance.
+ *
+ * \since 5.13
+ */
+void QObjectPicker::setPriority(int priority)
+{
+ Q_D(QObjectPicker);
+ if (priority != d->m_priority) {
+ d->m_priority = priority;
+ emit priorityChanged(priority);
+ }
+}
+
+/*!
\qmlproperty bool Qt3D.Render::ObjectPicker::dragEnabled
*/
/*!
@@ -312,6 +329,25 @@ bool QObjectPicker::isPressed() const
return d->m_pressed;
}
+/*!
+ \qmlproperty int Qt3D.Render::ObjectPicker::priority
+
+ The priority to be used when filtering pick results by priority when
+ PickingSettings.pickResultMode is set to PickingSettings.PriorityPick.
+*/
+/*!
+ \property Qt3DRender::QObjectPicker::priority
+
+ The priority to be used when filtering pick results by priority when
+ QPickingSettings::pickResultMode is set to
+ QPickingSettings::NearestPriorityPick.
+*/
+int QObjectPicker::priority() const
+{
+ Q_D(const QObjectPicker);
+ return d->m_priority;
+}
+
/*! \internal */
void QObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
{
@@ -465,6 +501,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QObjectPicker::createNodeCreationChange() co
Q_D(const QObjectPicker);
data.hoverEnabled = d->m_hoverEnabled;
data.dragEnabled = d->m_dragEnabled;
+ data.priority = d->m_priority;
return creationChange;
}
diff --git a/src/render/picking/qobjectpicker.h b/src/render/picking/qobjectpicker.h
index 9f3b138c3..1d15f6092 100644
--- a/src/render/picking/qobjectpicker.h
+++ b/src/render/picking/qobjectpicker.h
@@ -58,6 +58,7 @@ class QT3DRENDERSHARED_EXPORT QObjectPicker : public Qt3DCore::QComponent
Q_PROPERTY(bool dragEnabled READ isDragEnabled WRITE setDragEnabled NOTIFY dragEnabledChanged)
Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged)
Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged)
+ Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged REVISION 13)
public:
explicit QObjectPicker(QNode *parent = nullptr);
@@ -69,9 +70,12 @@ public:
bool containsMouse() const;
bool isPressed() const;
+ int priority() const;
+
public Q_SLOTS:
void setHoverEnabled(bool hoverEnabled);
void setDragEnabled(bool dragEnabled);
+ void setPriority(int priority);
Q_SIGNALS:
void pressed(Qt3DRender::QPickEvent *pick);
@@ -84,6 +88,7 @@ Q_SIGNALS:
void dragEnabledChanged(bool dragEnabled);
void pressedChanged(bool pressed);
void containsMouseChanged(bool containsMouse);
+ void priorityChanged(int priority);
protected:
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
diff --git a/src/render/picking/qobjectpicker_p.h b/src/render/picking/qobjectpicker_p.h
index 3c48b9419..384062bef 100644
--- a/src/render/picking/qobjectpicker_p.h
+++ b/src/render/picking/qobjectpicker_p.h
@@ -69,6 +69,7 @@ public:
, m_pressed(false)
, m_containsMouse(false)
, m_acceptedLastPressedEvent(true)
+ , m_priority(0)
{
m_shareable = false;
}
@@ -79,6 +80,7 @@ public:
bool m_pressed;
bool m_containsMouse;
bool m_acceptedLastPressedEvent;
+ int m_priority;
enum EventType {
Pressed,
@@ -102,6 +104,7 @@ struct QObjectPickerData
{
bool hoverEnabled;
bool dragEnabled;
+ int priority;
};
} // namespace Qt3DRender
diff --git a/src/render/renderers/opengl/graphicshelpers/glfence_p.h b/src/render/renderers/opengl/graphicshelpers/glfence_p.h
new file mode 100644
index 000000000..366065048
--- /dev/null
+++ b/src/render/renderers/opengl/graphicshelpers/glfence_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** 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 GLFENCE_P_H
+#define GLFENCE_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 <QtGlobal>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+// GLsync is a pointer to a struct (unlike the rest of GL which used int ids)
+// We cannot reference GLsync as it's only available since 3.2 We use FenceId
+// to wrap that around and trust the GLHelpers will convert them accordingly.
+using GLFence = void *;
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // GLFENCE_P_H
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp
index c5753195b..71540b1ad 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp
@@ -318,6 +318,33 @@ void GraphicsHelperES2::drawBuffer(GLenum mode)
qWarning() << "glDrawBuffer is not supported with OpenGL ES 2";
}
+void *GraphicsHelperES2::fenceSync()
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+ return nullptr;
+}
+
+void GraphicsHelperES2::clientWaitSync(void *, GLuint64 )
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+}
+
+void GraphicsHelperES2::waitSync(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+}
+
+bool GraphicsHelperES2::wasSyncSignaled(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+ return false;
+}
+
+void GraphicsHelperES2::deleteSync(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+}
+
void GraphicsHelperES2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h
index 1c6df41b6..8c8dd34e9 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h
@@ -132,6 +132,12 @@ public:
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp
index 34c1e7448..5e5d2e001 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp
@@ -147,6 +147,26 @@ QT_BEGIN_NAMESPACE
#define GL_READ_FRAMEBUFFER 0x8CA8
#endif
+#ifndef GL_SIGNALED
+#define GL_SIGNALED 0x9119
+#endif
+
+#ifndef GL_SYNC_STATUS
+#define GL_SYNC_STATUS 0x9114
+#endif
+
+#ifndef GL_TIMEOUT_IGNORED
+#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
+#endif
+
+#ifndef GL_SYNC_GPU_COMMANDS_COMPLETE
+#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
+#endif
+
+#ifndef GL_SYNC_FLUSH_COMMANDS_BIT
+#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
+#endif
+
namespace Qt3DRender {
namespace Render {
@@ -307,6 +327,7 @@ bool GraphicsHelperES3::supportsFeature(GraphicsHelperInterface::Feature feature
case BlitFramebuffer:
case UniformBufferObject:
case MapBuffer:
+ case Fences:
return true;
default:
return false;
@@ -439,6 +460,37 @@ uint GraphicsHelperES3::uniformByteSize(const ShaderUniform &description)
return arrayStride ? rawByteSize * arrayStride : rawByteSize;
}
+void *GraphicsHelperES3::fenceSync()
+{
+ return m_extraFuncs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+void GraphicsHelperES3::clientWaitSync(void *sync, GLuint64 nanoSecTimeout)
+{
+ m_extraFuncs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout);
+}
+
+void GraphicsHelperES3::waitSync(void *sync)
+{
+ m_extraFuncs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED);
+}
+
+bool GraphicsHelperES3::wasSyncSignaled(void *sync)
+{
+ GLint v;
+ m_extraFuncs->glGetSynciv(static_cast<GLsync>(sync),
+ GL_SYNC_STATUS,
+ sizeof(v),
+ nullptr,
+ &v);
+ return v == GL_SIGNALED;
+}
+
+void GraphicsHelperES3::deleteSync(void *sync)
+{
+ m_extraFuncs->glDeleteSync(static_cast<GLsync>(sync));
+}
+
void GraphicsHelperES3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
{
m_extraFuncs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h
index d4467cf7f..dc5cef10c 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h
@@ -90,6 +90,12 @@ public:
UniformType uniformTypeFromGLType(GLenum glType) override;
uint uniformByteSize(const ShaderUniform &description) override;
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
protected:
QOpenGLExtraFunctions *m_extraFuncs = nullptr;
};
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp
index 6da8a9b6f..b6f3412b2 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp
@@ -272,6 +272,33 @@ void GraphicsHelperGL2::drawBuffer(GLenum mode)
m_funcs->glDrawBuffer(mode);
}
+void *GraphicsHelperGL2::fenceSync()
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+ return nullptr;
+}
+
+void GraphicsHelperGL2::clientWaitSync(void *, GLuint64 )
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+}
+
+void GraphicsHelperGL2::waitSync(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+}
+
+bool GraphicsHelperGL2::wasSyncSignaled(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+ return false;
+}
+
+void GraphicsHelperGL2::deleteSync(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+}
+
void GraphicsHelperGL2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -412,6 +439,7 @@ bool GraphicsHelperGL2::supportsFeature(GraphicsHelperInterface::Feature feature
case MRT:
return (m_fboFuncs != nullptr);
case TextureDimensionRetrieval:
+ case MapBuffer:
return true;
default:
return false;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h
index 2db75004f..b142b2623 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h
@@ -132,6 +132,12 @@ public:
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp
index a35c4e37f..5ff1a2ba5 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp
@@ -334,6 +334,37 @@ void GraphicsHelperGL3_2::drawBuffer(GLenum mode)
m_funcs->glDrawBuffer(mode);
}
+void *GraphicsHelperGL3_2::fenceSync()
+{
+ return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+void GraphicsHelperGL3_2::clientWaitSync(void *sync, GLuint64 nanoSecTimeout)
+{
+ m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout);
+}
+
+void GraphicsHelperGL3_2::waitSync(void *sync)
+{
+ m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED);
+}
+
+bool GraphicsHelperGL3_2::wasSyncSignaled(void *sync)
+{
+ GLint v;
+ m_funcs->glGetSynciv(static_cast<GLsync>(sync),
+ GL_SYNC_STATUS,
+ sizeof(v),
+ nullptr,
+ &v);
+ return v == GL_SIGNALED;
+}
+
+void GraphicsHelperGL3_2::deleteSync(void *sync)
+{
+ m_funcs->glDeleteSync(static_cast<GLsync>(sync));
+}
+
void GraphicsHelperGL3_2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -481,6 +512,7 @@ bool GraphicsHelperGL3_2::supportsFeature(GraphicsHelperInterface::Feature featu
case TextureDimensionRetrieval:
case BindableFragmentOutputs:
case BlitFramebuffer:
+ case Fences:
return true;
case Tessellation:
return !m_tessFuncs.isNull();
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h
index 133295fd7..9e81345ad 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h
@@ -134,6 +134,12 @@ public:
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp
index b2512d84a..81081943d 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp
@@ -330,6 +330,37 @@ void GraphicsHelperGL3_3::drawBuffer(GLenum mode)
m_funcs->glDrawBuffer(mode);
}
+void *GraphicsHelperGL3_3::fenceSync()
+{
+ return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+void GraphicsHelperGL3_3::clientWaitSync(void *sync, GLuint64 nanoSecTimeout)
+{
+ m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout);
+}
+
+void GraphicsHelperGL3_3::waitSync(void *sync)
+{
+ m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED);
+}
+
+bool GraphicsHelperGL3_3::wasSyncSignaled(void *sync)
+{
+ GLint v;
+ m_funcs->glGetSynciv(static_cast<GLsync>(sync),
+ GL_SYNC_STATUS,
+ sizeof(v),
+ nullptr,
+ &v);
+ return v == GL_SIGNALED;
+}
+
+void GraphicsHelperGL3_3::deleteSync(void *sync)
+{
+ m_funcs->glDeleteSync(static_cast<GLsync>(sync));
+}
+
void GraphicsHelperGL3_3::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -477,6 +508,7 @@ bool GraphicsHelperGL3_3::supportsFeature(GraphicsHelperInterface::Feature featu
case TextureDimensionRetrieval:
case BindableFragmentOutputs:
case BlitFramebuffer:
+ case Fences:
return true;
case Tessellation:
return !m_tessFuncs.isNull();
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h
index 0ecdd3620..c480e5258 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h
@@ -134,6 +134,12 @@ public:
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp
index ce1b8ac2b..22cbf7428 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp
@@ -400,6 +400,39 @@ void GraphicsHelperGL4::drawBuffer(GLenum mode)
m_funcs->glDrawBuffer(mode);
}
+void *GraphicsHelperGL4::fenceSync()
+{
+ return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+void GraphicsHelperGL4::clientWaitSync(void *sync, GLuint64 nanoSecTimeout)
+{
+ qDebug() << Q_FUNC_INFO << sync << static_cast<GLsync>(sync);
+ GLenum e = m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout);
+ qDebug() << e;
+}
+
+void GraphicsHelperGL4::waitSync(void *sync)
+{
+ m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED);
+}
+
+bool GraphicsHelperGL4::wasSyncSignaled(void *sync)
+{
+ GLint v = 0;
+ m_funcs->glGetSynciv(static_cast<GLsync>(sync),
+ GL_SYNC_STATUS,
+ sizeof(v),
+ nullptr,
+ &v);
+ return v == GL_SIGNALED;
+}
+
+void GraphicsHelperGL4::deleteSync(void *sync)
+{
+ m_funcs->glDeleteSync(static_cast<GLsync>(sync));
+}
+
void GraphicsHelperGL4::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform1fv(location, count, values);
@@ -746,6 +779,8 @@ bool GraphicsHelperGL4::supportsFeature(GraphicsHelperInterface::Feature feature
case DrawBuffersBlend:
case BlitFramebuffer:
case IndirectDrawing:
+ case MapBuffer:
+ case Fences:
return true;
default:
return false;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h
index 3020b16d8..da62f4212 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h
@@ -132,6 +132,12 @@ public:
void readBuffer(GLenum mode) override;
void drawBuffer(GLenum mode) override;
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h
index e41325cb7..2a1688b7f 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h
@@ -82,7 +82,8 @@ public:
DrawBuffersBlend,
BlitFramebuffer,
IndirectDrawing,
- MapBuffer
+ MapBuffer,
+ Fences
};
enum FBOBindMode {
@@ -155,6 +156,12 @@ public:
virtual void readBuffer(GLenum mode) = 0;
virtual void drawBuffer(GLenum mode) = 0;
+ virtual void *fenceSync() = 0;
+ virtual void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) = 0;
+ virtual void waitSync(void *sync) = 0;
+ virtual bool wasSyncSignaled(void *sync) = 0;
+ virtual void deleteSync(void *sync) = 0;
+
virtual void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) = 0;
virtual void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) = 0;
virtual void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) = 0;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri
index 9b25be0eb..5c9479d2b 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri
@@ -13,7 +13,8 @@ HEADERS += \
$$PWD/graphicshelpergl3_3_p.h \
$$PWD/graphicshelpergl4_p.h \
$$PWD/graphicshelpergl3_2_p.h \
- $$PWD/submissioncontext_p.h
+ $$PWD/submissioncontext_p.h \
+ $$PWD/glfence_p.h
SOURCES += \
$$PWD/graphicscontext.cpp \
diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp
index dc1e85b8e..d1ac853ea 100644
--- a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp
@@ -929,10 +929,22 @@ int SubmissionContext::activateTexture(TextureScope scope, GLTexture *tex, int o
// Note: tex->dna() could be 0 if the texture has not been created yet
if (m_activeTextures[onUnit].texture != tex) {
// Texture must have been created and updated at this point
- QOpenGLTexture *glTex = tex->getGLTexture();
- if (glTex == nullptr)
- return -1;
- glTex->bind(onUnit);
+
+ const int sharedTextureId = tex->sharedTextureId();
+
+ // We have a valid texture id provided by a shared context
+ if (sharedTextureId > 0) {
+ m_gl->functions()->glActiveTexture(GL_TEXTURE0 + onUnit);
+ const QAbstractTexture::Target target = tex->properties().target;
+ // For now we know that target values correspond to the GL values
+ m_gl->functions()->glBindTexture(target, tex->sharedTextureId());
+ } else {
+ QOpenGLTexture *glTex = tex->getGLTexture();
+ if (glTex == nullptr)
+ return -1;
+ glTex->bind(onUnit);
+ }
+
if (m_activeTextures[onUnit].texture)
TextureExtRendererLocker::unlock(m_activeTextures[onUnit].texture);
m_activeTextures[onUnit].texture = tex;
@@ -1249,6 +1261,33 @@ void SubmissionContext::clearStencilValue(int stencil)
}
}
+GLFence SubmissionContext::fenceSync()
+{
+ return m_glHelper->fenceSync();
+}
+
+void SubmissionContext::clientWaitSync(GLFence sync, GLuint64 nanoSecTimeout)
+{
+ qDebug() << Q_FUNC_INFO << sync;
+ m_glHelper->clientWaitSync(sync, nanoSecTimeout);
+}
+
+void SubmissionContext::waitSync(GLFence sync)
+{
+ qDebug() << Q_FUNC_INFO << sync;
+ m_glHelper->waitSync(sync);
+}
+
+bool SubmissionContext::wasSyncSignaled(GLFence sync)
+{
+ return m_glHelper->wasSyncSignaled(sync);
+}
+
+void SubmissionContext::deleteSync(GLFence sync)
+{
+ m_glHelper->deleteSync(sync);
+}
+
// It will be easier if the QGraphicContext applies the QUniformPack
// than the other way around
bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h
index d502a8b27..dbfaef148 100644
--- a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h
@@ -59,6 +59,7 @@
#include <Qt3DRender/qattribute.h>
#include <Qt3DRender/private/handle_types_p.h>
#include <Qt3DRender/private/shadercache_p.h>
+#include <Qt3DRender/private/glfence_p.h>
QT_BEGIN_NAMESPACE
@@ -163,6 +164,14 @@ public:
void clearDepthValue(float depth);
void clearStencilValue(int stencil);
+
+ // Fences
+ GLFence fenceSync();
+ void clientWaitSync(GLFence sync, GLuint64 nanoSecTimeout);
+ void waitSync(GLFence sync);
+ bool wasSyncSignaled(GLFence sync);
+ void deleteSync(GLFence sync);
+
private:
void initialize();
diff --git a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp
index 629e7e935..9dd7faacc 100644
--- a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp
+++ b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp
@@ -68,6 +68,7 @@
#include <Qt3DRender/private/techniquemanager_p.h>
#include <Qt3DRender/private/memorybarrier_p.h>
#include <Qt3DRender/private/blitframebuffer_p.h>
+#include <Qt3DRender/private/waitfence_p.h>
QT_BEGIN_NAMESPACE
@@ -272,6 +273,17 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
break;
}
+ case FrameGraphNode::WaitFence: {
+ const Render::WaitFence *waitFence = static_cast<const Render::WaitFence *>(node);
+ rv->appendWaitFence(waitFence->data());
+ break;
+ }
+
+ case FrameGraphNode::SetFence: {
+ rv->appendInsertFenceId(node->peerId());
+ break;
+ }
+
default:
// Should never get here
qCWarning(Backend) << "Unhandled FrameGraphNode type";
diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp
index 7ed766f8b..4abe62bab 100644
--- a/src/render/renderers/opengl/renderer/renderer.cpp
+++ b/src/render/renderers/opengl/renderer/renderer.cpp
@@ -91,6 +91,7 @@
#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/qcameralens.h>
#include <Qt3DCore/private/qeventfilterservice_p.h>
@@ -196,6 +197,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, 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_ownedContext(false)
@@ -388,6 +390,9 @@ void Renderer::initialize()
[this] { releaseGraphicsResources(); });
}
+ qCDebug(Backend) << "Qt3D shared context:" << ctx->shareContext();
+ qCDebug(Backend) << "Qt global shared context:" << qt_gl_global_share_context();
+
if (!ctx->shareContext()) {
m_shareContext = new QOpenGLContext;
m_shareContext->setFormat(ctx->format());
@@ -1092,7 +1097,7 @@ void Renderer::lookForDirtyTextures()
}
// Dirty meaning that something has changed on the texture
- // either properties, parameters, generator or a texture image
+ // either properties, parameters, shared texture id, generator or a texture image
if (texture->dirtyFlags() != Texture::NotDirty)
m_dirtyTextures.push_back(handle);
// Note: texture dirty flags are reset when actually updating the
@@ -1178,7 +1183,7 @@ void Renderer::reloadDirtyShaders()
// Executed in a job
void Renderer::sendTextureChangesToFrontend()
{
- const QVector<QPair<TextureProperties, Qt3DCore::QNodeIdVector>> updateTextureProperties = std::move(m_updatedTextureProperties);
+ const QVector<QPair<Texture::TextureUpdateInfo, Qt3DCore::QNodeIdVector>> updateTextureProperties = std::move(m_updatedTextureProperties);
for (const auto &pair : updateTextureProperties) {
// Prepare change notification
@@ -1197,6 +1202,22 @@ void Renderer::sendTextureChangesToFrontend()
}
}
+// Executed in a job
+void Renderer::sendSetFenceHandlesToFrontend()
+{
+ const QVector<QPair<Qt3DCore::QNodeId, GLFence>> updatedSetFence = std::move(m_updatedSetFences);
+ FrameGraphManager *fgManager = m_nodesManager->frameGraphManager();
+ for (const auto &pair : updatedSetFence) {
+ FrameGraphNode *fgNode = fgManager->lookupNode(pair.first);
+ if (fgNode != nullptr) { // Node could have been deleted before we got a chance to notify it
+ Q_ASSERT(fgNode->nodeType() == FrameGraphNode::SetFence);
+ SetFence *setFenceNode = static_cast<SetFence *>(fgNode);
+ setFenceNode->setHandleType(QSetFence::OpenGLFenceId);
+ setFenceNode->setHandle(QVariant::fromValue(pair.second));
+ }
+ }
+}
+
// 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
@@ -1210,6 +1231,25 @@ void Renderer::sendTextureChangesToFrontend()
void Renderer::updateGLResources()
{
{
+ // Update active fence objects:
+ // - Destroy fences that have reached their signaled state
+ GLFenceManager *fenceManager = m_nodesManager->glFenceManager();
+ const auto end = fenceManager->end();
+ auto it = fenceManager->begin();
+ while (it != end) {
+ const GLFence fence = it.value();
+ if (m_submissionContext->wasSyncSignaled(fence)) {
+ // Fence was signaled, we delete it
+ // before removing the entry from the manager
+ m_submissionContext->deleteSync(fence);
+ it = fenceManager->erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+
+ {
Profiling::GLTimeRecorder recorder(Profiling::BufferUpload);
const QVector<HBuffer> dirtyBufferHandles = std::move(m_dirtyBuffers);
for (const HBuffer &handle: dirtyBufferHandles) {
@@ -1275,8 +1315,13 @@ void Renderer::updateGLResources()
// Gather these information and store them to be distributed by a change next frame
const QNodeIdVector referenceTextureIds = glTextureManager->referencedTextureIds(glTexture);
// Store properties and referenceTextureIds
- if (info.wasUpdated)
- m_updatedTextureProperties.push_back({info.properties, referenceTextureIds});
+ if (info.wasUpdated) {
+ Texture::TextureUpdateInfo updateInfo;
+ updateInfo.properties = info.properties;
+ updateInfo.handleType = QAbstractTexture::OpenGLTextureId;
+ updateInfo.handle = info.texture ? QVariant(info.texture->textureId()) : QVariant();
+ m_updatedTextureProperties.push_back({updateInfo, referenceTextureIds});
+ }
}
}
}
@@ -1298,18 +1343,21 @@ void Renderer::updateTexture(Texture *texture)
return;
// For implementing unique, non-shared, non-cached textures.
- // for now, every texture is shared by default
+ // 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;
- bool isUnique = false;
-
- // TO DO: Update the vector once per frame (or in a job)
- const QVector<HAttachment> activeRenderTargetOutputs = m_nodesManager->attachmentManager()->activeHandles();
- // A texture is unique if it's being reference by a render target output
- for (const HAttachment &attachmentHandle : activeRenderTargetOutputs) {
- RenderTargetOutput *attachment = m_nodesManager->attachmentManager()->data(attachmentHandle);
- if (attachment->textureUuid() == texture->peerId()) {
- isUnique = true;
- break;
+ 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;
+ }
}
}
@@ -1356,6 +1404,9 @@ void Renderer::updateTexture(Texture *texture)
// we hold a reference to a unique or exclusive access to a shared texture
// we can thus modify the texture directly.
const Texture::DirtyFlags dirtyFlags = texture->dirtyFlags();
+ if (dirtyFlags.testFlag(Texture::DirtySharedTextureId) &&
+ !glTextureManager->setSharedTextureId(glTexture, texture->sharedTextureId()))
+ qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setSharedTextureId failed, should be non-shared";
if (dirtyFlags.testFlag(Texture::DirtyProperties) &&
!glTextureManager->setProperties(glTexture, texture->properties()))
@@ -1389,6 +1440,7 @@ void Renderer::cleanupTexture(Qt3DCore::QNodeId cleanedUpTextureId)
glTextureManager->abandon(glTexture, cleanedUpTextureId);
}
+// Called by SubmitRenderView
void Renderer::downloadGLBuffers()
{
lookForDownloadableBuffers();
@@ -1473,6 +1525,45 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
if (renderView->memoryBarrier() != QMemoryBarrier::None)
m_submissionContext->memoryBarrier(renderView->memoryBarrier());
+
+ // Insert Fence into command stream if needed
+ const Qt3DCore::QNodeIdVector insertFenceIds = renderView->insertFenceIds();
+ GLFenceManager *fenceManager = m_nodesManager->glFenceManager();
+ for (const Qt3DCore::QNodeId insertFenceId : insertFenceIds) {
+ // If the fence is not in the manager, then it hasn't been inserted
+ // into the command stream yet.
+ if (fenceManager->find(insertFenceId) == fenceManager->end()) {
+ // Insert fence into command stream
+ GLFence glFence = m_submissionContext->fenceSync();
+ // Record glFence
+ fenceManager->insert(insertFenceId, glFence);
+ // Add entry for notification changes to be sent
+ m_updatedSetFences.push_back({insertFenceId, glFence});
+ }
+ // If it is in the manager, then it hasn't been signaled yet,
+ // nothing we can do but try at the next frame
+ }
+
+ // Wait for fences if needed
+ const QVector<QWaitFenceData> waitFences = renderView->waitFences();
+ for (const QWaitFenceData &waitFence : waitFences) {
+ // TO DO
+ if (waitFence.handleType != QWaitFence::OpenGLFenceId) {
+ qWarning() << "WaitFence handleType should be OpenGLFenceId when using the Qt 3D OpenGL renderer";
+ continue;
+ }
+ GLFence fence = reinterpret_cast<GLFence>(waitFence.handle.value<qintptr>());
+ if (fence == nullptr)
+ continue;
+
+ if (waitFence.waitOnCPU) {
+ m_submissionContext->clientWaitSync(fence,
+ waitFence.timeout);
+ } else {
+ m_submissionContext->waitSync(fence);
+ }
+ }
+
// Note: the RenderStateSet is allocated once per RV if needed
// and it contains a list of StateVariant value types
RenderStateSet *renderViewStateSet = renderView->stateSet();
@@ -1638,6 +1729,33 @@ void Renderer::skipNextFrame()
m_submitRenderViewsSemaphore.release(1);
}
+// Jobs we may have to run even if no rendering will happen
+QVector<QAspectJobPtr> Renderer::preRenderingJobs()
+{
+ QVector<QAspectJobPtr> jobs;
+
+ // Do we need to notify any texture about property changes?
+ if (m_updatedTextureProperties.size() > 0)
+ jobs.push_back(m_sendTextureChangesToFrontendJob);
+
+ // Do we need to notify frontend about fence change?
+ if (m_updatedSetFences.size() > 0)
+ jobs.push_back(m_sendSetFenceHandlesToFrontendJob);
+
+ const QVector<Qt3DCore::QNodeId> pendingCaptureIds = takePendingRenderCaptureSendRequests();
+ if (pendingCaptureIds.size() > 0) {
+ m_sendRenderCaptureJob->setPendingCaptureRequests(pendingCaptureIds);
+ jobs.push_back(m_sendRenderCaptureJob);
+ }
+ if (m_sendBufferCaptureJob->hasRequests())
+ jobs.push_back(m_sendBufferCaptureJob);
+
+ jobs.append(pickBoundingVolumeJob());
+ jobs.append(rayCastingJob());
+
+ return jobs;
+}
+
// Waits to be told to create jobs for the next frame
// Called by QRenderAspect jobsToExecute context of QAspectThread
// Returns all the jobs (and with proper dependency chain) required
@@ -1695,17 +1813,6 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.push_back(m_updateLevelOfDetailJob);
renderBinJobs.push_back(m_cleanupJob);
- const QVector<Qt3DCore::QNodeId> pendingCaptureIds = takePendingRenderCaptureSendRequests();
- if (pendingCaptureIds.size() > 0) {
- m_sendRenderCaptureJob->setPendingCaptureRequests(pendingCaptureIds);
- renderBinJobs.push_back(m_sendRenderCaptureJob);
- }
-
- // Do we need to notify any texture about property changes?
- if (m_updatedTextureProperties.size() > 0)
- renderBinJobs.push_back(m_sendTextureChangesToFrontendJob);
-
- renderBinJobs.push_back(m_sendBufferCaptureJob);
renderBinJobs.append(bufferJobs);
// Jobs to prepare GL Resource upload
diff --git a/src/render/renderers/opengl/renderer/renderer_p.h b/src/render/renderers/opengl/renderer/renderer_p.h
index 23708e3e8..93d6fdbfa 100644
--- a/src/render/renderers/opengl/renderer/renderer_p.h
+++ b/src/render/renderers/opengl/renderer/renderer_p.h
@@ -80,6 +80,7 @@
#include <Qt3DRender/private/updateentitylayersjob_p.h>
#include <Qt3DRender/private/renderercache_p.h>
#include <Qt3DRender/private/texture_p.h>
+#include <Qt3DRender/private/glfence_p.h>
#include <QHash>
#include <QMatrix4x4>
@@ -96,6 +97,10 @@
#include <functional>
+#if defined(QT_BUILD_INTERNAL)
+class tst_Renderer;
+#endif
+
QT_BEGIN_NAMESPACE
class QSurface;
@@ -195,6 +200,7 @@ public:
bool shouldRender() override;
void skipNextFrame() override;
+ QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() override;
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() override;
Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() override;
Qt3DCore::QAspectJobPtr rayCastingJob() override;
@@ -373,6 +379,7 @@ private:
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;
@@ -383,6 +390,7 @@ private:
void lookForDirtyTextures();
void reloadDirtyShaders();
void sendTextureChangesToFrontend();
+ void sendSetFenceHandlesToFrontend();
QMutex m_abandonedVaosMutex;
QVector<HVao> m_abandonedVaos;
@@ -391,7 +399,8 @@ private:
QVector<HBuffer> m_downloadableBuffers;
QVector<HShader> m_dirtyShaders;
QVector<HTexture> m_dirtyTextures;
- QVector<QPair<TextureProperties, Qt3DCore::QNodeIdVector>> m_updatedTextureProperties;
+ QVector<QPair<Texture::TextureUpdateInfo, Qt3DCore::QNodeIdVector>> m_updatedTextureProperties;
+ QVector<QPair<Qt3DCore::QNodeId, GLFence>> m_updatedSetFences;
bool m_ownedContext;
@@ -403,6 +412,10 @@ private:
friend class Qt3DRender::Debug::CommandExecuter;
#endif
+#ifdef QT_BUILD_INTERNAL
+ friend class ::tst_Renderer;
+#endif
+
QMetaObject::Connection m_contextConnection;
RendererCache m_cache;
};
diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp
index 8e0c16938..3aa45c836 100644
--- a/src/render/renderers/opengl/renderer/renderview.cpp
+++ b/src/render/renderers/opengl/renderer/renderview.cpp
@@ -714,6 +714,11 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
if ((computeJob = entity->renderComponent<ComputeCommand>()) != nullptr
&& computeJob->isEnabled()) {
+ // Note: if frameCount has reached 0 in the previous frame, isEnabled
+ // would be false
+ if (computeJob->runType() == QComputeCommand::Manual)
+ computeJob->updateFrameCount();
+
const Qt3DCore::QNodeId materialComponentId = entity->componentUuid<Material>();
const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId);
diff --git a/src/render/renderers/opengl/renderer/renderview_p.h b/src/render/renderers/opengl/renderer/renderview_p.h
index cb3c74917..7ebcdb6bd 100644
--- a/src/render/renderers/opengl/renderer/renderview_p.h
+++ b/src/render/renderers/opengl/renderer/renderview_p.h
@@ -65,6 +65,7 @@
#include <Qt3DRender/private/qmemorybarrier_p.h>
#include <Qt3DRender/private/qrendercapture_p.h>
#include <Qt3DRender/private/qblitframebuffer_p.h>
+#include <Qt3DRender/private/qwaitfence_p.h>
#include <Qt3DCore/private/qframeallocator_p.h>
#include <Qt3DRender/private/aligned_malloc_p.h>
@@ -174,6 +175,13 @@ public:
inline void appendProximityFilterId(const Qt3DCore::QNodeId proximityFilterId) { m_data.m_proximityFilterIds.push_back(proximityFilterId); }
inline Qt3DCore::QNodeIdVector proximityFilterIds() const { return m_data.m_proximityFilterIds; }
+ inline void appendInsertFenceId(const Qt3DCore::QNodeId setFenceId) { m_insertFenceIds.push_back(setFenceId); }
+ // We prefix with get to avoid confusion when it is called
+ inline Qt3DCore::QNodeIdVector insertFenceIds() const { return m_insertFenceIds; }
+
+ inline void appendWaitFence(const QWaitFenceData &data) { m_waitFences.push_back(data); }
+ inline QVector<QWaitFenceData> waitFences() const { return m_waitFences; }
+
inline void setRenderPassFilter(const RenderPassFilter *rpFilter) Q_DECL_NOTHROW { m_data.m_passFilter = rpFilter; }
inline const RenderPassFilter *renderPassFilter() const Q_DECL_NOTHROW { return m_data.m_passFilter; }
@@ -320,6 +328,8 @@ private:
bool m_frustumCulling:1;
int m_workGroups[3];
QMemoryBarrier::Operations m_memoryBarrier;
+ QVector<Qt3DCore::QNodeId> m_insertFenceIds;
+ QVector<QWaitFenceData> m_waitFences;
// We do not use pointers to RenderNodes or Drawable's here so that the
// render aspect is free to change the drawables on the next frame whilst
diff --git a/src/render/renderers/opengl/textures/gltexture.cpp b/src/render/renderers/opengl/textures/gltexture.cpp
index ce212de03..47a97c688 100644
--- a/src/render/renderers/opengl/textures/gltexture.cpp
+++ b/src/render/renderers/opengl/textures/gltexture.cpp
@@ -57,6 +57,11 @@
#include <Qt3DCore/qpropertynodeaddedchange.h>
#include <Qt3DCore/qpropertynoderemovedchange.h>
+#if !defined(QT_OPENGL_ES_2)
+#include <QOpenGLFunctions_3_1>
+#include <QOpenGLFunctions_4_5_Core>
+#endif
+
QT_BEGIN_NAMESPACE
using namespace Qt3DCore;
@@ -74,6 +79,7 @@ GLTexture::GLTexture(TextureDataManager *texDataMgr,
, m_textureDataManager(texDataMgr)
, m_textureImageDataManager(texImgDataMgr)
, m_dataFunctor(texGen)
+ , m_sharedTextureId(-1)
, m_pendingDataFunctor(nullptr)
, m_externalRendering(false)
{
@@ -181,39 +187,44 @@ GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture()
m_properties.status = QAbstractTexture::Error;
- // 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) {
- const bool successfullyLoadedTextureData = loadTextureDataFromGenerator();
- if (successfullyLoadedTextureData) {
- setDirtyFlag(Properties, true);
- needUpload = 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";
- m_pendingDataFunctor = m_dataFunctor.get();
+ const bool hasSharedTextureId = m_sharedTextureId > 0;
+
+ // Only load texture data if we are not using a sharedTextureId
+ 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) {
+ const bool successfullyLoadedTextureData = loadTextureDataFromGenerator();
+ if (successfullyLoadedTextureData) {
+ setDirtyFlag(Properties, true);
+ needUpload = 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";
+ m_pendingDataFunctor = m_dataFunctor.get();
+ }
+ textureInfo.properties.status = QAbstractTexture::Loading;
+ return textureInfo;
}
- textureInfo.properties.status = QAbstractTexture::Loading;
- return textureInfo;
}
- }
- // additional texture images may be defined through image data generators
- if (testDirtyFlag(TextureData)) {
- m_imageData.clear();
- loadTextureDataFromImages();
- needUpload = true;
- }
+ // additional texture images may be defined through image data generators
+ if (testDirtyFlag(TextureData)) {
+ m_imageData.clear();
+ loadTextureDataFromImages();
+ needUpload = true;
+ }
- // 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 format was not set
+ if (m_properties.format == QAbstractTexture::Automatic) {
+ textureInfo.properties.status = QAbstractTexture::Error;
+ return textureInfo;
+ }
}
// if the properties changed, we need to re-allocate the texture
- if (testDirtyFlag(Properties)) {
+ if (testDirtyFlag(Properties) || testDirtyFlag(SharedTextureId)) {
delete m_gl;
m_gl = nullptr;
textureInfo.wasUpdated = true;
@@ -223,40 +234,48 @@ GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture()
needUpload = true;
}
+ m_properties.status = QAbstractTexture::Ready;
- if (!m_gl) {
- m_gl = buildGLTexture();
+ if (hasSharedTextureId && testDirtyFlag(SharedTextureId)) {
+ // Update m_properties by doing introspection on the texture
+ introspectPropertiesFromSharedTextureId();
+ } else {
+ // We only build a QOpenGLTexture if we have no shared textureId set
if (!m_gl) {
- textureInfo.properties.status = QAbstractTexture::Error;
- return textureInfo;
- }
+ m_gl = buildGLTexture();
+ if (!m_gl) {
+ textureInfo.properties.status = QAbstractTexture::Error;
+ return textureInfo;
+ }
- m_gl->allocateStorage();
- if (!m_gl->isStorageAllocated()) {
- textureInfo.properties.status = QAbstractTexture::Error;
- return textureInfo;
+ m_gl->allocateStorage();
+ if (!m_gl->isStorageAllocated()) {
+ textureInfo.properties.status = QAbstractTexture::Error;
+ return textureInfo;
+ }
}
- }
- m_properties.status = QAbstractTexture::Ready;
- textureInfo.properties = m_properties;
- textureInfo.texture = m_gl;
+ textureInfo.texture = m_gl;
- // need to (re-)upload texture data?
- if (needUpload) {
- uploadGLTextureData();
- setDirtyFlag(TextureData, false);
- }
+ // need to (re-)upload texture data?
+ if (needUpload) {
+ uploadGLTextureData();
+ setDirtyFlag(TextureData, false);
+ }
- // need to set texture parameters?
- if (testDirtyFlag(Properties) || testDirtyFlag(Parameters)) {
- updateGLTextureParameters();
+ // need to set texture parameters?
+ if (testDirtyFlag(Properties) || testDirtyFlag(Parameters)) {
+ updateGLTextureParameters();
+ }
}
+ 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;
}
@@ -355,6 +374,14 @@ void GLTexture::setGenerator(const QTextureGeneratorPtr &generator)
}
}
+void GLTexture::setSharedTextureId(int textureId)
+{
+ if (m_sharedTextureId != textureId) {
+ m_sharedTextureId = textureId;
+ setDirtyFlag(SharedTextureId);
+ }
+}
+
// Return nullptr if
// - context cannot be obtained
// - texture hasn't yet been loaded
@@ -403,8 +430,8 @@ QOpenGLTexture *GLTexture::buildGLTexture()
// is written against GLES 1.0.
if (m_properties.format == QAbstractTexture::RGB8_ETC1) {
if ((ctx->isOpenGLES() && ctx->format().majorVersion() >= 3)
- || ctx->hasExtension(QByteArrayLiteral("GL_OES_compressed_ETC2_RGB8_texture"))
- || ctx->hasExtension(QByteArrayLiteral("GL_ARB_ES3_compatibility")))
+ || ctx->hasExtension(QByteArrayLiteral("GL_OES_compressed_ETC2_RGB8_texture"))
+ || ctx->hasExtension(QByteArrayLiteral("GL_ARB_ES3_compatibility")))
format = m_properties.format = QAbstractTexture::RGB8_ETC2;
}
@@ -414,14 +441,14 @@ QOpenGLTexture *GLTexture::buildGLTexture()
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) {
+ m_actualTarget == QAbstractTexture::Target2DArray ||
+ m_actualTarget == QAbstractTexture::Target2DMultisampleArray ||
+ m_actualTarget == QAbstractTexture::TargetCubeMapArray) {
glTex->setLayers(m_properties.layers);
}
if (m_actualTarget == QAbstractTexture::Target2DMultisample ||
- m_actualTarget == QAbstractTexture::Target2DMultisampleArray) {
+ m_actualTarget == QAbstractTexture::Target2DMultisampleArray) {
// Set samples count if multisampled texture
// (multisampled textures don't have mipmaps)
glTex->setSamples(m_properties.samples);
@@ -497,8 +524,8 @@ void GLTexture::updateGLTextureParameters()
{
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)
+ m_actualTarget != QAbstractTexture::Target1DArray &&
+ m_actualTarget != QAbstractTexture::TargetBuffer)
m_gl->setWrapMode(QOpenGLTexture::DirectionT, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeY));
if (m_actualTarget == QAbstractTexture::Target3D)
m_gl->setWrapMode(QOpenGLTexture::DirectionR, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeZ));
@@ -512,6 +539,129 @@ void GLTexture::updateGLTextureParameters()
}
}
+void GLTexture::introspectPropertiesFromSharedTextureId()
+{
+ // We know that the context is active when this function is called
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (!ctx) {
+ qWarning() << Q_FUNC_INFO << "requires an OpenGL context";
+ return;
+ }
+ QOpenGLFunctions *gl = ctx->functions();
+
+ // If the user has set the target format himself, we won't try to deduce it
+ if (m_properties.target != QAbstractTexture::TargetAutomatic)
+ return;
+
+ const QAbstractTexture::Target targets[] = {
+ QAbstractTexture::Target2D,
+ QAbstractTexture::TargetCubeMap,
+#ifndef QT_OPENGL_ES_2
+ QAbstractTexture::Target1D,
+ QAbstractTexture::Target1DArray,
+ QAbstractTexture::Target3D,
+ QAbstractTexture::Target2DArray,
+ QAbstractTexture::TargetCubeMapArray,
+ QAbstractTexture::Target2DMultisample,
+ QAbstractTexture::Target2DMultisampleArray,
+ QAbstractTexture::TargetRectangle,
+ QAbstractTexture::TargetBuffer,
+#endif
+ };
+
+#ifndef QT_OPENGL_ES_2
+ // Try to find texture target with GL 4.5 functions
+ 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
+ if (gl5 != nullptr)
+ gl5->glGetTextureParameteriv(m_sharedTextureId, GL_TEXTURE_TARGET, reinterpret_cast<int *>(&m_properties.target));
+#endif
+ }
+#endif
+
+ // If GL 4.5 function unavailable or not working, try a slower way
+ if (m_properties.target == QAbstractTexture::TargetAutomatic) {
+ // // OpenGL offers no proper way of querying for the target of a texture given its id
+ gl->glActiveTexture(GL_TEXTURE0);
+
+ const GLenum targetBindings[] = {
+ GL_TEXTURE_BINDING_2D,
+ GL_TEXTURE_BINDING_CUBE_MAP,
+#ifndef QT_OPENGL_ES_2
+ GL_TEXTURE_BINDING_1D,
+ GL_TEXTURE_BINDING_1D_ARRAY,
+ GL_TEXTURE_BINDING_3D,
+ GL_TEXTURE_BINDING_2D_ARRAY,
+ GL_TEXTURE_BINDING_CUBE_MAP_ARRAY,
+ GL_TEXTURE_BINDING_2D_MULTISAMPLE,
+ GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY,
+ GL_TEXTURE_BINDING_RECTANGLE,
+ GL_TEXTURE_BINDING_BUFFER
+#endif
+ };
+
+ Q_ASSERT(sizeof(targetBindings) / sizeof(targetBindings[0] == sizeof(targets) / sizeof(targets[0])));
+
+ for (uint i = 0; i < sizeof(targetBindings) / sizeof(targetBindings[0]); ++i) {
+ const int target = targets[i];
+ gl->glBindTexture(target, m_sharedTextureId);
+ int boundId = 0;
+ gl->glGetIntegerv(targetBindings[i], &boundId);
+ gl->glBindTexture(target, 0);
+ if (boundId == m_sharedTextureId) {
+ m_properties.target = static_cast<QAbstractTexture::Target>(target);
+ break;
+ }
+ }
+ }
+
+ // Return early if we weren't able to find texture target
+ if (std::find(std::begin(targets), std::end(targets), m_properties.target) == std::end(targets)) {
+ qWarning() << "Unable to determine texture target for shared GL texture";
+ return;
+ }
+
+ // Bind texture once we know its target
+ gl->glBindTexture(m_properties.target, m_sharedTextureId);
+
+ // TO DO: Improve by using glGetTextureParameters when available which
+ // support direct state access
+#ifndef GL_TEXTURE_MAX_LEVEL
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#endif
+
+#ifndef GL_TEXTURE_WRAP_R
+#define GL_TEXTURE_WRAP_R 0x8072
+#endif
+
+ gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_MAX_LEVEL, reinterpret_cast<int *>(&m_properties.mipLevels));
+ gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_MIN_FILTER, reinterpret_cast<int *>(&m_parameters.minificationFilter));
+ gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_MAG_FILTER, reinterpret_cast<int *>(&m_parameters.magnificationFilter));
+ gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_WRAP_R, reinterpret_cast<int *>(&m_parameters.wrapModeX));
+ gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_WRAP_S, reinterpret_cast<int *>(&m_parameters.wrapModeY));
+ gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_WRAP_T, reinterpret_cast<int *>(&m_parameters.wrapModeZ));
+
+#ifndef QT_OPENGL_ES_2
+ // Try to retrieve dimensions (not available on ES 2.0)
+ if (!ctx->isOpenGLES()) {
+ QOpenGLFunctions_3_1 *gl3 = ctx->versionFunctions<QOpenGLFunctions_3_1>();
+ if (!gl3) {
+ qWarning() << "Failed to retrieve shared texture dimensions";
+ return;
+ }
+
+ gl3->glGetTexLevelParameteriv(int(m_properties.target), 0, GL_TEXTURE_WIDTH, reinterpret_cast<int *>(&m_properties.width));
+ gl3->glGetTexLevelParameteriv(int(m_properties.target), 0, GL_TEXTURE_HEIGHT, reinterpret_cast<int *>(&m_properties.height));
+ gl3->glGetTexLevelParameteriv(int(m_properties.target), 0, GL_TEXTURE_DEPTH, reinterpret_cast<int *>(&m_properties.depth));
+ gl3->glGetTexLevelParameteriv(int(m_properties.target), 0, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<int *>(&m_properties.format));
+ }
+#endif
+
+ gl->glBindTexture(m_properties.target, 0);
+}
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/renderers/opengl/textures/gltexture_p.h b/src/render/renderers/opengl/textures/gltexture_p.h
index ca9c0d5db..66f66926c 100644
--- a/src/render/renderers/opengl/textures/gltexture_p.h
+++ b/src/render/renderers/opengl/textures/gltexture_p.h
@@ -125,6 +125,7 @@ public:
inline TextureProperties properties() const { return m_properties; }
inline TextureParameters parameters() const { return m_parameters; }
inline QTextureGeneratorPtr textureGenerator() const { return m_dataFunctor; }
+ inline int sharedTextureId() const { return m_sharedTextureId; }
inline QVector<Image> images() const { return m_images; }
inline QSize size() const { return QSize(m_properties.width, m_properties.height); }
@@ -204,14 +205,15 @@ protected:
void setProperties(const TextureProperties &props);
void setImages(const QVector<Image> &images);
void setGenerator(const QTextureGeneratorPtr &generator);
+ void setSharedTextureId(int textureId);
private:
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
-
+ Parameters = 0x04, // texture parameters need to be (re-)set
+ SharedTextureId = 0x08 // texture id from shared context
};
bool testDirtyFlag(DirtyFlag flag)
@@ -232,6 +234,7 @@ private:
void loadTextureDataFromImages();
void uploadGLTextureData();
void updateGLTextureParameters();
+ void introspectPropertiesFromSharedTextureId();
void destroyResources();
bool m_unique;
@@ -257,6 +260,7 @@ private:
QTextureDataPtr m_textureData;
QVector<QTextureImageDataPtr> m_imageData;
+ int m_sharedTextureId;
bool m_externalRendering;
};
diff --git a/src/render/texture/apitexturemanager_p.h b/src/render/texture/apitexturemanager_p.h
index 58e6e6420..79dc9af94 100644
--- a/src/render/texture/apitexturemanager_p.h
+++ b/src/render/texture/apitexturemanager_p.h
@@ -257,6 +257,19 @@ public:
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()
@@ -344,6 +357,7 @@ private:
newTex->setProperties(node->properties());
newTex->setParameters(node->parameters());
newTex->setImages(texImgs);
+ newTex->setSharedTextureId(node->sharedTextureId());
m_updatedTextures.push_back(newTex);
diff --git a/src/render/texture/qabstracttexture.cpp b/src/render/texture/qabstracttexture.cpp
index 03746620e..17c4a8f11 100644
--- a/src/render/texture/qabstracttexture.cpp
+++ b/src/render/texture/qabstracttexture.cpp
@@ -66,6 +66,9 @@ QAbstractTexturePrivate::QAbstractTexturePrivate()
, m_comparisonMode(QAbstractTexture::CompareNone)
, m_layers(1)
, m_samples(1)
+ , m_sharedTextureId(-1)
+ , m_handleType(QAbstractTexture::NoHandle)
+ , m_handle(QVariant())
{
}
@@ -561,6 +564,34 @@ void QAbstractTexture::setStatus(Status status)
}
/*!
+ * \internal
+ */
+void QAbstractTexture::setHandle(const QVariant &handle)
+{
+ Q_D(QAbstractTexture);
+ if (d->m_handle != handle) {
+ d->m_handle = handle;
+ const bool blocked = blockNotifications(true);
+ emit handleChanged(handle);
+ blockNotifications(blocked);
+ }
+}
+
+/*!
+ * \internal
+ */
+void QAbstractTexture::setHandleType(QAbstractTexture::HandleType type)
+{
+ Q_D(QAbstractTexture);
+ if (d->m_handleType != type) {
+ d->m_handleType = type;
+ const bool blocked = blockNotifications(true);
+ emit handleTypeChanged(type);
+ blockNotifications(blocked);
+ }
+}
+
+/*!
* \return the current status of the texture provider.
*/
QAbstractTexture::Status QAbstractTexture::status() const
@@ -886,6 +917,55 @@ QTextureGeneratorPtr QAbstractTexture::dataGenerator() const
return d->m_dataFunctor;
}
+/*!
+ * \property Qt3DRender::QAbstractTexture::handleType
+ *
+ * Holds the current texture handle type.
+ */
+
+/*!
+ * \qmlproperty handleType
+ *
+ * Holds the current texture handle type.
+ */
+
+/*!
+ * \return the current texture handle type.
+ * \since 5.12
+ */
+QAbstractTexture::HandleType QAbstractTexture::handleType() const
+{
+ Q_D(const QAbstractTexture);
+ return d->m_handleType;
+}
+
+
+/*!
+ * \property Qt3DRender::QAbstractTexture::handle
+ *
+ * Holds the current texture handle, if Qt 3D is using the OpenGL renderer,
+ * handle is a texture id integer.
+ */
+
+/*!
+ * \qmlproperty handle
+ *
+ * Holds the current texture handle, if Qt 3D is using the OpenGL renderer,
+ * handle is a texture id integer.
+ */
+
+/*!
+ * \return the current texture handle, if Qt 3D is using the OpenGL renderer,
+ * handle is a texture id integer.
+ *
+ * \since 5.12
+ */
+QVariant QAbstractTexture::handle() const
+{
+ Q_D(const QAbstractTexture);
+ return d->m_handle;
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QAbstractTexture::createNodeCreationChange() const
{
auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QAbstractTextureData>::create(this);
@@ -909,6 +989,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QAbstractTexture::createNodeCreationChange()
data.layers = d->m_layers;
data.samples = d->m_samples;
data.dataFunctor = d->m_dataFunctor;
+ data.sharedTextureId = d->m_sharedTextureId;
return creationChange;
}
@@ -941,6 +1022,10 @@ void QAbstractTexture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
bool blocked = blockNotifications(true);
setStatus(static_cast<QAbstractTexture::Status>(propertyChange->value().toInt()));
blockNotifications(blocked);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("handleType")) {
+ setHandleType(static_cast<QAbstractTexture::HandleType>(propertyChange->value().toInt()));
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("handle")) {
+ setHandle(propertyChange->value());
}
// TODO handle target changes, it's a CONSTANT property but can be affected by loader
break;
diff --git a/src/render/texture/qabstracttexture.h b/src/render/texture/qabstracttexture.h
index f17633710..e6833ffb4 100644
--- a/src/render/texture/qabstracttexture.h
+++ b/src/render/texture/qabstracttexture.h
@@ -73,6 +73,8 @@ class QT3DRENDERSHARED_EXPORT QAbstractTexture : public Qt3DCore::QNode
Q_PROPERTY(ComparisonMode comparisonMode READ comparisonMode WRITE setComparisonMode NOTIFY comparisonModeChanged)
Q_PROPERTY(int layers READ layers WRITE setLayers NOTIFY layersChanged)
Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged)
+ Q_PROPERTY(HandleType handleType READ handleType NOTIFY handleTypeChanged REVISION 13)
+ Q_PROPERTY(QVariant handle READ handle NOTIFY handleChanged REVISION 13)
public:
@@ -268,6 +270,12 @@ public:
};
Q_ENUM(ComparisonMode) // LCOV_EXCL_LINE
+ enum HandleType {
+ NoHandle,
+ OpenGLTextureId
+ };
+ Q_ENUM(HandleType) // LCOV_EXCL_LINE
+
~QAbstractTexture();
Target target() const;
@@ -298,6 +306,8 @@ public:
int layers() const;
int samples() const;
QTextureGeneratorPtr dataGenerator() const;
+ HandleType handleType() const;
+ QVariant handle() const;
public Q_SLOTS:
void setFormat(TextureFormat format);
@@ -327,6 +337,8 @@ Q_SIGNALS:
void comparisonModeChanged(ComparisonMode comparisonMode);
void layersChanged(int layers);
void samplesChanged(int samples);
+ void handleTypeChanged(HandleType handleType);
+ void handleChanged(QVariant handle);
protected:
explicit QAbstractTexture(Qt3DCore::QNode *parent = nullptr);
@@ -335,6 +347,8 @@ protected:
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
void setStatus(Status status);
+ void setHandle(const QVariant &handle);
+ void setHandleType(HandleType type);
private:
Q_DECLARE_PRIVATE(QAbstractTexture)
diff --git a/src/render/texture/qabstracttexture_p.h b/src/render/texture/qabstracttexture_p.h
index a27ae3729..0ad1d0737 100644
--- a/src/render/texture/qabstracttexture_p.h
+++ b/src/render/texture/qabstracttexture_p.h
@@ -87,6 +87,11 @@ public :
int m_layers;
int m_samples;
+ int m_sharedTextureId;
+
+ QAbstractTexture::HandleType m_handleType;
+ QVariant m_handle;
+
QTextureGeneratorPtr dataFunctor() const;
void setDataFunctor(const QTextureGeneratorPtr &generator);
@@ -113,6 +118,7 @@ struct QAbstractTextureData
Qt3DCore::QNodeIdVector textureImageIds;
int layers;
int samples;
+ int sharedTextureId;
QTextureGeneratorPtr dataFunctor;
};
diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp
index 029e47817..cf93f872f 100644
--- a/src/render/texture/qtexture.cpp
+++ b/src/render/texture/qtexture.cpp
@@ -1475,6 +1475,69 @@ bool QTextureFromSourceGenerator::isMirrored() const
return m_mirrored;
}
+/*!
+ * \class QSharedGLTexture
+ * \brief Allows to use a textureId from a separate OpenGL context in a Qt 3D scene.
+ *
+ * Depending on the rendering mode used by Qt 3D, the shared context will either be:
+ * \list
+ * \li qt_gl_global_share_context when letting Qt 3D drive the rendering. When
+ * setting the attribute Qt::AA_ShareOpenGLContexts on the QApplication class,
+ * this will automatically make QOpenGLWidget instances have their context shared
+ * with qt_gl_global_share_context.
+ * \li the shared context from the QtQuick scene. You might have to subclass
+ * QWindow or use QtQuickRenderControl to have control over what that shared
+ * context is though as of 5.13 it is qt_gl_global_share_context.
+ * \endlist
+ *
+ * \since 5.13
+ *
+ * Any 3rd party engine that shares its context with the Qt 3D renderer can now
+ * provide texture ids that will be referenced by the Qt 3D texture.
+ *
+ * You can omit specifying the texture properties, Qt 3D will try at runtime to
+ * determine what they are. If you know them, you can of course provide them,
+ * avoid additional work for Qt 3D.
+ *
+ * Keep in mind that if you are using custom materials and shaders, you need to
+ * specify the correct sampler type to be used.
+ */
+
+QSharedGLTexture::QSharedGLTexture(Qt3DCore::QNode *parent)
+ : QAbstractTexture(parent)
+{
+ QAbstractTexturePrivate *d = static_cast<QAbstractTexturePrivate *>(Qt3DCore::QNodePrivate::get(this));
+ d->m_target = TargetAutomatic;
+}
+
+QSharedGLTexture::~QSharedGLTexture()
+{
+}
+
+/*!
+ * \qmlproperty textureId
+ *
+ * The OpenGL texture id value that you want Qt3D to gain access to.
+ */
+/*!
+ *\property Qt3DRender::QSharedGLTexture::textureId
+ *
+ * The OpenGL texture id value that you want Qt3D to gain access to.
+ */
+int QSharedGLTexture::textureId() const
+{
+ return static_cast<QAbstractTexturePrivate *>(d_ptr.get())->m_sharedTextureId;
+}
+
+void QSharedGLTexture::setTextureId(int id)
+{
+ QAbstractTexturePrivate *d = static_cast<QAbstractTexturePrivate *>(Qt3DCore::QNodePrivate::get(this));
+ if (d->m_sharedTextureId != id) {
+ d->m_sharedTextureId = id;
+ emit textureIdChanged(id);
+ }
+}
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/texture/qtexture.h b/src/render/texture/qtexture.h
index 24d19fbcf..991725de2 100644
--- a/src/render/texture/qtexture.h
+++ b/src/render/texture/qtexture.h
@@ -169,6 +169,23 @@ private:
Q_DECLARE_PRIVATE(QTextureLoader)
};
+class QT3DRENDERSHARED_EXPORT QSharedGLTexture : public QAbstractTexture
+{
+ Q_OBJECT
+ Q_PROPERTY(int textureId READ textureId WRITE setTextureId NOTIFY textureIdChanged)
+public:
+ explicit QSharedGLTexture(Qt3DCore::QNode *parent = nullptr);
+ ~QSharedGLTexture();
+
+ int textureId() const;
+
+public Q_SLOTS:
+ void setTextureId(int id);
+
+Q_SIGNALS:
+ void textureIdChanged(int textureId);
+};
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp
index 749b85802..17fd47be3 100644
--- a/src/render/texture/texture.cpp
+++ b/src/render/texture/texture.cpp
@@ -115,6 +115,7 @@ void Texture::cleanup()
// texture is being referenced by a shared API specific texture (GLTexture)
m_dataFunctor.reset();
m_textureImageIds.clear();
+ m_sharedTextureId = -1;
// set default values
m_properties = {};
@@ -181,6 +182,9 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
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;
@@ -219,7 +223,7 @@ void Texture::setDataGenerator(const QTextureGeneratorPtr &generator)
// Called by sendTextureChangesToFrontendJob once GLTexture and sharing
// has been performed
-void Texture::updatePropertiesAndNotify(const TextureProperties &properties)
+void Texture::updatePropertiesAndNotify(const TextureUpdateInfo &updateInfo)
{
// If we are Dirty, some property has changed and the properties we have
// received are potentially already outdated
@@ -228,57 +232,73 @@ void Texture::updatePropertiesAndNotify(const TextureProperties &properties)
// Note we don't update target has it is constant for frontend nodes
- if (properties.width != m_properties.width) {
- m_properties.width = properties.width;
+ 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(properties.width);
+ change->setValue(updateInfo.properties.width);
notifyObservers(change);
}
- if (properties.height != m_properties.height) {
- m_properties.height = properties.height;
+ 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(properties.height);
+ change->setValue(updateInfo.properties.height);
notifyObservers(change);
}
- if (properties.depth != m_properties.depth) {
- m_properties.depth = properties.depth;
+ 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(properties.depth);
+ change->setValue(updateInfo.properties.depth);
notifyObservers(change);
}
- if (properties.layers != m_properties.layers) {
- m_properties.layers = properties.layers;
+ 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(properties.layers);
+ change->setValue(updateInfo.properties.layers);
notifyObservers(change);
}
- if (properties.format != m_properties.format) {
- m_properties.format = properties.format;
+ 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(properties.format);
+ change->setValue(updateInfo.properties.format);
notifyObservers(change);
}
- if (properties.status != m_properties.status) {
- m_properties.status = properties.status;
+ 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(properties.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);
}
}
@@ -315,11 +335,14 @@ void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan
m_parameters.comparisonFunction = data.comparisonFunction;
m_parameters.comparisonMode = data.comparisonMode;
m_dataFunctor = data.dataFunctor;
+ m_sharedTextureId = data.sharedTextureId;
for (const QNodeId imgId : data.textureImageIds)
addTextureImage(imgId);
addDirtyFlag(DirtyFlags(DirtyImageGenerators|DirtyProperties|DirtyParameters));
+ if (m_sharedTextureId > 0)
+ addDirtyFlag(DirtySharedTextureId);
}
diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h
index 86c49f695..c60e90181 100644
--- a/src/render/texture/texture_p.h
+++ b/src/render/texture/texture_p.h
@@ -137,10 +137,18 @@ public:
DirtyProperties = 0x1,
DirtyParameters = 0x2,
DirtyImageGenerators = 0x4,
- DirtyDataGenerator = 0x8
+ DirtyDataGenerator = 0x8,
+ DirtySharedTextureId = 0x16
};
Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
+ struct TextureUpdateInfo
+ {
+ TextureProperties properties;
+ QVariant handle;
+ QAbstractTexture::HandleType handleType;
+ };
+
void addDirtyFlag(DirtyFlags flags);
DirtyFlags dirtyFlags();
void unsetDirty();
@@ -155,9 +163,10 @@ public:
inline const TextureParameters& parameters() const { return m_parameters; }
inline const Qt3DCore::QNodeIdVector textureImageIds() const { return m_textureImageIds; }
inline const QTextureGeneratorPtr& dataGenerator() const { return m_dataFunctor; }
+ inline int sharedTextureId() const { return m_sharedTextureId; }
void setDataGenerator(const QTextureGeneratorPtr &generator);
- void updatePropertiesAndNotify(const TextureProperties &propreties);
+ void updatePropertiesAndNotify(const TextureUpdateInfo &updateInfo);
bool isValid(TextureImageManager *manager) const;
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
@@ -165,6 +174,7 @@ private:
DirtyFlags m_dirty;
TextureProperties m_properties;
TextureParameters m_parameters;
+ int m_sharedTextureId;
QTextureGeneratorPtr m_dataFunctor;
Qt3DCore::QNodeIdVector m_textureImageIds;