summaryrefslogtreecommitdiffstats
path: root/src/render/backend
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2018-02-15 12:44:27 +0000
committerSean Harmer <sean.harmer@kdab.com>2018-02-15 20:59:03 +0000
commit6e82860f19bb28744c0d7f6ccc88ca89b187e3ce (patch)
tree1c8682d5bf06a0a03cefc3da5e3918056de78a04 /src/render/backend
parent0bbccd492532786adc6816b992b85b4fdf162842 (diff)
parente1d1a59eb04f8b17582571275073a6cfa10e9e32 (diff)
Merge remote-tracking branch 'origin/5.10' into 5.11
Conflicts: src/animation/doc/src/qt3danimation-module.qdoc src/render/backend/abstractrenderer_p.h src/render/backend/buffervisitor_p.h src/render/backend/renderer.cpp src/render/backend/renderer_p.h src/render/backend/triangleboundingvolume_p.h src/render/backend/trianglesextractor_p.h src/render/frontend/sphere_p.h src/render/jobs/calcboundingvolumejob.cpp src/render/jobs/job_common_p.h src/render/jobs/pickboundingvolumejob.cpp src/render/jobs/pickboundingvolumejob_p.h src/render/jobs/pickboundingvolumeutils.cpp src/render/jobs/renderviewjobutils_p.h tests/auto/render/boundingsphere/tst_boundingsphere.cpp tests/auto/render/commons/testrenderer.h tests/auto/render/raycasting/tst_raycasting.cpp tests/auto/render/render.pro tests/auto/render/renderer/tst_renderer.cpp Change-Id: I76633bc5a5a065e5f9ea62cc16563377e5c693a3
Diffstat (limited to 'src/render/backend')
-rw-r--r--src/render/backend/abstractrenderer_p.h10
-rw-r--r--src/render/backend/buffervisitor_p.h12
-rw-r--r--src/render/backend/cameralens.cpp22
-rw-r--r--src/render/backend/cameralens_p.h12
-rw-r--r--src/render/backend/entity.cpp4
-rw-r--r--src/render/backend/entity_p.h4
-rw-r--r--src/render/backend/handle_types_p.h5
-rw-r--r--src/render/backend/managers_p.h3
-rw-r--r--src/render/backend/nodemanagers.cpp2
-rw-r--r--src/render/backend/pointsvisitor.cpp4
-rw-r--r--src/render/backend/pointsvisitor_p.h3
-rw-r--r--src/render/backend/render-backend.pri6
-rw-r--r--src/render/backend/renderbarrierjob.cpp111
-rw-r--r--src/render/backend/renderbarrierjob_p.h91
-rw-r--r--src/render/backend/renderer.cpp590
-rw-r--r--src/render/backend/renderer_p.h52
-rw-r--r--src/render/backend/renderqueue.cpp1
-rw-r--r--src/render/backend/renderview.cpp91
-rw-r--r--src/render/backend/renderview_p.h42
-rw-r--r--src/render/backend/renderviewbuilder.cpp25
-rw-r--r--src/render/backend/segmentsvisitor.cpp12
-rw-r--r--src/render/backend/segmentsvisitor_p.h5
-rw-r--r--src/render/backend/shaderparameterpack.cpp6
-rw-r--r--src/render/backend/shaderparameterpack_p.h10
-rw-r--r--src/render/backend/transform.cpp6
-rw-r--r--src/render/backend/transform_p.h6
-rw-r--r--src/render/backend/triangleboundingvolume.cpp54
-rw-r--r--src/render/backend/triangleboundingvolume_p.h37
-rw-r--r--src/render/backend/trianglesextractor.cpp2
-rw-r--r--src/render/backend/trianglesextractor_p.h6
-rw-r--r--src/render/backend/trianglesvisitor.cpp44
-rw-r--r--src/render/backend/trianglesvisitor_p.h10
-rw-r--r--src/render/backend/uniform.cpp34
-rw-r--r--src/render/backend/uniform_p.h37
34 files changed, 851 insertions, 508 deletions
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index 54f37ea21..bf05bdec8 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -134,7 +134,7 @@ public:
// Threaded renderer
virtual void render() = 0;
// Synchronous renderer
- virtual void doRender(bool scene3dBlocking = false) = 0;
+ virtual void doRender() = 0;
virtual void cleanGraphicsResources() = 0;
@@ -151,7 +151,7 @@ public:
virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0;
virtual Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() = 0;
virtual Qt3DCore::QAspectJobPtr rayCastingJob() = 0;
- virtual Qt3DCore::QAspectJobPtr syncTextureLoadingJob() = 0;
+ virtual Qt3DCore::QAspectJobPtr syncSkeletonLoadingJob() = 0;
virtual Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() = 0;
virtual void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Entity *root) = 0;
@@ -170,6 +170,12 @@ public:
virtual void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) = 0;
virtual QSurfaceFormat format() = 0;
virtual QOpenGLContext *shareContext() const = 0;
+
+ virtual void lockSurfaceAndRender() = 0;
+ virtual bool releaseRendererAndRequestPromiseToRender() = 0;
+ virtual bool waitForRenderJobs() = 0;
+ virtual bool tryWaitForRenderJobs(int timeout) = 0;
+ virtual void abortRenderJobs() = 0;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractRenderer::BackendNodeDirtySet)
diff --git a/src/render/backend/buffervisitor_p.h b/src/render/backend/buffervisitor_p.h
index 4870171b1..98749b62c 100644
--- a/src/render/backend/buffervisitor_p.h
+++ b/src/render/backend/buffervisitor_p.h
@@ -195,7 +195,7 @@ protected:
const uint byteStride,
const uint count)
{
- const uint stride = byteStride / sizeof(Coordinate);
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 2;
for (uint ndx = 0; ndx < count; ++ndx) {
visit(ndx, coordinates[0], coordinates[1]);
coordinates += stride;
@@ -211,7 +211,7 @@ protected:
bool primitiveRestartEnabled,
int primitiveRestartIndex)
{
- const uint stride = byteStride / sizeof(Coordinate);
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 2;
for (uint i = 0; i < count; ++i) {
if (!primitiveRestartEnabled || indices[i] != primitiveRestartIndex) {
const uint n = stride * indices[i];
@@ -225,7 +225,7 @@ protected:
const uint byteStride,
const uint count)
{
- const uint stride = byteStride / sizeof(Coordinate);
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 3;
for (uint ndx = 0; ndx < count; ++ndx) {
visit(ndx, coordinates[0], coordinates[1], coordinates[2]);
coordinates += stride;
@@ -240,7 +240,7 @@ protected:
bool primitiveRestartEnabled,
int primitiveRestartIndex)
{
- const uint stride = byteStride / sizeof(Coordinate);
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 3;
for (uint i = 0; i < count; ++i) {
if (!primitiveRestartEnabled || indices[i] != primitiveRestartIndex) {
const uint n = stride * indices[i];
@@ -254,7 +254,7 @@ protected:
const uint byteStride,
const uint count)
{
- const uint stride = byteStride / sizeof(Coordinate);
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 4;
for (uint ndx = 0; ndx < count; ++ndx) {
visit(ndx, coordinates[0], coordinates[1], coordinates[2], coordinates[3]);
coordinates += stride;
@@ -269,7 +269,7 @@ protected:
bool primitiveRestartEnabled,
int primitiveRestartIndex)
{
- const uint stride = byteStride / sizeof(Coordinate);
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 4;
for (uint i = 0; i < count; ++i) {
if (!primitiveRestartEnabled || indices[i] != primitiveRestartIndex) {
const uint n = stride * indices[i];
diff --git a/src/render/backend/cameralens.cpp b/src/render/backend/cameralens.cpp
index e127b5885..b540b24c8 100644
--- a/src/render/backend/cameralens.cpp
+++ b/src/render/backend/cameralens.cpp
@@ -105,23 +105,25 @@ void CameraLens::setRenderAspect(QRenderAspect *renderAspect)
m_renderAspect = renderAspect;
}
-QMatrix4x4 CameraLens::viewMatrix(const QMatrix4x4 &worldTransform)
+Matrix4x4 CameraLens::viewMatrix(const Matrix4x4 &worldTransform)
{
- const QVector4D position = worldTransform * QVector4D(0.0f, 0.0f, 0.0f, 1.0f);
+ const Vector4D position = worldTransform * Vector4D(0.0f, 0.0f, 0.0f, 1.0f);
// OpenGL convention is looking down -Z
- const QVector4D viewDirection = worldTransform * QVector4D(0.0f, 0.0f, -1.0f, 0.0f);
- const QVector4D upVector = worldTransform * QVector4D(0.0f, 1.0f, 0.0f, 0.0f);
+ const Vector4D viewDirection = worldTransform * Vector4D(0.0f, 0.0f, -1.0f, 0.0f);
+ const Vector4D upVector = worldTransform * Vector4D(0.0f, 1.0f, 0.0f, 0.0f);
QMatrix4x4 m;
- m.lookAt(position.toVector3D(), (position + viewDirection).toVector3D(), upVector.toVector3D());
- return m;
+ m.lookAt(convertToQVector3D(Vector3D(position)),
+ convertToQVector3D(Vector3D(position + viewDirection)),
+ convertToQVector3D(Vector3D(upVector)));
+ return Matrix4x4(m);
}
void CameraLens::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QCameraLensData>>(change);
const auto &data = typedChange->data;
- m_projection = data.projectionMatrix;
+ m_projection = Matrix4x4(data.projectionMatrix);
m_exposure = data.exposure;
}
@@ -160,7 +162,7 @@ void CameraLens::notifySceneBoundingVolume(const Sphere &sphere, QNodeCommand::C
}
}
-void CameraLens::setProjection(const QMatrix4x4 &projection)
+void CameraLens::setProjection(const Matrix4x4 &projection)
{
m_projection = projection;
}
@@ -178,7 +180,7 @@ void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
if (propertyChange->propertyName() == QByteArrayLiteral("projectionMatrix")) {
QMatrix4x4 projectionMatrix = propertyChange->value().value<QMatrix4x4>();
- m_projection = projectionMatrix;
+ m_projection = Matrix4x4(projectionMatrix);
} else if (propertyChange->propertyName() == QByteArrayLiteral("exposure")) {
setExposure(propertyChange->value().toFloat());
}
@@ -212,7 +214,7 @@ void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
}
bool CameraLens::viewMatrixForCamera(EntityManager* manager, Qt3DCore::QNodeId cameraId,
- QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix)
+ Matrix4x4 &viewMatrix, Matrix4x4 &projectionMatrix)
{
Entity *camNode = manager->lookupResource(cameraId);
if (!camNode)
diff --git a/src/render/backend/cameralens_p.h b/src/render/backend/cameralens_p.h
index 9e237cfda..d00358fb8 100644
--- a/src/render/backend/cameralens_p.h
+++ b/src/render/backend/cameralens_p.h
@@ -53,7 +53,7 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DCore/private/qnodecommand_p.h>
-#include <QMatrix4x4>
+#include <Qt3DCore/private/matrix4x4_p.h>
#include <QRectF>
QT_BEGIN_NAMESPACE
@@ -89,10 +89,10 @@ public:
void setRenderAspect(QRenderAspect* renderAspect);
- QMatrix4x4 viewMatrix(const QMatrix4x4 &worldTransform);
+ Matrix4x4 viewMatrix(const Matrix4x4 &worldTransform);
- void setProjection(const QMatrix4x4 &projection);
- inline QMatrix4x4 projection() const { return m_projection; }
+ void setProjection(const Matrix4x4 &projection);
+ inline Matrix4x4 projection() const { return m_projection; }
void setExposure(float exposure);
inline float exposure() const { return m_exposure; }
@@ -101,7 +101,7 @@ public:
void notifySceneBoundingVolume(const Sphere &sphere, Qt3DCore::QNodeCommand::CommandId commandId);
static bool viewMatrixForCamera(EntityManager *manager, Qt3DCore::QNodeId cameraId,
- QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix);
+ Matrix4x4 &viewMatrix, Matrix4x4 &projectionMatrix);
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
@@ -110,8 +110,8 @@ private:
Qt3DCore::QNodeCommand::CommandId commandId);
QRenderAspect *m_renderAspect;
- QMatrix4x4 m_projection;
Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand;
+ Matrix4x4 m_projection;
float m_exposure;
};
diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp
index 1a0e877d6..85334d1d3 100644
--- a/src/render/backend/entity.cpp
+++ b/src/render/backend/entity.cpp
@@ -291,12 +291,12 @@ QVector<Entity *> Entity::children() const
return childrenVector;
}
-QMatrix4x4 *Entity::worldTransform()
+Matrix4x4 *Entity::worldTransform()
{
return m_nodeManagers->worldMatrixManager()->data(m_worldTransform);
}
-const QMatrix4x4 *Entity::worldTransform() const
+const Matrix4x4 *Entity::worldTransform() const
{
return m_nodeManagers->worldMatrixManager()->data(m_worldTransform);
}
diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h
index 5448b5297..075871d85 100644
--- a/src/render/backend/entity_p.h
+++ b/src/render/backend/entity_p.h
@@ -104,8 +104,8 @@ public:
QVector<Entity *> children() const;
bool hasChildren() const { return !m_childrenHandles.empty(); }
- QMatrix4x4 *worldTransform();
- const QMatrix4x4 *worldTransform() const;
+ Matrix4x4 *worldTransform();
+ const Matrix4x4 *worldTransform() const;
Sphere *localBoundingVolume() const { return m_localBoundingVolume.data(); }
Sphere *worldBoundingVolume() const { return m_worldBoundingVolume.data(); }
Sphere *worldBoundingVolumeWithChildren() const { return m_worldBoundingVolumeWithChildren.data(); }
diff --git a/src/render/backend/handle_types_p.h b/src/render/backend/handle_types_p.h
index bec2e3a9a..035bbfc91 100644
--- a/src/render/backend/handle_types_p.h
+++ b/src/render/backend/handle_types_p.h
@@ -53,11 +53,10 @@
#include <Qt3DRender/qt3drender_global.h>
#include <Qt3DCore/private/qhandle_p.h>
+#include <Qt3DCore/private/matrix4x4_p.h>
QT_BEGIN_NAMESPACE
-class QMatrix4x4;
-
namespace Qt3DRender {
class QTextureImageData;
@@ -109,7 +108,7 @@ typedef Qt3DCore::QHandle<FrameGraphNode *> HFrameGraphNode;
typedef Qt3DCore::QHandle<Layer> HLayer;
typedef Qt3DCore::QHandle<LevelOfDetail> HLevelOfDetail;
typedef Qt3DCore::QHandle<Material> HMaterial;
-typedef Qt3DCore::QHandle<QMatrix4x4> HMatrix;
+typedef Qt3DCore::QHandle<Matrix4x4> HMatrix;
typedef Qt3DCore::QHandle<OpenGLVertexArrayObject> HVao;
typedef Qt3DCore::QHandle<Shader> HShader;
typedef Qt3DCore::QHandle<ShaderBuilder> HShaderBuilder;
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index b3e7b6f27..c9bcb799e 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DCore/private/qresourcemanager_p.h>
+#include <Qt3DCore/private/matrix4x4_p.h>
#include <Qt3DRender/private/rendertargetoutput_p.h>
#include <Qt3DRender/private/cameralens_p.h>
#include <Qt3DRender/private/filterkey_p.h>
@@ -189,7 +190,7 @@ public:
};
class MatrixManager : public Qt3DCore::QResourceManager<
- QMatrix4x4,
+ Matrix4x4,
Qt3DCore::QNodeId,
Qt3DCore::NonLockingPolicy>
{
diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp
index 035d4d8d4..5db35082d 100644
--- a/src/render/backend/nodemanagers.cpp
+++ b/src/render/backend/nodemanagers.cpp
@@ -174,7 +174,7 @@ MaterialManager *NodeManagers::manager<Material>() const Q_DECL_NOTHROW
}
template<>
-MatrixManager *NodeManagers::manager<QMatrix4x4*>() const Q_DECL_NOTHROW
+MatrixManager *NodeManagers::manager<Matrix4x4>() const Q_DECL_NOTHROW
{
return m_worldMatrixManager;
}
diff --git a/src/render/backend/pointsvisitor.cpp b/src/render/backend/pointsvisitor.cpp
index 663488357..750182b19 100644
--- a/src/render/backend/pointsvisitor.cpp
+++ b/src/render/backend/pointsvisitor.cpp
@@ -72,7 +72,7 @@ void traverseCoordinatesIndexed(Index *indices,
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
uint ndx;
- QVector3D abc;
+ Vector3D abc;
while (i < indexInfo.count) {
ndx = indices[i];
const uint idx = ndx * verticesStride;
@@ -94,7 +94,7 @@ void traverseCoordinates(Vertex *vertices,
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
uint ndx = 0;
- QVector3D abc;
+ Vector3D abc;
while (ndx < vertexInfo.count) {
const uint idx = ndx * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j)
diff --git a/src/render/backend/pointsvisitor_p.h b/src/render/backend/pointsvisitor_p.h
index 9d44ffec5..1614f185b 100644
--- a/src/render/backend/pointsvisitor_p.h
+++ b/src/render/backend/pointsvisitor_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DCore/private/vector3d_p.h>
QT_BEGIN_NAMESPACE
@@ -75,7 +76,7 @@ public:
void apply(const Qt3DCore::QEntity *entity);
void apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id);
- virtual void visit(uint ndx, const QVector3D &c) = 0;
+ virtual void visit(uint ndx, const Vector3D &c) = 0;
protected:
NodeManagers *m_manager;
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index f7f30b5c9..a3df90f8c 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -45,7 +45,8 @@ HEADERS += \
$$PWD/visitorutils_p.h \
$$PWD/segmentsvisitor_p.h \
$$PWD/pointsvisitor_p.h \
- $$PWD/renderercache_p.h
+ $$PWD/renderercache_p.h \
+ $$PWD/renderbarrierjob_p.h
SOURCES += \
$$PWD/renderthread.cpp \
@@ -82,7 +83,8 @@ SOURCES += \
$$PWD/resourceaccessor.cpp \
$$PWD/segmentsvisitor.cpp \
$$PWD/commandthread.cpp \
- $$PWD/pointsvisitor.cpp
+ $$PWD/pointsvisitor.cpp \
+ $$PWD/renderbarrierjob.cpp
include($$QT3D_BUILD_ROOT/src/core/qt3dcore-config.pri)
QT_FOR_CONFIG += 3dcore-private
diff --git a/src/render/backend/renderbarrierjob.cpp b/src/render/backend/renderbarrierjob.cpp
new file mode 100644
index 000000000..c60c9f368
--- /dev/null
+++ b/src/render/backend/renderbarrierjob.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore 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 "renderbarrierjob_p.h"
+
+#include <Qt3DRender/private/renderlogging_p.h>
+
+#include <QtCore/QThread>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+QDebug operator<<(QDebug debug, JobTypes::JobType type)
+{
+ switch (type) {
+ case JobTypes::ReadRenderQueueSizeBarrier:
+ debug << "ReadRenderQueueSize";
+ break;
+ case JobTypes::BeginDrawingBarrier:
+ debug << "BeginDrawing";
+ break;
+ case JobTypes::UpdateGLResourcesBarrier:
+ debug << "UpdateGLResources";
+ break;
+ case JobTypes::PrepareCommandSubmissionBarrier:
+ debug << "PrepareCommandSubmission";
+ break;
+ case JobTypes::EndDrawingBarrier:
+ debug << "EndDrawing";
+ break;
+ default:
+ break;
+ }
+ return debug;
+}
+
+RenderBarrierJob::RenderBarrierJob(JobTypes::JobType type)
+ : QAspectJob()
+ , m_type(type)
+ , m_begin(0)
+ , m_end(0)
+{
+ SET_JOB_RUN_STAT_TYPE(this, type, 0);
+}
+
+void RenderBarrierJob::waitForDependencies()
+{
+ qCDebug(Jobs) << Q_FUNC_INFO << m_type << "waiting for job on" << QThread::currentThread();
+ m_begin.acquire();
+ qCDebug(Jobs) << Q_FUNC_INFO << m_type << "done waiting for job on" << QThread::currentThread();
+ Q_ASSERT(m_begin.available() == 0);
+}
+
+void RenderBarrierJob::allowToProceed()
+{
+ qCDebug(Jobs) << Q_FUNC_INFO << m_type << "releasing job on" << QThread::currentThread();
+ m_end.release();
+}
+
+void RenderBarrierJob::run()
+{
+ qCDebug(Jobs) << Q_FUNC_INFO << m_type << "job releasing render thread on" << QThread::currentThread();
+ m_begin.release();
+ qCDebug(Jobs) << Q_FUNC_INFO << m_type << "job waiting for render thread on" << QThread::currentThread();
+ m_end.acquire();
+ qCDebug(Jobs) << Q_FUNC_INFO << m_type << "job done on" << QThread::currentThread();
+ Q_ASSERT(m_end.available() == 0);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/renderbarrierjob_p.h b/src/render/backend/renderbarrierjob_p.h
new file mode 100644
index 000000000..a39b2aa83
--- /dev/null
+++ b/src/render/backend/renderbarrierjob_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore 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_RENDERBARRIERJOB_P_H
+#define QT3DRENDER_RENDER_RENDERBARRIERJOB_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/QAspectJob>
+
+#include <Qt3DRender/private/qt3drender_global_p.h>
+#include <Qt3DRender/private/job_common_p.h>
+
+#include <QtCore/qsemaphore.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT RenderBarrierJob : public Qt3DCore::QAspectJob
+{
+public:
+ RenderBarrierJob(JobTypes::JobType type);
+ // Called from render thread
+ void waitForDependencies();
+ // Called from render thread
+ void allowToProceed();
+
+ void run() final;
+private:
+ JobTypes::JobType m_type;
+ QSemaphore m_begin;
+ QSemaphore m_end;
+};
+
+using RenderBarrierJobPtr = QSharedPointer<RenderBarrierJob>;
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_RENDERBARRIERJOB_P_H
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index bb0585e6f..d89813f57 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -89,11 +89,14 @@
#include <Qt3DRender/private/buffercapture_p.h>
#include <Qt3DRender/private/offscreensurfacehelper_p.h>
#include <Qt3DRender/private/renderviewbuilder_p.h>
+#include <Qt3DRender/private/loadtexturedatajob_p.h>
+#include <Qt3DRender/private/renderbarrierjob_p.h>
#include <Qt3DRender/qcameralens.h>
#include <Qt3DCore/private/qeventfilterservice_p.h>
#include <Qt3DCore/private/qabstractaspectjobmanager_p.h>
#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <private/rendersurfaceselector_p.h>
#if QT_CONFIG(qt3d_profile_jobs)
#include <Qt3DCore/private/aspectcommanddebugger_p.h>
@@ -185,10 +188,16 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering))
, m_vaoGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering))
, m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering))
+ , m_loadTextureJob(Render::LoadTextureDataJobPtr::create())
, m_shaderGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyShaders(); }, JobTypes::DirtyShaderGathering))
- , m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading))
+ , m_syncSkeletonLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncSkeletonLoading))
, m_ownedContext(false)
, m_offscreenHelper(nullptr)
+ , m_readRenderQueueSizeBarrierJob(RenderBarrierJobPtr::create(JobTypes::ReadRenderQueueSizeBarrier))
+ , m_beginDrawingBarrierJob(RenderBarrierJobPtr::create(JobTypes::BeginDrawingBarrier))
+ , m_updateGLResourcesBarrierJob(RenderBarrierJobPtr::create(JobTypes::UpdateGLResourcesBarrier))
+ , m_prepareCommandSubmissionBarrierJob(RenderBarrierJobPtr::create(JobTypes::PrepareCommandSubmissionBarrier))
+ , m_endDrawingBarrierJob(RenderBarrierJobPtr::create(JobTypes::EndDrawingBarrier))
#if QT_CONFIG(qt3d_profile_jobs)
, m_commandExecuter(new Qt3DRender::Debug::CommandExecuter(this))
#endif
@@ -199,27 +208,49 @@ Renderer::Renderer(QRenderAspect::RenderType type)
if (m_renderThread)
m_renderThread->waitForStart();
+ // Render thread barrier interdependencies
+ m_beginDrawingBarrierJob->addDependency(m_readRenderQueueSizeBarrierJob);
+ m_updateGLResourcesBarrierJob->addDependency(m_beginDrawingBarrierJob);
+ m_prepareCommandSubmissionBarrierJob->addDependency(m_updateGLResourcesBarrierJob);
+ m_endDrawingBarrierJob->addDependency(m_prepareCommandSubmissionBarrierJob);
+
// Create jobs to update transforms and bounding volumes
// We can only update bounding volumes once all world transforms are known
- m_calculateBoundingVolumeJob->addDependency(m_updateTreeEnabledJob);
m_updateWorldBoundingVolumeJob->addDependency(m_worldTransformJob);
m_updateWorldBoundingVolumeJob->addDependency(m_calculateBoundingVolumeJob);
m_expandBoundingVolumeJob->addDependency(m_updateWorldBoundingVolumeJob);
m_updateShaderDataTransformJob->addDependency(m_worldTransformJob);
m_pickBoundingVolumeJob->addDependency(m_expandBoundingVolumeJob);
-
- // Dirty texture gathering depends on m_syncTextureLoadingJob
- // m_syncTextureLoadingJob will depend on the texture loading jobs
- m_textureGathererJob->addDependency(m_syncTextureLoadingJob);
+ // m_calculateBoundingVolumeJob's dependency on m_updateTreeEnabledJob is set in renderBinJobs
// Ensures all skeletons are loaded before we try to update them
- m_updateSkinningPaletteJob->addDependency(m_syncTextureLoadingJob);
+ m_updateSkinningPaletteJob->addDependency(m_syncSkeletonLoadingJob);
// All world stuff depends on the RenderEntity's localBoundingVolume
m_updateLevelOfDetailJob->addDependency(m_updateMeshTriangleListJob);
m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob);
m_rayCastingJob->addDependency(m_updateMeshTriangleListJob);
+ // Independent job dependencies
+ m_beginDrawingBarrierJob->addDependency(m_vaoGathererJob);
+
+ // Make sure we do not try to filter techniques before we have proper context
+ m_filterCompatibleTechniqueJob->addDependency(m_beginDrawingBarrierJob);
+
+ // Make sure we have gathered dirty shaders, textures and buffers before calling updateGLResources
+ m_updateGLResourcesBarrierJob->addDependency(m_bufferGathererJob);
+ m_updateGLResourcesBarrierJob->addDependency(m_shaderGathererJob);
+ m_updateGLResourcesBarrierJob->addDependency(m_textureGathererJob);
+
+ // Make sure we load textures after gathering
+ m_loadTextureJob->addDependency(m_updateGLResourcesBarrierJob);
+ m_loadTextureJob->addDependency(m_textureGathererJob);
+
+ // Make sure we prepare command submission after textures are loaded
+ m_prepareCommandSubmissionBarrierJob->addDependency(m_loadTextureJob);
+
+ // Make sure we have found compatible techniques before gathering shaders
+ m_updateGLResourcesBarrierJob->addDependency(m_filterCompatibleTechniqueJob);
m_shaderGathererJob->addDependency(m_filterCompatibleTechniqueJob);
m_filterCompatibleTechniqueJob->setRenderer(this);
@@ -288,6 +319,7 @@ void Renderer::setNodeManagers(NodeManagers *managers)
m_updateSkinningPaletteJob->setManagers(m_nodesManager);
m_updateMeshTriangleListJob->setManagers(m_nodesManager);
m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager());
+ m_loadTextureJob->setNodeManagers(m_nodesManager);
}
void Renderer::setServices(QServiceLocator *services)
@@ -406,12 +438,17 @@ void Renderer::shutdown()
m_renderQueue->reset();
if (!m_renderThread) {
+ // Make sure the aspect thread is not left behind
+ m_willRenderPromise.store(0);
+ m_rendererReadySemaphore.release();
releaseGraphicsResources();
} else {
// Wake up the render thread in case it is waiting for some renderviews
// to be ready. The isReadyToSubmit() function checks for a shutdown
// having been requested.
- m_submitRenderViewsSemaphore.release(1);
+ m_willRenderPromise.store(0);
+ m_rendererReadySemaphore.release(1);
+ m_renderJobsReadySemaphore.release(1);
m_renderThread->wait();
}
}
@@ -527,7 +564,7 @@ void Renderer::setSceneRoot(QBackendNodeFactory *factory, Entity *sgRoot)
m_updateTreeEnabledJob->setRoot(m_renderSceneRoot);
// Set all flags to dirty
- m_dirtyBits.marked |= AbstractRenderer::AllDirty;
+ m_dirtyBits |= AbstractRenderer::AllDirty;
}
void Renderer::registerEventFilter(QEventFilterService *service)
@@ -546,6 +583,123 @@ RenderSettings *Renderer::settings() const
return m_settings;
}
+bool Renderer::createSurfaceLockAndMakeCurrent()
+{
+ FrameGraphVisitor visitor(nodeManagers()->frameGraphManager());
+ const QVector<FrameGraphNode *> fgLeaves = visitor.traverse(frameGraphRoot());
+ for (FrameGraphNode *leafNode : fgLeaves) {
+ FrameGraphNode *node = leafNode;
+ while (node) {
+ if (!node->isEnabled() || node->nodeType() != FrameGraphNode::Surface) {
+ node = node->parent();
+ continue;
+ }
+ const auto *surfaceSelector = static_cast<const RenderSurfaceSelector *>(node);
+ auto locker = QSharedPointer<SurfaceLocker>::create(surfaceSelector->surface());
+ if (!locker->isSurfaceValid())
+ return false;
+
+ m_surfaceLockers.append(locker);
+ node = node->parent();
+
+ if (!m_graphicsContext->makeCurrent(surfaceSelector->surface()))
+ return false;
+
+ // TODO: The same surface may appear twice here, so we return early to avoid a deadlock.
+ // We may want to fix this at some point and make sure we properly lock multiple
+ // surfaces.
+ return true;
+ }
+ }
+ // No surface found
+ return false;
+}
+
+// Called by render() or Scene3D on render thread
+void Renderer::lockSurfaceAndRender()
+{
+ // Make sure we can lock the surface before rendering. This cannot be done in a job,
+ // because we would otherwise risk rendering into a surface that could get destroyed.
+ // We could lock/unlock while rendering, but that requires a fair amount of extra
+ // logic to be able to recover gracefully from a partially completed render.
+ if (!createSurfaceLockAndMakeCurrent()) {
+ m_surfaceLockers.clear();
+ abortRenderJobs();
+ // We cannot render because we could not lock the surface or the surface is a nullptr.
+ // However, the surface might change in the next frontend/backend sync.
+ // We therefore need to make sure the aspect thread does not get stuck waiting for
+ // the next frame.
+ m_vsyncFrameAdvanceService->proceedToNextFrame();
+ return;
+ }
+ // Let the aspect thread know that we promise to render
+ m_willRenderPromise.store(1);
+ // Release the aspect thread
+ m_rendererReadySemaphore.release();
+ doRender();
+ // Release the surface lockers
+ m_surfaceLockers.clear();
+}
+
+/*!
+ * \internal
+ * Called by RenderAspect on aspect thread, returns false if
+ * the render thread has not promised to render the next frame.
+ *
+ * If this function returns false, the aspect thread
+ * bails out and does not issue the renderBinJobs.
+ *
+ * This keeps us from ending up in a deadlock where the barriers are
+ * waiting for doRender to release them.
+*/
+bool Renderer::releaseRendererAndRequestPromiseToRender()
+{
+ // Release the render thread, which could be waiting in waitForRenderJobs
+ // or is about to call tryWaitForRenderJobs
+ m_renderJobsReadySemaphore.release();
+ // Wait for the render thread to allow us to continue
+ m_rendererReadySemaphore.acquire();
+ // Check if the render thread has promised to call doRender
+ return m_willRenderPromise.testAndSetOrdered(1, 0);
+}
+
+/*!
+ * \internal
+ * Called by render(), returns false if we are no longer running
+*/
+bool Renderer::waitForRenderJobs()
+{
+ // Wait for the aspect thread to arrive at releaseRendererAndRequestPromiseToRender,
+ // which is right before it will create the renderBinJobs
+ m_renderJobsReadySemaphore.acquire();
+ // Check if we have not shut down in the meantime and rather want to bail out
+ return m_running.load();
+}
+
+/*!
+ * \internal
+ * Called by Scene3D, returns true if we could acquire
+*/
+bool Renderer::tryWaitForRenderJobs(int timeout)
+{
+ // See if the aspect thread has arrived at releaseRendererAndRequestPromiseToRender.
+ // If not, Scene3D needs to continue to avoid locking up the render thread.
+ return m_renderJobsReadySemaphore.tryAcquire(1, timeout) && m_running.load();
+}
+
+/*!
+ * \internal
+ * Called by Scene3D, in shutdown
+*/
+void Renderer::abortRenderJobs()
+{
+ // Make sure the aspect does not start render jobs
+ m_willRenderPromise.store(0);
+ // Release the aspect so it gets out of the job creation
+ m_rendererReadySemaphore.release();
+}
+
+
void Renderer::render()
{
// Traversing the framegraph tree from root to lead node
@@ -562,168 +716,102 @@ void Renderer::render()
// One scene description
// One framegraph description
- while (m_running.load() > 0) {
- doRender();
+ while (waitForRenderJobs()) {
+ lockSurfaceAndRender();
// TO DO: Restore windows exposed detection
// Probably needs to happens some place else though
}
}
-void Renderer::doRender(bool scene3dBlocking)
+/*!
+ * \internal
+ * The doRender function is called either by Renderer::render or
+ * QRenderAspect::tryRenderSynchronous (Scene3D).
+ * Jobs that it depends on are guaranteed to have been spawned by the aspect thread.
+ * It will run once for each set of renderBinJobs.
+ * Throughout the function call, the jobs are kept in sync using barriers.
+ * This guarantees the state of the GL context for the jobs.
+ * It is therefore important that any job that needs this function to be in at a specific point
+ * in the executio depends on the right barrier.
+*/
+void Renderer::doRender()
{
- Renderer::ViewSubmissionResultData submissionData;
- bool hasCleanedQueueAndProceeded = false;
- bool preprocessingComplete = false;
- bool beganDrawing = false;
- const bool canSubmit = isReadyToSubmit();
-
- // Lock the mutex to protect access to the renderQueue while we look for its state
- QMutexLocker locker(m_renderQueue->mutex());
- bool queueIsComplete = m_renderQueue->isFrameQueueComplete();
+ m_readRenderQueueSizeBarrierJob->waitForDependencies();
+ const bool queueIsComplete = m_renderQueue->isFrameQueueComplete();
const bool queueIsEmpty = m_renderQueue->targetRenderViewCount() == 0;
+ Q_ASSERT(queueIsComplete && !queueIsEmpty);
+ m_readRenderQueueSizeBarrierJob->allowToProceed();
- // Scene3D Blocking Mode
- if (scene3dBlocking && !queueIsComplete && !queueIsEmpty) {
- int i = 0;
- // We wait at most 10ms to avoid a case we could never recover from
- while (!queueIsComplete && i++ < 10) {
- QThread::msleep(1);
- qCDebug(Backend) << Q_FUNC_INFO << "Waiting for ready queue (try:" << i << "/ 10)";
- locker.unlock();
- queueIsComplete = m_renderQueue->isFrameQueueComplete();
- locker.relock();
- }
- }
-
- // When using synchronous rendering (QtQuick)
- // We are not sure that the frame queue is actually complete
- // Since a call to render may not be synched with the completions
- // of the RenderViewJobs
- // In such a case we return early, waiting for a next call with
- // the frame queue complete at this point
-
- // RenderQueue is complete (but that means it may be of size 0)
- if (canSubmit && (queueIsComplete && !queueIsEmpty)) {
- const QVector<Render::RenderView *> renderViews = m_renderQueue->nextFrameQueue();
-
+ const QVector<Render::RenderView *> renderViews = m_renderQueue->nextFrameQueue();
#if QT_CONFIG(qt3d_profile_jobs)
- // Save start of frame
- JobRunStats submissionStatsPart1;
- JobRunStats submissionStatsPart2;
- submissionStatsPart1.jobId.typeAndInstance[0] = JobTypes::FrameSubmissionPart1;
- submissionStatsPart1.jobId.typeAndInstance[1] = 0;
- submissionStatsPart1.threadId = reinterpret_cast<quint64>(QThread::currentThreadId());
- submissionStatsPart1.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
- submissionStatsPart2.jobId.typeAndInstance[0] = JobTypes::FrameSubmissionPart2;
- submissionStatsPart2.jobId.typeAndInstance[1] = 0;
- submissionStatsPart2.threadId = reinterpret_cast<quint64>(QThread::currentThreadId());
+ // Save start of frame
+ JobRunStats submissionStatsPart1;
+ JobRunStats submissionStatsPart2;
+ submissionStatsPart1.jobId.typeAndInstance[0] = JobTypes::FrameSubmissionPart1;
+ submissionStatsPart1.jobId.typeAndInstance[1] = 0;
+ submissionStatsPart1.threadId = reinterpret_cast<quint64>(QThread::currentThreadId());
+ submissionStatsPart1.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
+ submissionStatsPart2.jobId.typeAndInstance[0] = JobTypes::FrameSubmissionPart2;
+ submissionStatsPart2.jobId.typeAndInstance[1] = 0;
+ submissionStatsPart2.threadId = reinterpret_cast<quint64>(QThread::currentThreadId());
#endif
- if (canRender()) {
- { // Scoped to destroy surfaceLock
- QSurface *surface = nullptr;
- for (const Render::RenderView *rv: renderViews) {
- surface = rv->surface();
- if (surface)
- break;
- }
-
- SurfaceLocker surfaceLock(surface);
- const bool surfaceIsValid = (surface && surfaceLock.isSurfaceValid());
- if (surfaceIsValid) {
- // Reset state for each draw if we don't have complete control of the context
- if (!m_ownedContext)
- m_graphicsContext->setCurrentStateSet(nullptr);
- beganDrawing = m_graphicsContext->beginDrawing(surface);
- if (beganDrawing) {
- // 1) Execute commands for buffer uploads, texture updates, shader loading first
- updateGLResources();
- // 2) Update VAO and copy data into commands to allow concurrent submission
- prepareCommandsSubmission(renderViews);
- preprocessingComplete = true;
- }
- }
- }
- // 2) Proceed to next frame and start preparing frame n + 1
- m_renderQueue->reset();
- locker.unlock(); // Done protecting RenderQueue
- m_vsyncFrameAdvanceService->proceedToNextFrame();
- hasCleanedQueueAndProceeded = true;
+ // Reset state for each draw if we don't have complete control of the context
+ if (!m_ownedContext)
+ m_graphicsContext->setCurrentStateSet(nullptr);
+ // Initialize context
+ m_beginDrawingBarrierJob->waitForDependencies();
+ m_graphicsContext->beginDrawing();
+ m_beginDrawingBarrierJob->allowToProceed();
+ // Execute commands for buffer uploads, texture updates, shader loading first
+ m_updateGLResourcesBarrierJob->waitForDependencies();
+ updateGLResources();
+ m_updateGLResourcesBarrierJob->allowToProceed();
+ // Update VAO and copy data into commands to allow concurrent submission
+ m_prepareCommandSubmissionBarrierJob->waitForDependencies();
+ prepareCommandsSubmission(renderViews);
+ m_prepareCommandSubmissionBarrierJob->allowToProceed();
+
+ // Proceed to next frame and start preparing frame n + 1
+ m_renderQueue->reset();
+ m_vsyncFrameAdvanceService->proceedToNextFrame();
#if QT_CONFIG(qt3d_profile_jobs)
- if (preprocessingComplete) {
- submissionStatsPart2.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
- submissionStatsPart1.endTime = submissionStatsPart2.startTime;
- }
+ submissionStatsPart2.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
+ submissionStatsPart1.endTime = submissionStatsPart2.startTime;
#endif
- // Only try to submit the RenderViews if the preprocessing was successful
- // This part of the submission is happening in parallel to the RV building for the next frame
- if (preprocessingComplete) {
- // 3) Submit the render commands for frame n (making sure we never reference something that could be changing)
- // Render using current device state and renderer configuration
- submissionData = submitRenderViews(renderViews);
-
- // Perform any required cleanup of the Graphics resources (Buffers deleted, Shader deleted...)
- cleanGraphicsResources();
- }
- }
+ // Submit the render commands for frame n (making sure we never reference something that could be changing)
+ // Render using current device state and renderer configuration
+ Renderer::ViewSubmissionResultData submissionData = submitRenderViews(renderViews);
+ // Perform any required cleanup of the Graphics resources (Buffers deleted, Shader deleted...)
+ cleanGraphicsResources();
#if QT_CONFIG(qt3d_profile_jobs)
- // Execute the pending shell commands
- m_commandExecuter->performAsynchronousCommandExecution(renderViews);
+ // Execute the pending shell commands
+ m_commandExecuter->performAsynchronousCommandExecution(renderViews);
#endif
- // Delete all the RenderViews which will clear the allocators
- // that were used for their allocation
- qDeleteAll(renderViews);
+ // Delete all the RenderViews which will clear the allocators
+ // that were used for their allocation
+ qDeleteAll(renderViews);
#if QT_CONFIG(qt3d_profile_jobs)
- if (preprocessingComplete) {
- // Save submission elapsed time
- submissionStatsPart2.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
- // Note this is safe since proceedToNextFrame is the one going to trigger
- // the write to the file, and this is performed after this step
- Qt3DCore::QThreadPooler::addSubmissionLogStatsEntry(submissionStatsPart1);
- Qt3DCore::QThreadPooler::addSubmissionLogStatsEntry(submissionStatsPart2);
- Profiling::GLTimeRecorder::writeResults();
- }
+ // Save submission elapsed time
+ submissionStatsPart2.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
+ // Note this is safe since proceedToNextFrame is the one going to trigger
+ // the write to the file, and this is performed after this step
+ Qt3DCore::QThreadPooler::addSubmissionLogStatsEntry(submissionStatsPart1);
+ Qt3DCore::QThreadPooler::addSubmissionLogStatsEntry(submissionStatsPart2);
+ Profiling::GLTimeRecorder::writeResults();
#endif
- }
-
- // Only reset renderQueue and proceed to next frame if the submission
- // succeeded or if we are using a render thread and that is wasn't performed
- // already
-
- // If hasCleanedQueueAndProceeded isn't true this implies that something went wrong
- // with the rendering and/or the renderqueue is incomplete from some reason
- // (in the case of scene3d the render jobs may be taking too long ....)
- // or alternatively it could be complete but empty (RenderQueue of size 0)
- if (!hasCleanedQueueAndProceeded &&
- (m_renderThread || queueIsComplete || queueIsEmpty)) {
- // RenderQueue was full but something bad happened when
- // trying to render it and therefore proceedToNextFrame was not called
- // Note: in this case the renderQueue mutex is still locked
-
- // Reset the m_renderQueue so that we won't try to render
- // with a queue used by a previous frame with corrupted content
- // if the current queue was correctly submitted
- m_renderQueue->reset();
-
- // We allow the RenderTickClock service to proceed to the next frame
- // In turn this will allow the aspect manager to request a new set of jobs
- // to be performed for each aspect
- m_vsyncFrameAdvanceService->proceedToNextFrame();
- }
// Perform the last swapBuffers calls after the proceedToNextFrame
// as this allows us to gain a bit of time for the preparation of the
// next frame
// Finish up with last surface used in the list of RenderViews
- if (beganDrawing) {
- SurfaceLocker surfaceLock(submissionData.surface);
- // Finish up with last surface used in the list of RenderViews
- m_graphicsContext->endDrawing(submissionData.lastBoundFBOId == m_graphicsContext->defaultFBO() && surfaceLock.isSurfaceValid());
- }
+ m_endDrawingBarrierJob->waitForDependencies();
+ m_graphicsContext->endDrawing(submissionData.lastBoundFBOId == m_graphicsContext->defaultFBO());
+ m_endDrawingBarrierJob->allowToProceed();
}
// Called by RenderViewJobs
@@ -738,48 +826,8 @@ void Renderer::enqueueRenderView(Render::RenderView *renderView, int submitOrder
// could be invalid since depending on the order of execution
// the counter could be complete but the renderview not yet added to the
// buffer depending on whichever order the cpu decides to process this
- const bool isQueueComplete = m_renderQueue->queueRenderView(renderView, submitOrder);
+ m_renderQueue->queueRenderView(renderView, submitOrder);
locker.unlock(); // We're done protecting the queue at this point
- if (isQueueComplete) {
- if (m_renderThread && m_running.load())
- Q_ASSERT(m_submitRenderViewsSemaphore.available() == 0);
- m_submitRenderViewsSemaphore.release(1);
- }
-}
-
-bool Renderer::canRender() const
-{
- // Make sure that we've not been told to terminate
- if (m_renderThread && !m_running.load()) {
- qCDebug(Rendering) << "RenderThread termination requested whilst waiting";
- return false;
- }
-
- // TO DO: Check if all surfaces have been destroyed...
- // It may be better if the last window to be closed trigger a call to shutdown
- // Rather than having checks for the surface everywhere
-
- return true;
-}
-
-bool Renderer::isReadyToSubmit()
-{
- // If we are using a render thread, make sure that
- // we've been told to render before rendering
- if (m_renderThread) { // Prevent ouf of order execution
- m_submitRenderViewsSemaphore.acquire(1);
-
- // Check if shutdown has been requested
- if (m_running.load() == 0)
- return false;
-
- // When using Thread rendering, the semaphore should only
- // be released when the frame queue is complete and there's
- // something to render
- // The case of shutdown should have been handled just before
- Q_ASSERT(m_renderQueue->isFrameQueueComplete());
- }
- return true;
}
// Main thread
@@ -890,6 +938,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
const QVector<Qt3DCore::QNodeId> attributeIds = rGeometry->attributes();
for (Qt3DCore::QNodeId attributeId : attributeIds) {
Attribute *attribute = m_nodesManager->attributeManager()->lookupResource(attributeId);
+ Q_ASSERT(attribute);
switch (attribute->attributeType()) {
case QAttribute::IndexAttribute:
indexAttribute = attribute;
@@ -922,6 +971,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
if (command->m_drawIndirect) {
command->m_indirectAttributeByteOffset = indirectAttribute->byteOffset();
command->m_indirectDrawBuffer = m_nodesManager->bufferManager()->lookupHandle(indirectAttribute->bufferId());
+ Q_ASSERT(!command->m_indirectDrawBuffer.isNull());
} else {
// Use the count specified by the GeometryRender
// If not specify use the indexAttribute count if present
@@ -1037,6 +1087,7 @@ void Renderer::lookForDirtyShaders()
RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
+ Q_ASSERT(renderPass && shader);
ShaderBuilder *shaderBuilder = nullptr;
for (const HShaderBuilder &builderHandle : activeBuilders) {
@@ -1103,6 +1154,7 @@ void Renderer::updateGLResources()
const QVector<HBuffer> dirtyBufferHandles = std::move(m_dirtyBuffers);
for (const HBuffer &handle: dirtyBufferHandles) {
Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
+ Q_ASSERT(buffer);
// Forces creation if it doesn't exit
// Also note the binding point doesn't really matter here, we just upload data
if (!m_graphicsContext->hasGLBufferForBuffer(buffer))
@@ -1119,6 +1171,7 @@ void Renderer::updateGLResources()
ShaderManager *shaderManager = m_nodesManager->shaderManager();
for (const HShader &handle: dirtyShaderHandles) {
Shader *shader = shaderManager->data(handle);
+ Q_ASSERT(shader);
// Compile shader
m_graphicsContext->loadShader(shader, shaderManager);
}
@@ -1129,6 +1182,7 @@ void Renderer::updateGLResources()
const QVector<HTexture> activeTextureHandles = std::move(m_dirtyTextures);
for (const HTexture &handle: activeTextureHandles) {
Texture *texture = m_nodesManager->textureManager()->data(handle);
+ Q_ASSERT(texture);
// Upload/Update texture
updateTexture(texture);
}
@@ -1236,6 +1290,7 @@ void Renderer::updateTexture(Texture *texture)
// Render Thread
void Renderer::cleanupTexture(const Texture *texture)
{
+ Q_ASSERT(texture);
GLTextureManager *glTextureManager = m_nodesManager->glTextureManager();
GLTexture *glTexture = glTextureManager->lookupResource(texture->peerId());
@@ -1288,7 +1343,6 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
// If not, we have to free up the context from the previous surface
// and make the context current on the new surface
surface = renderView->surface();
- SurfaceLocker surfaceLock(surface);
// TO DO: Make sure that the surface we are rendering too has not been unset
@@ -1296,7 +1350,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
// TODO: Investigate if it's worth providing a fallback offscreen surface
// to use when surface is null. Or if we should instead expose an
// offscreensurface to Qt3D.
- if (!surface || !surfaceLock.isSurfaceValid()) {
+ if (!surface) {
m_lastFrameCorrect.store(0);
continue;
}
@@ -1313,12 +1367,14 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
if (surfaceHasChanged) {
// If we can't make the context current on the surface, skip to the
// next RenderView. We won't get the full frame but we may get something
- if (!m_graphicsContext->beginDrawing(surface)) {
+ if (!m_graphicsContext->makeCurrent(surface)) {
qWarning() << "Failed to make OpenGL context current on surface";
m_lastFrameCorrect.store(0);
continue;
}
+ m_graphicsContext->beginDrawing();
+
previousSurface = surface;
lastBoundFBOId = m_graphicsContext->boundFrameBufferObject();
}
@@ -1457,39 +1513,35 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
void Renderer::markDirty(BackendNodeDirtySet changes, BackendNode *node)
{
Q_UNUSED(node);
- m_dirtyBits.marked |= changes;
+ m_dirtyBits|= changes;
}
Renderer::BackendNodeDirtySet Renderer::dirtyBits()
{
- return m_dirtyBits.marked;
+ return m_dirtyBits;
}
#if defined(QT_BUILD_INTERNAL)
void Renderer::clearDirtyBits(BackendNodeDirtySet changes)
{
- m_dirtyBits.remaining &= ~changes;
- m_dirtyBits.marked &= ~changes;
+ m_dirtyBits &= ~changes;
}
#endif
bool Renderer::shouldRender()
{
+ if (!m_settings)
+ return false;
// Only render if something changed during the last frame, or the last frame
// was not rendered successfully (or render-on-demand is disabled)
return (m_settings->renderPolicy() == QRenderSettings::Always
- || m_dirtyBits.marked != 0
- || m_dirtyBits.remaining != 0
+ || m_dirtyBits != 0
|| !m_lastFrameCorrect.load());
}
void Renderer::skipNextFrame()
{
- Q_ASSERT(m_settings->renderPolicy() != QRenderSettings::Always);
-
- // make submitRenderViews() actually run
- m_renderQueue->setNoRender();
- m_submitRenderViewsSemaphore.release(1);
+ m_vsyncFrameAdvanceService->proceedToNextFrame();
}
// Waits to be told to create jobs for the next frame
@@ -1500,28 +1552,46 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
{
QVector<QAspectJobPtr> renderBinJobs;
- // Create the jobs to build the frame
- const QVector<QAspectJobPtr> bufferJobs = createRenderBufferJobs();
-
// Remove previous dependencies
m_calculateBoundingVolumeJob->removeDependency(QWeakPointer<QAspectJob>());
m_cleanupJob->removeDependency(QWeakPointer<QAspectJob>());
- // Set dependencies
- for (const QAspectJobPtr &bufferJob : bufferJobs)
- m_calculateBoundingVolumeJob->addDependency(bufferJob);
+ // Render thread barrier jobs
+ renderBinJobs.append(m_readRenderQueueSizeBarrierJob);
+ renderBinJobs.append(m_beginDrawingBarrierJob);
+ renderBinJobs.append(m_updateGLResourcesBarrierJob);
+ renderBinJobs.append(m_prepareCommandSubmissionBarrierJob);
+ renderBinJobs.append(m_endDrawingBarrierJob);
+ // Jobs independent of dirty bits
+ renderBinJobs.push_back(m_updateSkinningPaletteJob);
+ renderBinJobs.push_back(m_updateLevelOfDetailJob);
+ renderBinJobs.push_back(m_cleanupJob);
+ renderBinJobs.push_back(m_sendRenderCaptureJob);
+ renderBinJobs.push_back(m_sendBufferCaptureJob);
+ renderBinJobs.push_back(m_vaoGathererJob);
+
+ // Independent job properties
+ m_updateSkinningPaletteJob->setDirtyJoints(m_nodesManager->jointManager()->dirtyJoints());
m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot());
- const BackendNodeDirtySet dirtyBitsForFrame = m_dirtyBits.marked | m_dirtyBits.remaining;
- m_dirtyBits.marked = 0;
- m_dirtyBits.remaining = 0;
- BackendNodeDirtySet notCleared = 0;
+ // Buffer jobs, depends on dirty buffers
+ const QVector<QAspectJobPtr> bufferJobs = createRenderBufferJobs();
+ for (const QAspectJobPtr &bufferJob : bufferJobs) {
+ m_calculateBoundingVolumeJob->addDependency(bufferJob);
+ m_beginDrawingBarrierJob->addDependency(bufferJob);
+ }
+ renderBinJobs.append(bufferJobs);
+
+ // Jobs dependent on dirty bits
+ const BackendNodeDirtySet dirtyBitsForFrame = m_dirtyBits;
+ m_dirtyBits = 0;
- // Add jobs
const bool entitiesEnabledDirty = dirtyBitsForFrame & AbstractRenderer::EntityEnabledDirty;
if (entitiesEnabledDirty) {
renderBinJobs.push_back(m_updateTreeEnabledJob);
+ // This dependency is added here because we clear all dependencies
+ // at the start of this function.
m_calculateBoundingVolumeJob->addDependency(m_updateTreeEnabledJob);
}
@@ -1541,80 +1611,55 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.push_back(m_expandBoundingVolumeJob);
}
- m_updateSkinningPaletteJob->setDirtyJoints(m_nodesManager->jointManager()->dirtyJoints());
- renderBinJobs.push_back(m_updateSkinningPaletteJob);
- renderBinJobs.push_back(m_updateLevelOfDetailJob);
- renderBinJobs.push_back(m_cleanupJob);
- renderBinJobs.push_back(m_sendRenderCaptureJob);
- renderBinJobs.push_back(m_sendBufferCaptureJob);
- renderBinJobs.append(bufferJobs);
-
- // Jobs to prepare GL Resource upload
- renderBinJobs.push_back(m_vaoGathererJob);
-
if (dirtyBitsForFrame & AbstractRenderer::BuffersDirty)
renderBinJobs.push_back(m_bufferGathererJob);
if (dirtyBitsForFrame & AbstractRenderer::TexturesDirty) {
- renderBinJobs.push_back(m_syncTextureLoadingJob);
+ renderBinJobs.push_back(m_loadTextureJob);
renderBinJobs.push_back(m_textureGathererJob);
}
+ if (dirtyBitsForFrame & AbstractRenderer::SkeletonDataDirty)
+ renderBinJobs.push_back(m_syncSkeletonLoadingJob);
+
+ if (dirtyBitsForFrame & AbstractRenderer::TechniquesDirty )
+ renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
+
+ if (dirtyBitsForFrame & AbstractRenderer::ShadersDirty)
+ renderBinJobs.push_back(m_shaderGathererJob);
// Layer cache is dependent on layers, layer filters and the enabled flag
// on entities
const bool layersDirty = dirtyBitsForFrame & AbstractRenderer::LayersDirty;
const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty;
-
const bool materialDirty = dirtyBitsForFrame & AbstractRenderer::MaterialDirty;
- QMutexLocker lock(m_renderQueue->mutex());
- if (m_renderQueue->wasReset()) { // Have we rendered yet? (Scene3D case)
- // Traverse the current framegraph. For each leaf node create a
- // RenderView and set its configuration then create a job to
- // populate the RenderView with a set of RenderCommands that get
- // their details from the RenderNodes that are visible to the
- // Camera selected by the framegraph configuration
- FrameGraphVisitor visitor(m_nodesManager->frameGraphManager());
- const QVector<FrameGraphNode *> fgLeaves = visitor.traverse(frameGraphRoot());
-
- // Remove leaf nodes that no longer exist from cache
- const QList<FrameGraphNode *> keys = m_cache.leafNodeCache.keys();
- for (FrameGraphNode *leafNode : keys) {
- if (!fgLeaves.contains(leafNode))
- m_cache.leafNodeCache.remove(leafNode);
- }
-
- const int fgBranchCount = fgLeaves.size();
- for (int i = 0; i < fgBranchCount; ++i) {
- RenderViewBuilder builder(fgLeaves.at(i), i, this);
- builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt);
- builder.setMaterialGathererCacheNeedsToBeRebuilt(materialDirty);
- builder.prepareJobs();
- renderBinJobs.append(builder.buildJobHierachy());
- }
-
- // Set target number of RenderViews
- m_renderQueue->setTargetRenderViewCount(fgBranchCount);
- } else {
- // FilterLayerEntityJob is part of the RenderViewBuilder jobs and must be run later
- // if none of those jobs are started this frame
- notCleared |= AbstractRenderer::EntityEnabledDirty;
- notCleared |= AbstractRenderer::LayersDirty;
+ // Traverse the current framegraph. For each leaf node create a
+ // RenderView and set its configuration then create a job to
+ // populate the RenderView with a set of RenderCommands that get
+ // their details from the RenderNodes that are visible to the
+ // Camera selected by the framegraph configuration
+ FrameGraphVisitor visitor(m_nodesManager->frameGraphManager());
+ const QVector<FrameGraphNode *> fgLeaves = visitor.traverse(frameGraphRoot());
+
+ // Remove leaf nodes that no longer exist from cache
+ const QList<FrameGraphNode *> keys = m_cache.leafNodeCache.keys();
+ for (FrameGraphNode *leafNode : keys) {
+ if (!fgLeaves.contains(leafNode))
+ m_cache.leafNodeCache.remove(leafNode);
}
- if (isRunning() && m_graphicsContext->isInitialized()) {
- if (dirtyBitsForFrame & AbstractRenderer::TechniquesDirty )
- renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
- if (dirtyBitsForFrame & AbstractRenderer::ShadersDirty)
- renderBinJobs.push_back(m_shaderGathererJob);
- } else {
- notCleared |= AbstractRenderer::TechniquesDirty;
- notCleared |= AbstractRenderer::ShadersDirty;
- notCleared |= AbstractRenderer::MaterialDirty;
+ const int fgBranchCount = fgLeaves.size();
+ for (int i = 0; i < fgBranchCount; ++i) {
+ RenderViewBuilder builder(fgLeaves.at(i), i, this);
+ builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt);
+ builder.setMaterialGathererCacheNeedsToBeRebuilt(materialDirty);
+ builder.prepareJobs();
+ renderBinJobs.append(builder.buildJobHierachy());
}
- m_dirtyBits.remaining = dirtyBitsForFrame & notCleared;
+ // Set target number of RenderViews
+ m_renderQueue->setTargetRenderViewCount(fgBranchCount);
return renderBinJobs;
}
@@ -1645,9 +1690,9 @@ QAspectJobPtr Renderer::rayCastingJob()
return m_rayCastingJob;
}
-QAspectJobPtr Renderer::syncTextureLoadingJob()
+QAspectJobPtr Renderer::syncSkeletonLoadingJob()
{
- return m_syncTextureLoadingJob;
+ return m_syncSkeletonLoadingJob;
}
QAspectJobPtr Renderer::expandBoundingVolumeJob()
@@ -1752,7 +1797,7 @@ void Renderer::performCompute(const RenderView *, RenderCommand *command)
command->m_workGroups[2]);
}
// HACK: Reset the compute flag to dirty
- m_dirtyBits.marked |= AbstractRenderer::ComputeDirty;
+ m_dirtyBits |= AbstractRenderer::ComputeDirty;
#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
int err = m_graphicsContext->openGLContext()->functions()->glGetError();
@@ -1888,11 +1933,13 @@ bool Renderer::updateVAOWithAttributes(Geometry *geometry,
for (QNodeId attributeId : attributeIds) {
// TO DO: Improvement we could store handles and use the non locking policy on the attributeManager
Attribute *attribute = m_nodesManager->attributeManager()->lookupResource(attributeId);
+ Q_ASSERT(attribute);
if (attribute == nullptr)
return false;
Buffer *buffer = m_nodesManager->bufferManager()->lookupResource(attribute->bufferId());
+ Q_ASSERT(buffer);
// Buffer update was already performed at this point
// Just make sure the attribute reference a valid buffer
@@ -1945,6 +1992,7 @@ bool Renderer::requiresVAOAttributeUpdate(Geometry *geometry,
for (QNodeId attributeId : attributeIds) {
// TO DO: Improvement we could store handles and use the non locking policy on the attributeManager
Attribute *attribute = m_nodesManager->attributeManager()->lookupResource(attributeId);
+ Q_ASSERT(attribute);
if (attribute == nullptr)
continue;
@@ -1986,7 +2034,7 @@ void Renderer::cleanGraphicsResources()
}
}
-QList<QMouseEvent> Renderer::pendingPickingEvents() const
+QList<QPair<QObject *, QMouseEvent>> Renderer::pendingPickingEvents() const
{
return m_pickEventFilter->pendingMouseEvents();
}
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index 521d17e80..fbb29dc7c 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -144,6 +144,10 @@ class NodeManagers;
class UpdateLevelOfDetailJob;
typedef QSharedPointer<UpdateLevelOfDetailJob> UpdateLevelOfDetailJobPtr;
+class LoadTextureDataJob;
+using LoadTextureDataJobPtr = QSharedPointer<LoadTextureDataJob>;
+class RenderBarrierJob;
+using RenderBarrierJobPtr = QSharedPointer<RenderBarrierJob>;
using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>;
@@ -171,7 +175,7 @@ public:
void releaseGraphicsResources() override;
void render() override;
- void doRender(bool scene3dBlocking = false) override;
+ void doRender() override;
void cleanGraphicsResources() override;
bool isRunning() const override { return m_running.load(); }
@@ -188,17 +192,29 @@ public:
void clearDirtyBits(BackendNodeDirtySet changes) override;
#endif
+ void lockSurfaceAndRender() override;
+ bool releaseRendererAndRequestPromiseToRender() override;
+ bool waitForRenderJobs() override;
+ bool tryWaitForRenderJobs(int timeout) override;
+ void abortRenderJobs() override;
+
bool shouldRender() override;
void skipNextFrame() override;
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() override;
Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() override;
Qt3DCore::QAspectJobPtr rayCastingJob() override;
- Qt3DCore::QAspectJobPtr syncTextureLoadingJob() override;
+ Qt3DCore::QAspectJobPtr syncSkeletonLoadingJob() override;
Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() override;
QVector<Qt3DCore::QAspectJobPtr> createRenderBufferJobs() const;
+ inline RenderBarrierJobPtr readRenderQueueSizeBarrierJob() const { return m_readRenderQueueSizeBarrierJob; }
+ inline RenderBarrierJobPtr beginDrawingBarrierJob() const { return m_beginDrawingBarrierJob; }
+ inline RenderBarrierJobPtr updateGLResourcesBarrierJob() const { return m_updateGLResourcesBarrierJob; }
+ inline RenderBarrierJobPtr prepareCommandSubmissionBarrierJob() const { return m_prepareCommandSubmissionBarrierJob; }
+ inline RenderBarrierJobPtr endDrawingBarrierJob() const { return m_endDrawingBarrierJob; }
+
inline FrameCleanupJobPtr frameCleanupJob() const { return m_cleanupJob; }
inline UpdateShaderDataTransformJobPtr updateShaderDataTransformJob() const { return m_updateShaderDataTransformJob; }
inline CalculateBoundingVolumeJobPtr calculateBoundingVolumeJob() const { return m_calculateBoundingVolumeJob; }
@@ -208,8 +224,9 @@ public:
inline UpdateLevelOfDetailJobPtr updateLevelOfDetailJob() const { return m_updateLevelOfDetailJob; }
inline UpdateMeshTriangleListJobPtr updateMeshTriangleListJob() const { return m_updateMeshTriangleListJob; }
inline FilterCompatibleTechniqueJobPtr filterCompatibleTechniqueJob() const { return m_filterCompatibleTechniqueJob; }
- inline SynchronizerJobPtr textureLoadSyncJob() const { return m_syncTextureLoadingJob; }
+ inline SynchronizerJobPtr textureLoadSyncJob() const { return m_syncSkeletonLoadingJob; }
inline UpdateSkinningPaletteJobPtr updateSkinningPaletteJob() const { return m_updateSkinningPaletteJob; }
+ inline LoadTextureDataJobPtr loadTextureJob() const {return m_loadTextureJob; }
Qt3DCore::QAbstractFrameAdvanceService *frameAdvanceService() const override;
@@ -245,14 +262,13 @@ public:
inline RenderStateSet *defaultRenderState() const { return m_defaultRenderStateSet; }
- QList<QMouseEvent> pendingPickingEvents() const;
+ QList<QPair<QObject*, QMouseEvent>> pendingPickingEvents() const;
QList<QKeyEvent> pendingKeyEvents() const;
void addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId);
const QVector<Qt3DCore::QNodeId> takePendingRenderCaptureSendRequests();
void enqueueRenderView(RenderView *renderView, int submitOrder);
- bool isReadyToSubmit();
QVariant executeCommand(const QStringList &args) override;
void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) override;
@@ -279,7 +295,7 @@ public:
private:
#endif
- bool canRender() const;
+ bool hasBeenAskedToTerminate() const;
Qt3DCore::QServiceLocator *m_services;
NodeManagers *m_nodesManager;
@@ -301,7 +317,6 @@ private:
QScopedPointer<RenderThread> m_renderThread;
QScopedPointer<VSyncFrameAdvanceService> m_vsyncFrameAdvanceService;
- QSemaphore m_submitRenderViewsSemaphore;
QSemaphore m_waitForInitializationToBeCompleted;
QAtomicInt m_running;
@@ -312,11 +327,7 @@ private:
QVector<Geometry *> m_dirtyGeometry;
QAtomicInt m_exposed;
- struct DirtyBits {
- BackendNodeDirtySet marked = 0; // marked dirty since last job build
- BackendNodeDirtySet remaining = 0; // remaining dirty after jobs have finished
- };
- DirtyBits m_dirtyBits;
+ BackendNodeDirtySet m_dirtyBits;
QAtomicInt m_lastFrameCorrect;
QOpenGLContext *m_glContext;
@@ -354,15 +365,18 @@ private:
GenericLambdaJobPtr<std::function<void ()>> m_bufferGathererJob;
GenericLambdaJobPtr<std::function<void ()>> m_vaoGathererJob;
GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob;
+ LoadTextureDataJobPtr m_loadTextureJob;
+
GenericLambdaJobPtr<std::function<void ()>> m_shaderGathererJob;
- SynchronizerJobPtr m_syncTextureLoadingJob;
+ SynchronizerJobPtr m_syncSkeletonLoadingJob;
void lookForAbandonedVaos();
void lookForDirtyBuffers();
void lookForDownloadableBuffers();
void lookForDirtyTextures();
void lookForDirtyShaders();
+ bool createSurfaceLockAndMakeCurrent();
QMutex m_abandonedVaosMutex;
QVector<HVao> m_abandonedVaos;
@@ -384,6 +398,18 @@ private:
QMetaObject::Connection m_contextConnection;
RendererCache m_cache;
+
+ RenderBarrierJobPtr m_readRenderQueueSizeBarrierJob;
+ RenderBarrierJobPtr m_beginDrawingBarrierJob;
+ RenderBarrierJobPtr m_updateGLResourcesBarrierJob;
+ RenderBarrierJobPtr m_prepareCommandSubmissionBarrierJob;
+ RenderBarrierJobPtr m_endDrawingBarrierJob;
+
+ QAtomicInt m_willRenderPromise;
+ QSemaphore m_rendererReadySemaphore;
+ QSemaphore m_renderJobsReadySemaphore;
+
+ QVector<QSharedPointer<SurfaceLocker>> m_surfaceLockers;
};
} // namespace Render
diff --git a/src/render/backend/renderqueue.cpp b/src/render/backend/renderqueue.cpp
index 2fa1cb7d2..db75558a4 100644
--- a/src/render/backend/renderqueue.cpp
+++ b/src/render/backend/renderqueue.cpp
@@ -90,7 +90,6 @@ bool RenderQueue::queueRenderView(RenderView *renderView, uint submissionOrderIn
Q_ASSERT(!m_noRender);
m_currentWorkQueue[submissionOrderIndex] = renderView;
++m_currentRenderViewCount;
- Q_ASSERT(m_currentRenderViewCount <= m_targetRenderViewCount);
return isFrameQueueComplete();
}
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index 055c14143..84de728d4 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -148,16 +148,16 @@ static QRectF resolveViewport(const QRectF &fractionalViewport, const QSize &sur
fractionalViewport.height() * surfaceSize.height());
}
-static QMatrix4x4 getProjectionMatrix(const CameraLens *lens)
+static Matrix4x4 getProjectionMatrix(const CameraLens *lens)
{
if (!lens)
qWarning() << "[Qt3D Renderer] No Camera Lens found. Add a CameraSelector to your Frame Graph or make sure that no entities will be rendered.";
- return lens ? lens->projection() : QMatrix4x4();
+ return lens ? lens->projection() : Matrix4x4();
}
UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standardUniformType,
Entity *entity,
- const QMatrix4x4 &model) const
+ const Matrix4x4 &model) const
{
switch (standardUniformType) {
case ModelMatrix:
@@ -182,24 +182,26 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
case InverseModelViewMatrix:
return UniformValue((m_data.m_viewMatrix * model).inverted());
case InverseViewProjectionMatrix: {
- const QMatrix4x4 viewProjectionMatrix = getProjectionMatrix(m_data.m_renderCameraLens) * m_data.m_viewMatrix;
+ const Matrix4x4 viewProjectionMatrix = getProjectionMatrix(m_data.m_renderCameraLens) * m_data.m_viewMatrix;
return UniformValue(viewProjectionMatrix.inverted());
}
case InverseModelViewProjectionMatrix:
- return UniformValue((m_data.m_viewProjectionMatrix * model).inverted(0));
+ return UniformValue((m_data.m_viewProjectionMatrix * model).inverted());
case ModelNormalMatrix:
- return UniformValue(model.normalMatrix());
+ return UniformValue(convertToQMatrix4x4(model).normalMatrix());
case ModelViewNormalMatrix:
- return UniformValue((m_data.m_viewMatrix * model).normalMatrix());
+ return UniformValue(convertToQMatrix4x4(m_data.m_viewMatrix * model).normalMatrix());
case ViewportMatrix: {
QMatrix4x4 viewportMatrix;
+ // TO DO: Implement on Matrix4x4
viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize));
- return UniformValue(viewportMatrix);
+ return UniformValue(Matrix4x4(viewportMatrix));
}
case InverseViewportMatrix: {
QMatrix4x4 viewportMatrix;
+ // TO DO: Implement on Matrix4x4
viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize));
- return UniformValue(viewportMatrix.inverted());
+ return UniformValue(Matrix4x4(viewportMatrix.inverted()));
}
case AspectRatio:
return float(m_surfaceSize.width()) / float(m_surfaceSize.height());
@@ -518,20 +520,6 @@ void RenderView::setRenderer(Renderer *renderer)
m_manager = renderer->nodeManagers();
}
-class LightSourceCompare
-{
-public:
- LightSourceCompare(Entity *node) { p = node->worldBoundingVolume()->center(); }
- bool operator()(const LightSource &a, const LightSource &b) const {
- const float distA = p.distanceToPoint(a.entity->worldBoundingVolume()->center());
- const float distB = p.distanceToPoint(b.entity->worldBoundingVolume()->center());
- return distA < distB;
- }
-
-private:
- QVector3D p;
-};
-
void RenderView::addClearBuffers(const ClearBuffers *cb) {
QClearBuffers::BufferTypeFlags type = cb->type();
@@ -603,7 +591,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
// Project the camera-to-object-center vector onto the camera
// view vector. This gives a depth value suitable as the key
// for BackToFront sorting.
- command->m_depth = QVector3D::dotProduct(entity->worldBoundingVolume()->center() - m_data.m_eyePos, m_data.m_eyeViewDir);
+ command->m_depth = Vector3D::dotProduct(entity->worldBoundingVolume()->center() - m_data.m_eyePos, m_data.m_eyeViewDir);
command->m_geometry = geometryHandle;
command->m_geometryRenderer = geometryRendererHandle;
@@ -629,8 +617,15 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
// Replace with more sophisticated mechanisms later.
// Copy vector so that we can sort it concurrently and we only want to sort the one for the current command
QVector<LightSource> lightSources = m_lightSources;
- if (lightSources.size() > 1)
- std::sort(lightSources.begin(), lightSources.end(), LightSourceCompare(entity));
+ if (lightSources.size() > 1) {
+ const Vector3D entityCenter = entity->worldBoundingVolume()->center();
+ std::sort(lightSources.begin(), lightSources.end(),
+ [&] (const LightSource &a, const LightSource &b) {
+ const float distA = entityCenter.distanceToPoint(a.entity->worldBoundingVolume()->center());
+ const float distB = entityCenter.distanceToPoint(b.entity->worldBoundingVolume()->center());
+ return distA < distB;
+ });
+ }
ParameterInfoList globalParameters = passData.parameterInfo;
// setShaderAndUniforms can initialize a localData
@@ -653,6 +648,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
const QVector<Qt3DCore::QNodeId> attributeIds = geometry->attributes();
for (Qt3DCore::QNodeId attributeId : attributeIds) {
Attribute *attribute = m_manager->attributeManager()->lookupResource(attributeId);
+ Q_ASSERT(attribute != nullptr);
if (attribute->attributeType() == QAttribute::IndexAttribute)
indexAttribute = attribute;
else if (command->m_attributes.contains(attribute->nameId()))
@@ -755,21 +751,21 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
void RenderView::updateMatrices()
{
if (m_data.m_renderCameraNode && m_data.m_renderCameraLens && m_data.m_renderCameraLens->isEnabled()) {
- const QMatrix4x4 cameraWorld = *(m_data.m_renderCameraNode->worldTransform());
+ const Matrix4x4 cameraWorld = *(m_data.m_renderCameraNode->worldTransform());
setViewMatrix(m_data.m_renderCameraLens->viewMatrix(cameraWorld));
setViewProjectionMatrix(m_data.m_renderCameraLens->projection() * viewMatrix());
//To get the eyePosition of the camera, we need to use the inverse of the
//camera's worldTransform matrix.
- const QMatrix4x4 inverseWorldTransform = viewMatrix().inverted();
- const QVector3D eyePosition(inverseWorldTransform.column(3));
+ const Matrix4x4 inverseWorldTransform = viewMatrix().inverted();
+ const Vector3D eyePosition(inverseWorldTransform.column(3));
setEyePosition(eyePosition);
// Get the viewing direction of the camera. Use the normal matrix to
// ensure non-uniform scale works too.
- QMatrix3x3 normalMat = m_data.m_viewMatrix.normalMatrix();
+ const QMatrix3x3 normalMat = convertToQMatrix4x4(m_data.m_viewMatrix).normalMatrix();
// dir = normalize(QVector3D(0, 0, -1) * normalMat)
- setEyeViewDirection(QVector3D(-normalMat(2, 0), -normalMat(2, 1), -normalMat(2, 2)).normalized());
+ setEyeViewDirection(Vector3D(-normalMat(2, 0), -normalMat(2, 1), -normalMat(2, 2)).normalized());
}
}
@@ -780,14 +776,19 @@ void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, c
// ShaderData/Buffers would be handled as UBO/SSBO and would therefore
// not be in the default uniform block
if (value.valueType() == UniformValue::NodeId) {
- const Qt3DCore::QNodeId texId = *value.constData<Qt3DCore::QNodeId>();
- const Texture *tex = m_manager->textureManager()->lookupResource(texId);
- if (tex != nullptr) {
- uniformPack.setTexture(nameId, texId);
- UniformValue::Texture textureValue;
- textureValue.nodeId = texId;
- uniformPack.setUniform(nameId, UniformValue(textureValue));
+ const Qt3DCore::QNodeId *nodeIds = value.constData<Qt3DCore::QNodeId>();
+
+ const int uniformArraySize = value.byteSize() / sizeof(Qt3DCore::QNodeId);
+ for (int i = 0; i < uniformArraySize; ++i) {
+ const Qt3DCore::QNodeId texId = nodeIds[i];
+ const Texture *tex = m_manager->textureManager()->lookupResource(texId);
+ if (tex != nullptr)
+ uniformPack.setTexture(nameId, i, texId);
}
+
+ UniformValue textureValue(uniformArraySize * sizeof(int), UniformValue::TextureValue);
+ std::fill(textureValue.data<int>(), textureValue.data<int>() + uniformArraySize, -1);
+ uniformPack.setUniform(nameId, textureValue);
} else {
uniformPack.setUniform(nameId, value);
}
@@ -797,7 +798,7 @@ void RenderView::setStandardUniformValue(ShaderParameterPack &uniformPack,
int glslNameId,
int nameId,
Entity *entity,
- const QMatrix4x4 &worldTransform) const
+ const Matrix4x4 &worldTransform) const
{
uniformPack.setUniform(glslNameId, standardUniformValue(ms_standardUniformSetters[nameId], entity, worldTransform));
}
@@ -963,7 +964,7 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
!shaderStorageBlockNamesIds.isEmpty() || !attributeNamesIds.isEmpty()) {
// Set default standard uniforms without bindings
- QMatrix4x4 worldTransform = *(entity->worldTransform());
+ const Matrix4x4 worldTransform = *(entity->worldTransform());
for (const int uniformNameId : uniformNamesIds) {
if (ms_standardUniformSetters.contains(uniformNameId))
setStandardUniformValue(command->m_parameterPack, uniformNameId, uniformNameId, entity, worldTransform);
@@ -1010,7 +1011,7 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
if (lightIdx == MAX_LIGHTS)
break;
Entity *lightEntity = lightSource.entity;
- const QVector3D worldPos = lightEntity->worldBoundingVolume()->center();
+ const Vector3D worldPos = lightEntity->worldBoundingVolume()->center();
for (Light *light : lightSource.lights) {
if (!light->isEnabled())
continue;
@@ -1025,13 +1026,13 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
// Note: implicit conversion of values to UniformValue
setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[lightIdx], worldPos);
setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[lightIdx], int(QAbstractLight::PointLight));
- setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[lightIdx], QVector3D(1.0f, 1.0f, 1.0f));
+ setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[lightIdx], Vector3D(1.0f, 1.0f, 1.0f));
setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[lightIdx], 0.5f);
// There is no risk in doing that even if multithreaded
// since we are sure that a shaderData is unique for a given light
// and won't ever be referenced as a Component either
- QMatrix4x4 *worldTransform = lightEntity->worldTransform();
+ Matrix4x4 *worldTransform = lightEntity->worldTransform();
if (worldTransform)
shaderData->updateWorldTransform(*worldTransform);
@@ -1046,9 +1047,9 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
// If no active light sources and no environment light, add a default light
if (activeLightSources.isEmpty() && !environmentLight) {
// Note: implicit conversion of values to UniformValue
- setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[0], QVector3D(10.0f, 10.0f, 0.0f));
+ setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[0], Vector3D(10.0f, 10.0f, 0.0f));
setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[0], int(QAbstractLight::PointLight));
- setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[0], QVector3D(1.0f, 1.0f, 1.0f));
+ setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[0], Vector3D(1.0f, 1.0f, 1.0f));
setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[0], 0.5f);
}
diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h
index b684cbb85..cb3c74917 100644
--- a/src/render/backend/renderview_p.h
+++ b/src/render/backend/renderview_p.h
@@ -67,6 +67,7 @@
#include <Qt3DRender/private/qblitframebuffer_p.h>
#include <Qt3DCore/private/qframeallocator_p.h>
+#include <Qt3DRender/private/aligned_malloc_p.h>
// TODO: Move out once this is all refactored
#include <Qt3DRender/private/renderviewjobutils_p.h>
@@ -98,14 +99,14 @@ typedef QPair<QString, ActivePropertyContent > ActiveProperty;
struct Q_AUTOTEST_EXPORT Plane
{
- explicit Plane(const QVector4D &planeEquation)
+ explicit Plane(const Vector4D &planeEquation)
: planeEquation(planeEquation)
- , normal(planeEquation.toVector3D().normalized())
- , d(planeEquation.w() / planeEquation.toVector3D().length())
+ , normal(Vector3D(planeEquation).normalized())
+ , d(planeEquation.w() / Vector3D(planeEquation).length())
{}
- const QVector4D planeEquation;
- const QVector3D normal;
+ const Vector4D planeEquation;
+ const Vector3D normal;
const float d;
};
@@ -136,6 +137,8 @@ public:
RenderView();
~RenderView();
+ QT3D_ALIGNED_MALLOC_AND_FREE()
+
// TODO: Add a way to specify a sort predicate for the RenderCommands
void sort();
@@ -153,17 +156,17 @@ public:
inline void setRenderCameraEntity(Entity *renderCameraNode) Q_DECL_NOTHROW { m_data.m_renderCameraNode = renderCameraNode; }
inline Entity *renderCameraEntity() const Q_DECL_NOTHROW { return m_data.m_renderCameraNode; }
- inline void setViewMatrix(const QMatrix4x4 &viewMatrix) Q_DECL_NOTHROW { m_data.m_viewMatrix = viewMatrix; }
- inline QMatrix4x4 viewMatrix() const Q_DECL_NOTHROW { return m_data.m_viewMatrix; }
+ inline void setViewMatrix(const Matrix4x4 &viewMatrix) Q_DECL_NOTHROW { m_data.m_viewMatrix = viewMatrix; }
+ inline Matrix4x4 viewMatrix() const Q_DECL_NOTHROW { return m_data.m_viewMatrix; }
- inline void setViewProjectionMatrix(const QMatrix4x4 &viewProjectionMatrix) Q_DECL_NOTHROW { m_data.m_viewProjectionMatrix = viewProjectionMatrix; }
- inline QMatrix4x4 viewProjectionMatrix() const Q_DECL_NOTHROW { return m_data.m_viewProjectionMatrix; }
+ inline void setViewProjectionMatrix(const Matrix4x4 &viewProjectionMatrix) Q_DECL_NOTHROW { m_data.m_viewProjectionMatrix = viewProjectionMatrix; }
+ inline Matrix4x4 viewProjectionMatrix() const Q_DECL_NOTHROW { return m_data.m_viewProjectionMatrix; }
- inline void setEyePosition(const QVector3D &eyePos) Q_DECL_NOTHROW { m_data.m_eyePos = eyePos; }
- inline QVector3D eyePosition() const Q_DECL_NOTHROW { return m_data.m_eyePos; }
+ inline void setEyePosition(const Vector3D &eyePos) Q_DECL_NOTHROW { m_data.m_eyePos = eyePos; }
+ inline Vector3D eyePosition() const Q_DECL_NOTHROW { return m_data.m_eyePos; }
- inline void setEyeViewDirection(const QVector3D &dir) Q_DECL_NOTHROW { m_data.m_eyeViewDir = dir; }
- inline QVector3D eyeViewDirection() const Q_DECL_NOTHROW { return m_data.m_eyeViewDir; }
+ inline void setEyeViewDirection(const Vector3D &dir) Q_DECL_NOTHROW { m_data.m_eyeViewDir = dir; }
+ inline Vector3D eyeViewDirection() const Q_DECL_NOTHROW { return m_data.m_eyeViewDir; }
inline void appendLayerFilter(const Qt3DCore::QNodeId layerFilterId) Q_DECL_NOTHROW { m_data.m_layerFilterIds.push_back(layerFilterId); }
inline Qt3DCore::QNodeIdVector layerFilters() const Q_DECL_NOTHROW { return m_data.m_layerFilterIds; }
@@ -260,12 +263,12 @@ public:
Entity *m_renderCameraNode;
const TechniqueFilter *m_techniqueFilter;
const RenderPassFilter *m_passFilter;
- QMatrix4x4 m_viewMatrix;
- QMatrix4x4 m_viewProjectionMatrix;
+ Matrix4x4 m_viewMatrix;
+ Matrix4x4 m_viewProjectionMatrix;
Qt3DCore::QNodeIdVector m_layerFilterIds;
QVector<Qt3DRender::QSortPolicy::SortType> m_sortingTypes;
- QVector3D m_eyePos;
- QVector3D m_eyeViewDir;
+ Vector3D m_eyePos;
+ Vector3D m_eyeViewDir;
Qt3DCore::QNodeIdVector m_proximityFilterIds;
};
@@ -285,7 +288,6 @@ private:
Entity *entity,
const QVector<LightSource> &activeLightSources,
EnvironmentLight *environmentLight) const;
-
mutable QThreadStorage<UniformBlockValueBuilder*> m_localData;
Qt3DCore::QNodeId m_renderCaptureNodeId;
@@ -360,14 +362,14 @@ private:
UniformValue standardUniformValue(StandardUniform standardUniformType,
Entity *entity,
- const QMatrix4x4 &model) const;
+ const Matrix4x4 &model) const;
void setUniformValue(ShaderParameterPack &uniformPack, int nameId, const UniformValue &value) const;
void setStandardUniformValue(ShaderParameterPack &uniformPack,
int glslNameId,
int nameId,
Entity *entity,
- const QMatrix4x4 &worldTransform) const;
+ const Matrix4x4 &worldTransform) const;
void setUniformBlockValue(ShaderParameterPack &uniformPack,
Shader *shader,
const ShaderUniformBlock &block,
diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp
index 0682018fc..495b666f5 100644
--- a/src/render/backend/renderviewbuilder.cpp
+++ b/src/render/backend/renderviewbuilder.cpp
@@ -39,6 +39,8 @@
#include "renderviewbuilder_p.h"
+#include <Qt3DRender/private/renderbarrierjob_p.h>
+
#include <QThread>
QT_BEGIN_NAMESPACE
@@ -81,9 +83,6 @@ public:
// Sort the commands
rv->sort();
-
- // Enqueue our fully populated RenderView with the RenderThread
- m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex());
}
private:
@@ -125,13 +124,15 @@ public:
const FilterLayerEntityJobPtr &filterEntityByLayerJob,
const FilterProximityDistanceJobPtr &filterProximityJob,
const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs,
- const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs)
+ const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs,
+ Renderer *renderer)
: m_renderViewJob(renderViewJob)
, m_frustumCullingJob(frustumCullingJob)
, m_filterEntityByLayerJob(filterEntityByLayerJob)
, m_filterProximityJob(filterProximityJob)
, m_materialGathererJobs(materialGathererJobs)
, m_renderViewBuilderJobs(renderViewBuilderJobs)
+ , m_renderer(renderer)
{}
void operator()()
@@ -157,6 +158,9 @@ public:
// Set whether frustum culling is enabled or not
m_frustumCullingJob->setActive(rv->frustumCulling());
+
+ // Enqueue RenderView with the renderer
+ m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex());
}
private:
@@ -166,6 +170,7 @@ private:
FilterProximityDistanceJobPtr m_filterProximityJob;
QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs;
+ Renderer *m_renderer;
};
class SyncRenderCommandBuilding
@@ -355,7 +360,7 @@ RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int rende
, m_lightGathererJob(Render::LightGathererPtr::create())
, m_renderableEntityFilterJob(RenderableEntityFilterPtr::create())
, m_computableEntityFilterJob(ComputableEntityFilterPtr::create())
- , m_frustumCullingJob(Render::FrustumCullingJobPtr::create())
+ , m_frustumCullingJob(new Render::FrustumCullingJob())
, m_syncFrustumCullingJob(SynchronizerJobPtr::create(SyncFrustumCulling(m_renderViewJob, m_frustumCullingJob), JobTypes::SyncFrustumCulling))
, m_setClearDrawBufferIndexJob(SynchronizerJobPtr::create(SetClearDrawBufferIndex(m_renderViewJob), JobTypes::ClearBufferDrawIndex))
, m_syncFilterEntityByLayerJob()
@@ -519,7 +524,8 @@ void RenderViewBuilder::prepareJobs()
m_filterEntityByLayerJob,
m_filterProximityJob,
m_materialGathererJobs,
- m_renderViewBuilderJobs),
+ m_renderViewBuilderJobs,
+ m_renderer),
JobTypes::SyncRenderViewInitialization);
}
@@ -545,11 +551,13 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
m_setClearDrawBufferIndexJob->addDependency(m_syncRenderViewInitializationJob);
+ m_renderer->readRenderQueueSizeBarrierJob()->addDependency(m_syncRenderViewInitializationJob);
m_syncRenderViewInitializationJob->addDependency(m_renderViewJob);
m_filterProximityJob->addDependency(m_renderer->expandBoundingVolumeJob());
m_filterProximityJob->addDependency(m_syncRenderViewInitializationJob);
+ m_syncRenderCommandBuildingJob->addDependency(m_renderer->updateGLResourcesBarrierJob());
m_syncRenderCommandBuildingJob->addDependency(m_syncRenderViewInitializationJob);
m_syncRenderCommandBuildingJob->addDependency(m_renderableEntityFilterJob);
m_syncRenderCommandBuildingJob->addDependency(m_computableEntityFilterJob);
@@ -558,10 +566,15 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
m_syncRenderCommandBuildingJob->addDependency(m_frustumCullingJob);
for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) {
+ renderViewCommandBuilder->addDependency(m_renderer->updateSkinningPaletteJob());
+ renderViewCommandBuilder->addDependency(m_renderer->updateWorldBoundingVolumeJob());
+ renderViewCommandBuilder->addDependency(m_renderer->updateShaderDataTransformJob());
renderViewCommandBuilder->addDependency(m_syncRenderCommandBuildingJob);
+
m_syncRenderViewCommandBuildersJob->addDependency(renderViewCommandBuilder);
}
+ m_renderer->prepareCommandSubmissionBarrierJob()->addDependency(m_syncRenderViewCommandBuildersJob);
m_renderer->frameCleanupJob()->addDependency(m_syncRenderViewCommandBuildersJob);
m_renderer->frameCleanupJob()->addDependency(m_setClearDrawBufferIndexJob);
diff --git a/src/render/backend/segmentsvisitor.cpp b/src/render/backend/segmentsvisitor.cpp
index 96e2b3b6c..a3a5d059c 100644
--- a/src/render/backend/segmentsvisitor.cpp
+++ b/src/render/backend/segmentsvisitor.cpp
@@ -86,7 +86,7 @@ void traverseSegmentsIndexed(Index *indices,
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
uint ndx[2];
- QVector3D abc[2];
+ Vector3D abc[2];
while (i < indexInfo.count) {
for (uint u = 0; u < 2; ++u) {
ndx[u] = indices[i + u];
@@ -112,7 +112,7 @@ void traverseSegments(Vertex *vertices,
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
uint ndx[2];
- QVector3D abc[2];
+ Vector3D abc[2];
while (i < vertexInfo.count) {
for (uint u = 0; u < 2; ++u) {
ndx[u] = (i + u);
@@ -139,7 +139,7 @@ void traverseSegmentStripIndexed(Index *indices,
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
uint ndx[2];
- QVector3D abc[2];
+ Vector3D abc[2];
ndx[0] = indices[0];
uint idx = ndx[0] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j)
@@ -180,7 +180,7 @@ void traverseSegmentStrip(Vertex *vertices,
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
uint ndx[2];
- QVector3D abc[2];
+ Vector3D abc[2];
ndx[0] = i;
uint idx = ndx[0] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j)
@@ -218,7 +218,7 @@ void traverseSegmentAdjacencyIndexed(Index *indices,
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
uint ndx[2];
- QVector3D abc[2];
+ Vector3D abc[2];
while (i < n) {
for (uint u = 0; u < 2; ++u) {
ndx[u] = indices[i + u];
@@ -245,7 +245,7 @@ void traverseSegmentAdjacency(Vertex *vertices,
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
uint ndx[2];
- QVector3D abc[2];
+ Vector3D abc[2];
while (i < n) {
for (uint u = 0; u < 2; ++u) {
ndx[u] = (i + u);
diff --git a/src/render/backend/segmentsvisitor_p.h b/src/render/backend/segmentsvisitor_p.h
index 21867b0d5..cd5df1268 100644
--- a/src/render/backend/segmentsvisitor_p.h
+++ b/src/render/backend/segmentsvisitor_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DCore/private/vector3d_p.h>
QT_BEGIN_NAMESPACE
@@ -75,8 +76,8 @@ public:
void apply(const Qt3DCore::QEntity *entity);
void apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id);
- virtual void visit(uint andx, const QVector3D &a,
- uint bndx, const QVector3D &b) = 0;
+ virtual void visit(uint andx, const Vector3D &a,
+ uint bndx, const Vector3D &b) = 0;
protected:
NodeManagers *m_manager;
diff --git a/src/render/backend/shaderparameterpack.cpp b/src/render/backend/shaderparameterpack.cpp
index 01a977aee..f78e45a5e 100644
--- a/src/render/backend/shaderparameterpack.cpp
+++ b/src/render/backend/shaderparameterpack.cpp
@@ -65,17 +65,17 @@ void ShaderParameterPack::setUniform(const int glslNameId, const UniformValue &v
m_uniforms.insert(glslNameId, val);
}
-void ShaderParameterPack::setTexture(const int glslNameId, Qt3DCore::QNodeId texId)
+void ShaderParameterPack::setTexture(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId texId)
{
for (int t=0; t<m_textures.size(); ++t) {
- if (m_textures[t].glslNameId != glslNameId)
+ if (m_textures[t].glslNameId != glslNameId || m_textures[t].uniformArrayIndex != uniformArrayIndex)
continue;
m_textures[t].texId = texId;
return;
}
- m_textures.append(NamedTexture(glslNameId, texId));
+ m_textures.append(NamedTexture(glslNameId, texId, uniformArrayIndex));
}
// Contains Uniform Block Index and QNodeId of the ShaderData (UBO)
diff --git a/src/render/backend/shaderparameterpack_p.h b/src/render/backend/shaderparameterpack_p.h
index c0ab05e57..abd63a187 100644
--- a/src/render/backend/shaderparameterpack_p.h
+++ b/src/render/backend/shaderparameterpack_p.h
@@ -96,7 +96,7 @@ public:
~ShaderParameterPack();
void setUniform(const int glslNameId, const UniformValue &val);
- void setTexture(const int glslNameId, Qt3DCore::QNodeId id);
+ void setTexture(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId id);
void setUniformBuffer(BlockToUBO blockToUBO);
void setShaderStorageBuffer(BlockToSSBO blockToSSBO);
void setSubmissionUniform(const ShaderUniform &uniform);
@@ -108,13 +108,15 @@ public:
struct NamedTexture
{
NamedTexture() {}
- NamedTexture(const int nm, Qt3DCore::QNodeId t)
- : glslNameId(nm)
- , texId(t)
+ NamedTexture(const int glslNameId, Qt3DCore::QNodeId texId, int uniformArrayIndex)
+ : glslNameId(glslNameId)
+ , texId(texId)
+ , uniformArrayIndex(uniformArrayIndex)
{ }
int glslNameId;
Qt3DCore::QNodeId texId;
+ int uniformArrayIndex;
};
inline QVector<NamedTexture> textures() const { return m_textures; }
diff --git a/src/render/backend/transform.cpp b/src/render/backend/transform.cpp
index 636c2d103..20574d6f7 100644
--- a/src/render/backend/transform.cpp
+++ b/src/render/backend/transform.cpp
@@ -64,7 +64,7 @@ void Transform::cleanup()
m_rotation = QQuaternion();
m_scale = QVector3D();
m_translation = QVector3D();
- m_transformMatrix = QMatrix4x4();
+ m_transformMatrix = Matrix4x4();
QBackendNode::setEnabled(false);
}
@@ -78,7 +78,7 @@ void Transform::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &ch
updateMatrix();
}
-QMatrix4x4 Transform::transformMatrix() const
+Matrix4x4 Transform::transformMatrix() const
{
return m_transformMatrix;
}
@@ -125,7 +125,7 @@ void Transform::updateMatrix()
m.translate(m_translation);
m.rotate(m_rotation);
m.scale(m_scale);
- m_transformMatrix = m;
+ m_transformMatrix = Matrix4x4(m);
}
} // namespace Render
diff --git a/src/render/backend/transform_p.h b/src/render/backend/transform_p.h
index ce026da9d..8e3e9d639 100644
--- a/src/render/backend/transform_p.h
+++ b/src/render/backend/transform_p.h
@@ -54,7 +54,7 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <QtGui/qquaternion.h>
#include <QtGui/qvector3d.h>
-#include <QMatrix4x4>
+#include <Qt3DCore/private/matrix4x4_p.h>
QT_BEGIN_NAMESPACE
@@ -71,7 +71,7 @@ public:
Transform();
void cleanup();
- QMatrix4x4 transformMatrix() const;
+ Matrix4x4 transformMatrix() const;
QVector3D scale() const;
QQuaternion rotation() const;
QVector3D translation() const;
@@ -83,7 +83,7 @@ public:
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
- QMatrix4x4 m_transformMatrix;
+ Matrix4x4 m_transformMatrix;
QQuaternion m_rotation;
QVector3D m_scale;
QVector3D m_translation;
diff --git a/src/render/backend/triangleboundingvolume.cpp b/src/render/backend/triangleboundingvolume.cpp
index ca2d26897..be5206657 100644
--- a/src/render/backend/triangleboundingvolume.cpp
+++ b/src/render/backend/triangleboundingvolume.cpp
@@ -49,35 +49,35 @@ namespace Render {
// Note: a, b, c in clockwise order
// RealTime Collision Detection page 192
bool intersectsSegmentTriangle(const RayCasting::QRay3D &ray,
- const QVector3D &a,
- const QVector3D &b,
- const QVector3D &c,
- QVector3D &uvw,
+ const Vector3D &a,
+ const Vector3D &b,
+ const Vector3D &c,
+ Vector3D &uvw,
float &t)
{
- const QVector3D ab = b - a;
- const QVector3D ac = c - a;
- const QVector3D qp = (ray.origin() - ray.point(ray.distance()));
+ const Vector3D ab = b - a;
+ const Vector3D ac = c - a;
+ const Vector3D qp = (ray.origin() - ray.point(ray.distance()));
- const QVector3D n = QVector3D::crossProduct(ab, ac);
- const float d = QVector3D::dotProduct(qp, n);
+ const Vector3D n = Vector3D::crossProduct(ab, ac);
+ const float d = Vector3D::dotProduct(qp, n);
if (d <= 0.0f)
return false;
- const QVector3D ap = ray.origin() - a;
- t = QVector3D::dotProduct(ap, n);
+ const Vector3D ap = ray.origin() - a;
+ t = Vector3D::dotProduct(ap, n);
if (t < 0.0f || t > d)
return false;
- const QVector3D e = QVector3D::crossProduct(qp, ap);
- uvw.setY(QVector3D::dotProduct(ac, e));
+ const Vector3D e = Vector3D::crossProduct(qp, ap);
+ uvw.setY(Vector3D::dotProduct(ac, e));
if (uvw.y() < 0.0f || uvw.y() > d)
return false;
- uvw.setZ(-QVector3D::dotProduct(ab, e));
+ uvw.setZ(-Vector3D::dotProduct(ab, e));
if (uvw.z() < 0.0f || uvw.y() + uvw.z() > d)
return false;
@@ -99,7 +99,7 @@ TriangleBoundingVolume::TriangleBoundingVolume()
/*!
The vertices a, b, c are assumed to be in counter clockwise order.
*/
-TriangleBoundingVolume::TriangleBoundingVolume(Qt3DCore::QNodeId id, const QVector3D &a, const QVector3D &b, const QVector3D &c)
+TriangleBoundingVolume::TriangleBoundingVolume(Qt3DCore::QNodeId id, const Vector3D &a, const Vector3D &b, const Vector3D &c)
: QBoundingVolume()
, m_id(id)
, m_a(a)
@@ -112,10 +112,10 @@ Qt3DCore::QNodeId TriangleBoundingVolume::id() const
return m_id;
}
-bool TriangleBoundingVolume::intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const
+bool TriangleBoundingVolume::intersects(const RayCasting::QRay3D &ray, Vector3D *q, Vector3D *uvw) const
{
float t = 0.0f;
- QVector3D uvwr;
+ Vector3D uvwr;
const float intersected = intersectsSegmentTriangle(ray, m_c, m_b, m_a, uvwr, t);
if (intersected) {
@@ -132,41 +132,41 @@ TriangleBoundingVolume::Type TriangleBoundingVolume::type() const
return RayCasting::QBoundingVolume::Triangle;
}
-QVector3D TriangleBoundingVolume::a() const
+Vector3D TriangleBoundingVolume::a() const
{
return m_a;
}
-QVector3D TriangleBoundingVolume::b() const
+Vector3D TriangleBoundingVolume::b() const
{
return m_b;
}
-QVector3D TriangleBoundingVolume::c() const
+Vector3D TriangleBoundingVolume::c() const
{
return m_c;
}
-void TriangleBoundingVolume::setA(const QVector3D &a)
+void TriangleBoundingVolume::setA(const Vector3D &a)
{
m_a = a;
}
-void TriangleBoundingVolume::setB(const QVector3D &b)
+void TriangleBoundingVolume::setB(const Vector3D &b)
{
m_b = b;
}
-void TriangleBoundingVolume::setC(const QVector3D &c)
+void TriangleBoundingVolume::setC(const Vector3D &c)
{
m_c = c;
}
-TriangleBoundingVolume TriangleBoundingVolume::transformed(const QMatrix4x4 &mat) const
+TriangleBoundingVolume TriangleBoundingVolume::transformed(const Matrix4x4 &mat) const
{
- const QVector3D tA = mat * m_a;
- const QVector3D tB = mat * m_b;
- const QVector3D tC = mat * m_c;
+ const Vector3D tA = mat * m_a;
+ const Vector3D tB = mat * m_b;
+ const Vector3D tC = mat * m_c;
return TriangleBoundingVolume(id(), tA, tB, tC);
}
diff --git a/src/render/backend/triangleboundingvolume_p.h b/src/render/backend/triangleboundingvolume_p.h
index 4735a1522..a45a5ed7c 100644
--- a/src/render/backend/triangleboundingvolume_p.h
+++ b/src/render/backend/triangleboundingvolume_p.h
@@ -53,6 +53,7 @@
#include <Qt3DRender/private/qboundingvolume_p.h>
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DCore/private/matrix4x4_p.h>
#include <QVector3D>
QT_BEGIN_NAMESPACE
@@ -62,10 +63,10 @@ namespace Qt3DRender {
namespace Render {
Q_AUTOTEST_EXPORT bool intersectsSegmentTriangle(const RayCasting::QRay3D &ray,
- const QVector3D &a,
- const QVector3D &b,
- const QVector3D &c,
- QVector3D &uvw,
+ const Vector3D &a,
+ const Vector3D &b,
+ const Vector3D &c,
+ Vector3D &uvw,
float &t);
class Q_AUTOTEST_EXPORT TriangleBoundingVolume : public RayCasting::QBoundingVolume
@@ -73,25 +74,25 @@ class Q_AUTOTEST_EXPORT TriangleBoundingVolume : public RayCasting::QBoundingVol
public:
TriangleBoundingVolume();
explicit TriangleBoundingVolume(Qt3DCore::QNodeId id,
- const QVector3D &a,
- const QVector3D &b,
- const QVector3D &c);
+ const Vector3D &a,
+ const Vector3D &b,
+ const Vector3D &c);
Qt3DCore::QNodeId id() const final;
- bool intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const final;
- Type type() const final;
+ bool intersects(const RayCasting::QRay3D &ray, Vector3D *q, Vector3D *uvw) const final;
+ Type type() const final;
- QVector3D a() const;
- QVector3D b() const;
- QVector3D c() const;
+ Vector3D a() const;
+ Vector3D b() const;
+ Vector3D c() const;
- void setA(const QVector3D &a);
- void setB(const QVector3D &b);
- void setC(const QVector3D &c);
+ void setA(const Vector3D &a);
+ void setB(const Vector3D &b);
+ void setC(const Vector3D &c);
- TriangleBoundingVolume transformed(const QMatrix4x4 &mat) const;
+ TriangleBoundingVolume transformed(const Matrix4x4 &mat) const;
- inline TriangleBoundingVolume &transform(const QMatrix4x4 &mat)
+ inline TriangleBoundingVolume &transform(const Matrix4x4 &mat)
{
*this = transformed(mat);
return *this;
@@ -99,7 +100,7 @@ public:
private:
Qt3DCore::QNodeId m_id;
- QVector3D m_a, m_b, m_c;
+ Vector3D m_a, m_b, m_c;
};
} // namespace Render
diff --git a/src/render/backend/trianglesextractor.cpp b/src/render/backend/trianglesextractor.cpp
index e7a36dab3..2ddb425a0 100644
--- a/src/render/backend/trianglesextractor.cpp
+++ b/src/render/backend/trianglesextractor.cpp
@@ -68,7 +68,7 @@ QVector<RayCasting::QBoundingVolume *> TrianglesExtractor::extract(const Qt3DCor
return m_volumes;
}
-void TrianglesExtractor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c)
+void TrianglesExtractor::visit(uint andx, const Vector3D &a, uint bndx, const Vector3D &b, uint cndx, const Vector3D &c)
{
Q_UNUSED(andx); Q_UNUSED(bndx); Q_UNUSED(cndx);
m_volumes.push_back(new TriangleBoundingVolume(m_nodeId, a, b, c));
diff --git a/src/render/backend/trianglesextractor_p.h b/src/render/backend/trianglesextractor_p.h
index 857c4c638..df4c20466 100644
--- a/src/render/backend/trianglesextractor_p.h
+++ b/src/render/backend/trianglesextractor_p.h
@@ -71,9 +71,9 @@ public:
QVector<RayCasting::QBoundingVolume *> extract(const Qt3DCore::QNodeId id);
private:
- void visit(uint andx, const QVector3D &a,
- uint bndx, const QVector3D &b,
- uint cndx, const QVector3D &c) override;
+ void visit(uint andx, const Vector3D &a,
+ uint bndx, const Vector3D &b,
+ uint cndx, const Vector3D &c) override;
GeometryRenderer *m_renderer;
QVector<RayCasting::QBoundingVolume *> m_volumes;
diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp
index 57538c8d7..87ba7bde9 100644
--- a/src/render/backend/trianglesvisitor.cpp
+++ b/src/render/backend/trianglesvisitor.cpp
@@ -85,11 +85,11 @@ void traverseTrianglesIndexed(index *indices,
TrianglesVisitor* visitor)
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
- QVector3D abc[3];
+ Vector3D abc[3];
while (i < indexInfo.count) {
for (uint u = 0; u < 3; ++u) {
ndx[u] = indices[i + u];
@@ -111,11 +111,11 @@ void traverseTriangles(vertex *vertices,
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
- QVector3D abc[3];
+ Vector3D abc[3];
while (i < vertexInfo.count) {
for (uint u = 0; u < 3; ++u) {
ndx[u] = (i + u);
@@ -147,11 +147,11 @@ void traverseTriangleStripIndexed(index *indices,
TrianglesVisitor* visitor)
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
- QVector3D abc[3];
+ Vector3D abc[3];
while (i < indexInfo.count - 2) {
bool degenerate = false;
for (uint u = 0; u < 3; ++u) {
@@ -178,11 +178,11 @@ void traverseTriangleStrip(vertex *vertices,
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
- QVector3D abc[3];
+ Vector3D abc[3];
while (i < vertexInfo.count - 2) {
for (uint u = 0; u < 3; ++u) {
ndx[u] = (i + u);
@@ -204,11 +204,11 @@ void traverseTriangleFanIndexed(index *indices,
const BufferInfo &vertexInfo,
TrianglesVisitor* visitor)
{
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
- QVector3D abc[3];
+ Vector3D abc[3];
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[0][j] = vertices[static_cast<int>(indices[0]) * verticesStride + j];
@@ -234,11 +234,11 @@ void traverseTriangleFan(vertex *vertices,
const BufferInfo &vertexInfo,
TrianglesVisitor* visitor)
{
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
- QVector3D abc[3];
+ Vector3D abc[3];
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[0][j] = vertices[j];
@@ -268,11 +268,11 @@ void traverseTriangleAdjacencyIndexed(index *indices,
TrianglesVisitor* visitor)
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
- QVector3D abc[3];
+ Vector3D abc[3];
while (i < indexInfo.count) {
for (uint u = 0; u < 6; u += 2) {
ndx[u / 2] = indices[i + u];
@@ -294,11 +294,11 @@ void traverseTriangleAdjacency(Vertex *vertices,
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(Vertex) : maxVerticesDataSize;
uint ndx[3];
- QVector3D abc[3];
+ Vector3D abc[3];
while (i < vertexInfo.count) {
for (uint u = 0; u < 6; u += 2) {
ndx[u / 2] = (i + u);
@@ -313,10 +313,10 @@ void traverseTriangleAdjacency(Vertex *vertices,
}
template<typename Coordinate>
-QVector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint index)
+Vector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint index)
{
- const uint stride = info.byteStride / sizeof(Coordinate);
- QVector4D ret(0, 0, 0, 1.0f);
+ const uint stride = info.byteStride ? info.byteStride / sizeof(Coordinate) : info.dataSize;
+ Vector4D ret(0, 0, 0, 1.0f);
coordinates += stride * index;
for (uint e = 0; e < info.dataSize; ++e)
ret[e] = coordinates[e];
@@ -340,7 +340,7 @@ typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
}
-QVector4D readBuffer(const BufferInfo &info, uint index)
+Vector4D readBuffer(const BufferInfo &info, uint index)
{
switch (info.type) {
case QAttribute::Byte:
@@ -362,7 +362,7 @@ QVector4D readBuffer(const BufferInfo &info, uint index)
default:
break;
}
- return QVector4D();
+ return Vector4D();
}
template<typename Index, typename Visitor>
@@ -509,7 +509,7 @@ bool CoordinateReader::setGeometry(const GeometryRenderer *renderer, const QStri
return true;
}
-QVector4D CoordinateReader::getCoordinate(uint vertexIndex)
+Vector4D CoordinateReader::getCoordinate(uint vertexIndex)
{
return readBuffer(m_bufferInfo, vertexIndex);
}
diff --git a/src/render/backend/trianglesvisitor_p.h b/src/render/backend/trianglesvisitor_p.h
index 9428857ac..ee206f1c9 100644
--- a/src/render/backend/trianglesvisitor_p.h
+++ b/src/render/backend/trianglesvisitor_p.h
@@ -54,6 +54,8 @@
#include <Qt3DCore/qnodeid.h>
#include <Qt3DRender/QAttribute>
#include <Qt3DRender/private/bufferutils_p.h>
+#include <Qt3DCore/private/vector3d_p.h>
+#include <Qt3DCore/private/vector4d_p.h>
#include <private/qt3drender_global_p.h>
@@ -81,9 +83,9 @@ public:
void apply(const Qt3DCore::QEntity *entity);
void apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id);
- virtual void visit(uint andx, const QVector3D &a,
- uint bndx, const QVector3D &b,
- uint cndx, const QVector3D &c) = 0;
+ virtual void visit(uint andx, const Vector3D &a,
+ uint bndx, const Vector3D &b,
+ uint cndx, const Vector3D &c) = 0;
protected:
NodeManagers *m_manager;
@@ -102,7 +104,7 @@ public:
bool setGeometry(const GeometryRenderer *renderer, const QString &attributeName);
- QVector4D getCoordinate(uint vertexIndex);
+ Vector4D getCoordinate(uint vertexIndex);
protected:
NodeManagers *m_manager;
diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp
index 03220a219..41ee24967 100644
--- a/src/render/backend/uniform.cpp
+++ b/src/render/backend/uniform.cpp
@@ -47,10 +47,22 @@ namespace Render {
namespace {
const int qNodeIdTypeId = qMetaTypeId<Qt3DCore::QNodeId>();
+const int qVector3DTypeId = qMetaTypeId<Vector3D>();
+const int qVector4DTypeId = qMetaTypeId<Vector4D>();
+const int qMatrix4x4TypeId = qMetaTypeId<Matrix4x4>();
// glUniform*fv/glUniform*iv/glUniform*uiv -> only handles sizeof(float)/sizeof(int)
int byteSizeForMetaType(int type)
{
+ if (type == qMatrix4x4TypeId)
+ return sizeof(Matrix4x4);
+ if (type == qVector3DTypeId)
+ return sizeof(Vector3D);
+ if (type == qVector4DTypeId)
+ return sizeof(Vector4D);
+ if (type == qNodeIdTypeId)
+ return sizeof(Qt3DCore::QNodeId);
+
switch (type) {
case QMetaType::Bool:
case QMetaType::Int:
@@ -88,9 +100,9 @@ int byteSizeForMetaType(int type)
case QMetaType::QVector4D:
case QMetaType::QColor:
return 4 * sizeof(float);
-
case QMetaType::QMatrix4x4:
return 16 * sizeof(float);
+
default:
Q_UNREACHABLE();
return -1;
@@ -102,11 +114,22 @@ int byteSizeForMetaType(int type)
UniformValue UniformValue::fromVariant(const QVariant &variant)
{
// Texture/Buffer case
- if (variant.userType() == qNodeIdTypeId)
+ const int type = variant.userType();
+
+ if (type == qNodeIdTypeId)
return UniformValue(variant.value<Qt3DCore::QNodeId>());
+ if (type == qMatrix4x4TypeId)
+ return UniformValue(variant.value<Matrix4x4>());
+
+ if (type == qVector3DTypeId)
+ return UniformValue(variant.value<Vector3D>());
+
+ if (type == qVector4DTypeId)
+ return UniformValue(variant.value<Vector4D>());
+
UniformValue v;
- switch (variant.userType()) {
+ switch (type) {
case QMetaType::Bool:
v.data<bool>()[0] = variant.toBool();
break;
@@ -209,6 +232,11 @@ UniformValue UniformValue::fromVariant(const QVariant &variant)
break;
const int listEntryType = variants.first().userType();
+
+ // array of textures
+ if (listEntryType == qNodeIdTypeId)
+ v.m_valueType = NodeId;
+
const int stride = byteSizeForMetaType(listEntryType) / sizeof(float);
// Resize v.m_data
v.m_data.resize(stride * variants.size());
diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h
index e0d8fedeb..e31aaa609 100644
--- a/src/render/backend/uniform_p.h
+++ b/src/render/backend/uniform_p.h
@@ -53,6 +53,9 @@
#include <qt3drender_global.h>
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DCore/private/matrix4x4_p.h>
+#include <Qt3DCore/private/vector3d_p.h>
+#include <Qt3DCore/private/vector4d_p.h>
#include <QMatrix4x4>
#include <QVector2D>
@@ -111,11 +114,6 @@ public:
BufferValue
};
- struct Texture {
- int textureId = 0; // Set first so that glUniform1iv will work
- Qt3DCore::QNodeId nodeId;
- };
-
// UniformValue implicitely converts doubles to floats to ensure
// correct rendering behavior for the cases where Qt3D parameters created from
// a double or QVariant(double) are used to fill uniform values that in reality
@@ -135,8 +133,8 @@ public:
UniformValue(double d) : UniformValue() { data<float>()[0] = d; } // Double to float conversion
UniformValue(bool b) : UniformValue() { data<bool>()[0] = b; }
UniformValue(const QVector2D &vec2) : UniformValue() { memcpy(m_data.data(), &vec2, sizeof(QVector2D)); }
- UniformValue(const QVector3D &vec3) : UniformValue() { memcpy(m_data.data(), &vec3, sizeof(QVector3D)); }
- UniformValue(const QVector4D &vec4) : m_data(4) { memcpy(m_data.data(), &vec4, sizeof(QVector4D)); }
+ UniformValue(const Vector3D &vec3) : UniformValue() { memcpy(m_data.data(), &vec3, sizeof(Vector3D)); }
+ UniformValue(const Vector4D &vec4) : m_data(sizeof(Vector4D) / sizeof(float)) { memcpy(m_data.data(), &vec4, sizeof(Vector4D)); }
UniformValue(const QMatrix3x3 &mat33)
: m_data(9)
@@ -145,12 +143,22 @@ public:
memcpy(m_data.data(), mat33.constData(), 9 * sizeof(float));
}
+ // We don t want the QMatrix4x4 builder to use sizeof since QMatrix4x4 contains a type flag
+#if defined(__SSE2__) || defined(__AVX2__)
+ UniformValue(const Matrix4x4 &mat44)
+ : m_data(sizeof(Matrix4x4) / sizeof(float))
+ {
+ // Use constData because we want column-major layout
+ memcpy(m_data.data(), &mat44, sizeof(Matrix4x4));
+ }
+#else
UniformValue(const QMatrix4x4 &mat44)
: m_data(16)
{
// Use constData because we want column-major layout
memcpy(m_data.data(), mat44.constData(), 16 * sizeof(float));
}
+#endif
UniformValue(const QVector<QMatrix4x4> &v)
: m_data(16 * v.size())
@@ -164,6 +172,13 @@ public:
}
}
+ // Reserve data to be filled in later
+ UniformValue(int byteSize, ValueType valueType)
+ : m_data(byteSize / sizeof(float))
+ , m_valueType(valueType)
+ {
+ }
+
// For nodes which will later be replaced by a Texture or Buffer
UniformValue(Qt3DCore::QNodeId id)
: UniformValue()
@@ -172,14 +187,6 @@ public:
memcpy(m_data.data(), &id, sizeof(Qt3DCore::QNodeId));
}
- // For textures
- UniformValue(UniformValue::Texture t)
- : UniformValue()
- {
- m_valueType = TextureValue;
- memcpy(m_data.data(), &t, sizeof(Texture));
- }
-
ValueType valueType() const { return m_valueType; }
UniformType storedType() const { return m_storedType; }