diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2018-09-20 12:10:26 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2018-10-12 05:53:02 +0000 |
commit | 1739b90d6120e24065b0c85a8d293234c5d51787 (patch) | |
tree | 59efafef45767c9077ada0a8664d18e8bdf765c2 | |
parent | 12cd9f0a5e32038d860d688ac6fa5b4ae32cfe7b (diff) |
Implement WaitFence/SetFence handling into the renderer
Slightly reorganize jobs between jobs needed for rendering and jobs
that should run even when no rendering is required.
Change-Id: I02d262efd8cb46c71c40ac6dbcd4d1b25bb725e1
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
35 files changed, 957 insertions, 40 deletions
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h index f1bdca7be..f19db066c 100644 --- a/src/render/backend/abstractrenderer_p.h +++ b/src/render/backend/abstractrenderer_p.h @@ -153,6 +153,7 @@ public: virtual bool shouldRender() = 0; virtual void skipNextFrame() = 0; + virtual QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() = 0; virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0; virtual Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() = 0; virtual Qt3DCore::QAspectJobPtr rayCastingJob() = 0; diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index b62e2f3e0..eb219fd1e 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -72,6 +72,7 @@ #include <Qt3DRender/private/shaderdata_p.h> #include <Qt3DRender/private/handle_types_p.h> #include <Qt3DRender/private/glbuffer_p.h> +#include <Qt3DRender/private/glfence_p.h> #include <Qt3DRender/private/textureimage_p.h> #include <Qt3DRender/private/attribute_p.h> #include <Qt3DRender/private/geometry_p.h> @@ -317,6 +318,10 @@ class GLBufferManager : public Qt3DCore::QResourceManager< { }; +class GLFenceManager : public QHash<Qt3DCore::QNodeId, GLFence> +{ +}; + class TextureImageManager : public Qt3DCore::QResourceManager< TextureImage, Qt3DCore::QNodeId, diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp index 5db35082d..584ddd65c 100644 --- a/src/render/backend/nodemanagers.cpp +++ b/src/render/backend/nodemanagers.cpp @@ -85,6 +85,7 @@ NodeManagers::NodeManagers() , m_parameterManager(new ParameterManager()) , m_shaderDataManager(new ShaderDataManager()) , m_glBufferManager(new GLBufferManager()) + , m_glFenceManager(new GLFenceManager()) , m_bufferManager(new BufferManager()) , m_attributeManager(new AttributeManager()) , m_geometryManager(new GeometryManager()) @@ -128,6 +129,7 @@ NodeManagers::~NodeManagers() delete m_parameterManager; delete m_shaderDataManager; delete m_glBufferManager; + delete m_glFenceManager; delete m_textureImageManager; delete m_bufferManager; delete m_attributeManager; diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h index 9277d4385..2c4926894 100644 --- a/src/render/backend/nodemanagers_p.h +++ b/src/render/backend/nodemanagers_p.h @@ -87,6 +87,7 @@ class AttachmentManager; class ParameterManager; class ShaderDataManager; class GLBufferManager; +class GLFenceManager; class TextureImageManager; class FilterKeyManager; class FrameGraphManager; @@ -210,6 +211,7 @@ public: inline ParameterManager *parameterManager() const Q_DECL_NOEXCEPT { return m_parameterManager; } inline ShaderDataManager *shaderDataManager() const Q_DECL_NOEXCEPT { return m_shaderDataManager; } inline GLBufferManager *glBufferManager() const Q_DECL_NOEXCEPT { return m_glBufferManager; } + inline GLFenceManager *glFenceManager() const Q_DECL_NOEXCEPT { return m_glFenceManager; } inline TextureImageManager *textureImageManager() const Q_DECL_NOEXCEPT { return m_textureImageManager; } inline BufferManager *bufferManager() const Q_DECL_NOEXCEPT { return m_bufferManager; } inline AttributeManager *attributeManager() const Q_DECL_NOEXCEPT { return m_attributeManager; } @@ -255,6 +257,7 @@ private: ParameterManager *m_parameterManager; ShaderDataManager *m_shaderDataManager; GLBufferManager *m_glBufferManager; + GLFenceManager *m_glFenceManager; BufferManager *m_bufferManager; AttributeManager *m_attributeManager; GeometryManager *m_geometryManager; diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index ccec826ff..795073ce0 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -88,6 +88,8 @@ #include <Qt3DRender/qproximityfilter.h> #include <Qt3DRender/qshaderprogrambuilder.h> #include <Qt3DRender/qblitframebuffer.h> +#include <Qt3DRender/qsetfence.h> +#include <Qt3DRender/qwaitfence.h> #include <Qt3DCore/qarmature.h> #include <Qt3DCore/qjoint.h> #include <Qt3DCore/qskeletonloader.h> @@ -150,6 +152,8 @@ #include <Qt3DRender/private/joint_p.h> #include <Qt3DRender/private/loadskeletonjob_p.h> #include <Qt3DRender/private/proximityfilter_p.h> +#include <Qt3DRender/private/setfence_p.h> +#include <Qt3DRender/private/waitfence_p.h> #include <private/qrenderpluginfactory_p.h> #include <private/qrenderplugin_p.h> @@ -291,6 +295,8 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType<QMemoryBarrier>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::MemoryBarrier, QMemoryBarrier> >::create(m_renderer)); q->registerBackendType<QProximityFilter>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ProximityFilter, QProximityFilter> >::create(m_renderer)); q->registerBackendType<QBlitFramebuffer>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::BlitFramebuffer, QBlitFramebuffer> >::create(m_renderer)); + q->registerBackendType<QSetFence>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::SetFence, QSetFence> >::create(m_renderer)); + q->registerBackendType<QWaitFence>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::WaitFence, QWaitFence> >::create(m_renderer)); // Picking q->registerBackendType<QObjectPicker>(QSharedPointer<Render::NodeFunctor<Render::ObjectPicker, Render::ObjectPickerManager> >::create(m_renderer)); @@ -361,6 +367,8 @@ void QRenderAspectPrivate::unregisterBackendTypes() unregisterBackendType<QRenderCapture>(); unregisterBackendType<QBufferCapture>(); unregisterBackendType<QMemoryBarrier>(); + unregisterBackendType<QSetFence>(); + unregisterBackendType<QWaitFence>(); // Picking unregisterBackendType<QObjectPicker>(); @@ -502,11 +510,8 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) const QVector<QAspectJobPtr> geometryJobs = d->createGeometryRendererJobs(); jobs.append(geometryJobs); - - // Add all jobs to queue - // Note: the getter is also responsible for returning a job ready to run - jobs.append(d->m_renderer->pickBoundingVolumeJob()); - jobs.append(d->m_renderer->rayCastingJob()); + const QVector<QAspectJobPtr> preRenderingJobs = d->m_renderer->preRenderingJobs(); + jobs.append(preRenderingJobs); // Don't spawn any rendering jobs, if the renderer decides to skip this frame // Note: this only affects rendering jobs (jobs that load buffers, diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h index 2ae7d81ff..e776d452d 100644 --- a/src/render/jobs/job_common_p.h +++ b/src/render/jobs/job_common_p.h @@ -107,7 +107,8 @@ namespace JobTypes { SyncFilterEntityByLayer, SyncMaterialGatherer, UpdateLayerEntity, - SendTextureChangesToFrontend + SendTextureChangesToFrontend, + SendSetFenceHandlesToFrontend, }; } // JobTypes diff --git a/src/render/jobs/sendbuffercapturejob.cpp b/src/render/jobs/sendbuffercapturejob.cpp index eae26ba6c..8683ea9f2 100644 --- a/src/render/jobs/sendbuffercapturejob.cpp +++ b/src/render/jobs/sendbuffercapturejob.cpp @@ -67,6 +67,12 @@ void SendBufferCaptureJob::addRequest(QPair<Buffer *, QByteArray> request) m_pendingSendBufferCaptures.push_back(request); } +// Called by aspect thread jobs to execute (no concurrency at that point) +bool SendBufferCaptureJob::hasRequests() const +{ + return m_pendingSendBufferCaptures.size() > 0; +} + void SendBufferCaptureJob::run() { QMutexLocker locker(&m_mutex); diff --git a/src/render/jobs/sendbuffercapturejob_p.h b/src/render/jobs/sendbuffercapturejob_p.h index 771497e2f..854414ec6 100644 --- a/src/render/jobs/sendbuffercapturejob_p.h +++ b/src/render/jobs/sendbuffercapturejob_p.h @@ -75,6 +75,7 @@ public: ~SendBufferCaptureJob(); void addRequest(QPair<Buffer*, QByteArray> request); + bool hasRequests() const; void run() final; diff --git a/src/render/renderers/opengl/graphicshelpers/glfence_p.h b/src/render/renderers/opengl/graphicshelpers/glfence_p.h new file mode 100644 index 000000000..366065048 --- /dev/null +++ b/src/render/renderers/opengl/graphicshelpers/glfence_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GLFENCE_P_H +#define GLFENCE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGlobal> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +// GLsync is a pointer to a struct (unlike the rest of GL which used int ids) +// We cannot reference GLsync as it's only available since 3.2 We use FenceId +// to wrap that around and trust the GLHelpers will convert them accordingly. +using GLFence = void *; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + + +#endif // GLFENCE_P_H diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp index 2b2645505..f41f0f0f3 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp @@ -290,6 +290,33 @@ void GraphicsHelperES2::drawBuffer(GLenum mode) qWarning() << "glDrawBuffer is not supported with OpenGL ES 2"; } +void *GraphicsHelperES2::fenceSync() +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; + return nullptr; +} + +void GraphicsHelperES2::clientWaitSync(void *, GLuint64 ) +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; +} + +void GraphicsHelperES2::waitSync(void *) +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; +} + +bool GraphicsHelperES2::wasSyncSignaled(void *) +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; + return false; +} + +void GraphicsHelperES2::deleteSync(void *) +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; +} + void GraphicsHelperES2::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h index 1c6df41b6..8c8dd34e9 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h @@ -132,6 +132,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp index 34c1e7448..5e5d2e001 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp @@ -147,6 +147,26 @@ QT_BEGIN_NAMESPACE #define GL_READ_FRAMEBUFFER 0x8CA8 #endif +#ifndef GL_SIGNALED +#define GL_SIGNALED 0x9119 +#endif + +#ifndef GL_SYNC_STATUS +#define GL_SYNC_STATUS 0x9114 +#endif + +#ifndef GL_TIMEOUT_IGNORED +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#endif + +#ifndef GL_SYNC_GPU_COMMANDS_COMPLETE +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#endif + +#ifndef GL_SYNC_FLUSH_COMMANDS_BIT +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#endif + namespace Qt3DRender { namespace Render { @@ -307,6 +327,7 @@ bool GraphicsHelperES3::supportsFeature(GraphicsHelperInterface::Feature feature case BlitFramebuffer: case UniformBufferObject: case MapBuffer: + case Fences: return true; default: return false; @@ -439,6 +460,37 @@ uint GraphicsHelperES3::uniformByteSize(const ShaderUniform &description) return arrayStride ? rawByteSize * arrayStride : rawByteSize; } +void *GraphicsHelperES3::fenceSync() +{ + return m_extraFuncs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void GraphicsHelperES3::clientWaitSync(void *sync, GLuint64 nanoSecTimeout) +{ + m_extraFuncs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout); +} + +void GraphicsHelperES3::waitSync(void *sync) +{ + m_extraFuncs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED); +} + +bool GraphicsHelperES3::wasSyncSignaled(void *sync) +{ + GLint v; + m_extraFuncs->glGetSynciv(static_cast<GLsync>(sync), + GL_SYNC_STATUS, + sizeof(v), + nullptr, + &v); + return v == GL_SIGNALED; +} + +void GraphicsHelperES3::deleteSync(void *sync) +{ + m_extraFuncs->glDeleteSync(static_cast<GLsync>(sync)); +} + void GraphicsHelperES3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { m_extraFuncs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h index d4467cf7f..dc5cef10c 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h @@ -90,6 +90,12 @@ public: UniformType uniformTypeFromGLType(GLenum glType) override; uint uniformByteSize(const ShaderUniform &description) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + protected: QOpenGLExtraFunctions *m_extraFuncs = nullptr; }; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp index 6da8a9b6f..b6f3412b2 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp @@ -272,6 +272,33 @@ void GraphicsHelperGL2::drawBuffer(GLenum mode) m_funcs->glDrawBuffer(mode); } +void *GraphicsHelperGL2::fenceSync() +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; + return nullptr; +} + +void GraphicsHelperGL2::clientWaitSync(void *, GLuint64 ) +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; +} + +void GraphicsHelperGL2::waitSync(void *) +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; +} + +bool GraphicsHelperGL2::wasSyncSignaled(void *) +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; + return false; +} + +void GraphicsHelperGL2::deleteSync(void *) +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; +} + void GraphicsHelperGL2::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); @@ -412,6 +439,7 @@ bool GraphicsHelperGL2::supportsFeature(GraphicsHelperInterface::Feature feature case MRT: return (m_fboFuncs != nullptr); case TextureDimensionRetrieval: + case MapBuffer: return true; default: return false; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h index 2db75004f..b142b2623 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h @@ -132,6 +132,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp index a35c4e37f..5ff1a2ba5 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp @@ -334,6 +334,37 @@ void GraphicsHelperGL3_2::drawBuffer(GLenum mode) m_funcs->glDrawBuffer(mode); } +void *GraphicsHelperGL3_2::fenceSync() +{ + return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void GraphicsHelperGL3_2::clientWaitSync(void *sync, GLuint64 nanoSecTimeout) +{ + m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout); +} + +void GraphicsHelperGL3_2::waitSync(void *sync) +{ + m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED); +} + +bool GraphicsHelperGL3_2::wasSyncSignaled(void *sync) +{ + GLint v; + m_funcs->glGetSynciv(static_cast<GLsync>(sync), + GL_SYNC_STATUS, + sizeof(v), + nullptr, + &v); + return v == GL_SIGNALED; +} + +void GraphicsHelperGL3_2::deleteSync(void *sync) +{ + m_funcs->glDeleteSync(static_cast<GLsync>(sync)); +} + void GraphicsHelperGL3_2::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); @@ -481,6 +512,7 @@ bool GraphicsHelperGL3_2::supportsFeature(GraphicsHelperInterface::Feature featu case TextureDimensionRetrieval: case BindableFragmentOutputs: case BlitFramebuffer: + case Fences: return true; case Tessellation: return !m_tessFuncs.isNull(); diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h index 133295fd7..9e81345ad 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h @@ -134,6 +134,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp index b2512d84a..81081943d 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp @@ -330,6 +330,37 @@ void GraphicsHelperGL3_3::drawBuffer(GLenum mode) m_funcs->glDrawBuffer(mode); } +void *GraphicsHelperGL3_3::fenceSync() +{ + return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void GraphicsHelperGL3_3::clientWaitSync(void *sync, GLuint64 nanoSecTimeout) +{ + m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout); +} + +void GraphicsHelperGL3_3::waitSync(void *sync) +{ + m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED); +} + +bool GraphicsHelperGL3_3::wasSyncSignaled(void *sync) +{ + GLint v; + m_funcs->glGetSynciv(static_cast<GLsync>(sync), + GL_SYNC_STATUS, + sizeof(v), + nullptr, + &v); + return v == GL_SIGNALED; +} + +void GraphicsHelperGL3_3::deleteSync(void *sync) +{ + m_funcs->glDeleteSync(static_cast<GLsync>(sync)); +} + void GraphicsHelperGL3_3::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); @@ -477,6 +508,7 @@ bool GraphicsHelperGL3_3::supportsFeature(GraphicsHelperInterface::Feature featu case TextureDimensionRetrieval: case BindableFragmentOutputs: case BlitFramebuffer: + case Fences: return true; case Tessellation: return !m_tessFuncs.isNull(); diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h index 0ecdd3620..c480e5258 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h @@ -134,6 +134,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp index ce1b8ac2b..22cbf7428 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp @@ -400,6 +400,39 @@ void GraphicsHelperGL4::drawBuffer(GLenum mode) m_funcs->glDrawBuffer(mode); } +void *GraphicsHelperGL4::fenceSync() +{ + return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void GraphicsHelperGL4::clientWaitSync(void *sync, GLuint64 nanoSecTimeout) +{ + qDebug() << Q_FUNC_INFO << sync << static_cast<GLsync>(sync); + GLenum e = m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout); + qDebug() << e; +} + +void GraphicsHelperGL4::waitSync(void *sync) +{ + m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED); +} + +bool GraphicsHelperGL4::wasSyncSignaled(void *sync) +{ + GLint v = 0; + m_funcs->glGetSynciv(static_cast<GLsync>(sync), + GL_SYNC_STATUS, + sizeof(v), + nullptr, + &v); + return v == GL_SIGNALED; +} + +void GraphicsHelperGL4::deleteSync(void *sync) +{ + m_funcs->glDeleteSync(static_cast<GLsync>(sync)); +} + void GraphicsHelperGL4::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) { m_funcs->glUniform1fv(location, count, values); @@ -746,6 +779,8 @@ bool GraphicsHelperGL4::supportsFeature(GraphicsHelperInterface::Feature feature case DrawBuffersBlend: case BlitFramebuffer: case IndirectDrawing: + case MapBuffer: + case Fences: return true; default: return false; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h index 3020b16d8..da62f4212 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h @@ -132,6 +132,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h index e41325cb7..2a1688b7f 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h @@ -82,7 +82,8 @@ public: DrawBuffersBlend, BlitFramebuffer, IndirectDrawing, - MapBuffer + MapBuffer, + Fences }; enum FBOBindMode { @@ -155,6 +156,12 @@ public: virtual void readBuffer(GLenum mode) = 0; virtual void drawBuffer(GLenum mode) = 0; + virtual void *fenceSync() = 0; + virtual void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) = 0; + virtual void waitSync(void *sync) = 0; + virtual bool wasSyncSignaled(void *sync) = 0; + virtual void deleteSync(void *sync) = 0; + virtual void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) = 0; virtual void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) = 0; virtual void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) = 0; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri index 9b25be0eb..5c9479d2b 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri @@ -13,7 +13,8 @@ HEADERS += \ $$PWD/graphicshelpergl3_3_p.h \ $$PWD/graphicshelpergl4_p.h \ $$PWD/graphicshelpergl3_2_p.h \ - $$PWD/submissioncontext_p.h + $$PWD/submissioncontext_p.h \ + $$PWD/glfence_p.h SOURCES += \ $$PWD/graphicscontext.cpp \ diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp index e7ebf3322..7900db879 100644 --- a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp +++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp @@ -1258,6 +1258,33 @@ void SubmissionContext::clearStencilValue(int stencil) } } +GLFence SubmissionContext::fenceSync() +{ + return m_glHelper->fenceSync(); +} + +void SubmissionContext::clientWaitSync(GLFence sync, GLuint64 nanoSecTimeout) +{ + qDebug() << Q_FUNC_INFO << sync; + m_glHelper->clientWaitSync(sync, nanoSecTimeout); +} + +void SubmissionContext::waitSync(GLFence sync) +{ + qDebug() << Q_FUNC_INFO << sync; + m_glHelper->waitSync(sync); +} + +bool SubmissionContext::wasSyncSignaled(GLFence sync) +{ + return m_glHelper->wasSyncSignaled(sync); +} + +void SubmissionContext::deleteSync(GLFence sync) +{ + m_glHelper->deleteSync(sync); +} + // It will be easier if the QGraphicContext applies the QUniformPack // than the other way around bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h index d502a8b27..dbfaef148 100644 --- a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h +++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h @@ -59,6 +59,7 @@ #include <Qt3DRender/qattribute.h> #include <Qt3DRender/private/handle_types_p.h> #include <Qt3DRender/private/shadercache_p.h> +#include <Qt3DRender/private/glfence_p.h> QT_BEGIN_NAMESPACE @@ -163,6 +164,14 @@ public: void clearDepthValue(float depth); void clearStencilValue(int stencil); + + // Fences + GLFence fenceSync(); + void clientWaitSync(GLFence sync, GLuint64 nanoSecTimeout); + void waitSync(GLFence sync); + bool wasSyncSignaled(GLFence sync); + void deleteSync(GLFence sync); + private: void initialize(); diff --git a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp index 629e7e935..9dd7faacc 100644 --- a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp +++ b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp @@ -68,6 +68,7 @@ #include <Qt3DRender/private/techniquemanager_p.h> #include <Qt3DRender/private/memorybarrier_p.h> #include <Qt3DRender/private/blitframebuffer_p.h> +#include <Qt3DRender/private/waitfence_p.h> QT_BEGIN_NAMESPACE @@ -272,6 +273,17 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN break; } + case FrameGraphNode::WaitFence: { + const Render::WaitFence *waitFence = static_cast<const Render::WaitFence *>(node); + rv->appendWaitFence(waitFence->data()); + break; + } + + case FrameGraphNode::SetFence: { + rv->appendInsertFenceId(node->peerId()); + break; + } + default: // Should never get here qCWarning(Backend) << "Unhandled FrameGraphNode type"; diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index 79afda1cc..d71256484 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -91,6 +91,7 @@ #include <Qt3DRender/private/renderviewbuilder_p.h> #include <Qt3DRender/private/commandthread_p.h> #include <Qt3DRender/private/glcommands_p.h> +#include <Qt3DRender/private/setfence_p.h> #include <Qt3DRender/qcameralens.h> #include <Qt3DCore/private/qeventfilterservice_p.h> @@ -195,6 +196,7 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_vaoGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering)) , m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering)) , m_sendTextureChangesToFrontendJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { sendTextureChangesToFrontend(); }, JobTypes::SendTextureChangesToFrontend)) + , m_sendSetFenceHandlesToFrontendJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { sendSetFenceHandlesToFrontend(); }, JobTypes::SendSetFenceHandlesToFrontend)) , m_introspectShaderJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { reloadDirtyShaders(); }, JobTypes::DirtyShaderGathering)) , m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading)) , m_ownedContext(false) @@ -1194,6 +1196,22 @@ void Renderer::sendTextureChangesToFrontend() } } +// Executed in a job +void Renderer::sendSetFenceHandlesToFrontend() +{ + const QVector<QPair<Qt3DCore::QNodeId, GLFence>> updatedSetFence = std::move(m_updatedSetFences); + FrameGraphManager *fgManager = m_nodesManager->frameGraphManager(); + for (const auto &pair : updatedSetFence) { + FrameGraphNode *fgNode = fgManager->lookupNode(pair.first); + if (fgNode != nullptr) { // Node could have been deleted before we got a chance to notify it + Q_ASSERT(fgNode->nodeType() == FrameGraphNode::SetFence); + SetFence *setFenceNode = static_cast<SetFence *>(fgNode); + setFenceNode->setHandleType(QSetFence::OpenGLFenceId); + setFenceNode->setHandle(QVariant::fromValue(pair.second)); + } + } +} + // Render Thread (or QtQuick RenderThread when using Scene3D) // Scene3D: When using Scene3D rendering, we can't assume that when // updateGLResources is called, the resource handles points to still existing @@ -1207,6 +1225,25 @@ void Renderer::sendTextureChangesToFrontend() void Renderer::updateGLResources() { { + // Update active fence objects: + // - Destroy fences that have reached their signaled state + GLFenceManager *fenceManager = m_nodesManager->glFenceManager(); + const auto end = fenceManager->end(); + auto it = fenceManager->begin(); + while (it != end) { + const GLFence fence = it.value(); + if (m_submissionContext->wasSyncSignaled(fence)) { + // Fence was signaled, we delete it + // before removing the entry from the manager + m_submissionContext->deleteSync(fence); + it = fenceManager->erase(it); + } else { + ++it; + } + } + } + + { Profiling::GLTimeRecorder recorder(Profiling::BufferUpload); const QVector<HBuffer> dirtyBufferHandles = std::move(m_dirtyBuffers); for (const HBuffer &handle: dirtyBufferHandles) { @@ -1397,6 +1434,7 @@ void Renderer::cleanupTexture(Qt3DCore::QNodeId cleanedUpTextureId) glTextureManager->abandon(glTexture, cleanedUpTextureId); } +// Called by SubmitRenderView void Renderer::downloadGLBuffers() { lookForDownloadableBuffers(); @@ -1481,6 +1519,45 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren if (renderView->memoryBarrier() != QMemoryBarrier::None) m_submissionContext->memoryBarrier(renderView->memoryBarrier()); + + // Insert Fence into command stream if needed + const Qt3DCore::QNodeIdVector insertFenceIds = renderView->insertFenceIds(); + GLFenceManager *fenceManager = m_nodesManager->glFenceManager(); + for (const Qt3DCore::QNodeId insertFenceId : insertFenceIds) { + // If the fence is not in the manager, then it hasn't been inserted + // into the command stream yet. + if (fenceManager->find(insertFenceId) == fenceManager->end()) { + // Insert fence into command stream + GLFence glFence = m_submissionContext->fenceSync(); + // Record glFence + fenceManager->insert(insertFenceId, glFence); + // Add entry for notification changes to be sent + m_updatedSetFences.push_back({insertFenceId, glFence}); + } + // If it is in the manager, then it hasn't been signaled yet, + // nothing we can do but try at the next frame + } + + // Wait for fences if needed + const QVector<QWaitFenceData> waitFences = renderView->waitFences(); + for (const QWaitFenceData &waitFence : waitFences) { + // TO DO + if (waitFence.handleType != QWaitFence::OpenGLFenceId) { + qWarning() << "WaitFence handleType should be OpenGLFenceId when using the Qt 3D OpenGL renderer"; + continue; + } + GLFence fence = reinterpret_cast<GLFence>(waitFence.handle.value<qintptr>()); + if (fence == nullptr) + continue; + + if (waitFence.waitOnCPU) { + m_submissionContext->clientWaitSync(fence, + waitFence.timeout); + } else { + m_submissionContext->waitSync(fence); + } + } + // Note: the RenderStateSet is allocated once per RV if needed // and it contains a list of StateVariant value types RenderStateSet *renderViewStateSet = renderView->stateSet(); @@ -1646,6 +1723,33 @@ void Renderer::skipNextFrame() m_submitRenderViewsSemaphore.release(1); } +// Jobs we may have to run even if no rendering will happen +QVector<QAspectJobPtr> Renderer::preRenderingJobs() +{ + QVector<QAspectJobPtr> jobs; + + // Do we need to notify any texture about property changes? + if (m_updatedTextureProperties.size() > 0) + jobs.push_back(m_sendTextureChangesToFrontendJob); + + // Do we need to notify frontend about fence change? + if (m_updatedSetFences.size() > 0) + jobs.push_back(m_sendSetFenceHandlesToFrontendJob); + + const QVector<Qt3DCore::QNodeId> pendingCaptureIds = takePendingRenderCaptureSendRequests(); + if (pendingCaptureIds.size() > 0) { + m_sendRenderCaptureJob->setPendingCaptureRequests(pendingCaptureIds); + jobs.push_back(m_sendRenderCaptureJob); + } + if (m_sendBufferCaptureJob->hasRequests()) + jobs.push_back(m_sendBufferCaptureJob); + + jobs.append(pickBoundingVolumeJob()); + jobs.append(rayCastingJob()); + + return jobs; +} + // Waits to be told to create jobs for the next frame // Called by QRenderAspect jobsToExecute context of QAspectThread // Returns all the jobs (and with proper dependency chain) required @@ -1702,17 +1806,6 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() renderBinJobs.push_back(m_updateLevelOfDetailJob); renderBinJobs.push_back(m_cleanupJob); - const QVector<Qt3DCore::QNodeId> pendingCaptureIds = takePendingRenderCaptureSendRequests(); - if (pendingCaptureIds.size() > 0) { - m_sendRenderCaptureJob->setPendingCaptureRequests(pendingCaptureIds); - renderBinJobs.push_back(m_sendRenderCaptureJob); - } - - // Do we need to notify any texture about property changes? - if (m_updatedTextureProperties.size() > 0) - renderBinJobs.push_back(m_sendTextureChangesToFrontendJob); - - renderBinJobs.push_back(m_sendBufferCaptureJob); renderBinJobs.append(bufferJobs); // Jobs to prepare GL Resource upload diff --git a/src/render/renderers/opengl/renderer/renderer_p.h b/src/render/renderers/opengl/renderer/renderer_p.h index 5bd03142f..93d6fdbfa 100644 --- a/src/render/renderers/opengl/renderer/renderer_p.h +++ b/src/render/renderers/opengl/renderer/renderer_p.h @@ -80,6 +80,7 @@ #include <Qt3DRender/private/updateentitylayersjob_p.h> #include <Qt3DRender/private/renderercache_p.h> #include <Qt3DRender/private/texture_p.h> +#include <Qt3DRender/private/glfence_p.h> #include <QHash> #include <QMatrix4x4> @@ -96,6 +97,10 @@ #include <functional> +#if defined(QT_BUILD_INTERNAL) +class tst_Renderer; +#endif + QT_BEGIN_NAMESPACE class QSurface; @@ -195,6 +200,7 @@ public: bool shouldRender() override; void skipNextFrame() override; + QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() override; QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() override; Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() override; Qt3DCore::QAspectJobPtr rayCastingJob() override; @@ -373,6 +379,7 @@ private: GenericLambdaJobPtr<std::function<void ()>> m_vaoGathererJob; GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob; GenericLambdaJobPtr<std::function<void ()>> m_sendTextureChangesToFrontendJob; + GenericLambdaJobPtr<std::function<void ()>> m_sendSetFenceHandlesToFrontendJob; IntrospectShadersJobPtr m_introspectShaderJob; SynchronizerJobPtr m_syncTextureLoadingJob; @@ -383,6 +390,7 @@ private: void lookForDirtyTextures(); void reloadDirtyShaders(); void sendTextureChangesToFrontend(); + void sendSetFenceHandlesToFrontend(); QMutex m_abandonedVaosMutex; QVector<HVao> m_abandonedVaos; @@ -392,6 +400,7 @@ private: QVector<HShader> m_dirtyShaders; QVector<HTexture> m_dirtyTextures; QVector<QPair<Texture::TextureUpdateInfo, Qt3DCore::QNodeIdVector>> m_updatedTextureProperties; + QVector<QPair<Qt3DCore::QNodeId, GLFence>> m_updatedSetFences; bool m_ownedContext; @@ -403,6 +412,10 @@ private: friend class Qt3DRender::Debug::CommandExecuter; #endif +#ifdef QT_BUILD_INTERNAL + friend class ::tst_Renderer; +#endif + QMetaObject::Connection m_contextConnection; RendererCache m_cache; }; diff --git a/src/render/renderers/opengl/renderer/renderview_p.h b/src/render/renderers/opengl/renderer/renderview_p.h index cb3c74917..7ebcdb6bd 100644 --- a/src/render/renderers/opengl/renderer/renderview_p.h +++ b/src/render/renderers/opengl/renderer/renderview_p.h @@ -65,6 +65,7 @@ #include <Qt3DRender/private/qmemorybarrier_p.h> #include <Qt3DRender/private/qrendercapture_p.h> #include <Qt3DRender/private/qblitframebuffer_p.h> +#include <Qt3DRender/private/qwaitfence_p.h> #include <Qt3DCore/private/qframeallocator_p.h> #include <Qt3DRender/private/aligned_malloc_p.h> @@ -174,6 +175,13 @@ public: inline void appendProximityFilterId(const Qt3DCore::QNodeId proximityFilterId) { m_data.m_proximityFilterIds.push_back(proximityFilterId); } inline Qt3DCore::QNodeIdVector proximityFilterIds() const { return m_data.m_proximityFilterIds; } + inline void appendInsertFenceId(const Qt3DCore::QNodeId setFenceId) { m_insertFenceIds.push_back(setFenceId); } + // We prefix with get to avoid confusion when it is called + inline Qt3DCore::QNodeIdVector insertFenceIds() const { return m_insertFenceIds; } + + inline void appendWaitFence(const QWaitFenceData &data) { m_waitFences.push_back(data); } + inline QVector<QWaitFenceData> waitFences() const { return m_waitFences; } + inline void setRenderPassFilter(const RenderPassFilter *rpFilter) Q_DECL_NOTHROW { m_data.m_passFilter = rpFilter; } inline const RenderPassFilter *renderPassFilter() const Q_DECL_NOTHROW { return m_data.m_passFilter; } @@ -320,6 +328,8 @@ private: bool m_frustumCulling:1; int m_workGroups[3]; QMemoryBarrier::Operations m_memoryBarrier; + QVector<Qt3DCore::QNodeId> m_insertFenceIds; + QVector<QWaitFenceData> m_waitFences; // We do not use pointers to RenderNodes or Drawable's here so that the // render aspect is free to change the drawables on the next frame whilst diff --git a/tests/auto/render/commons/testrenderer.h b/tests/auto/render/commons/testrenderer.h index 466cebe14..f19b3211b 100644 --- a/tests/auto/render/commons/testrenderer.h +++ b/tests/auto/render/commons/testrenderer.h @@ -57,6 +57,7 @@ public: bool isRunning() const override { return true; } bool shouldRender() override { return true; } void skipNextFrame() override {} + QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() override { return QVector<Qt3DCore::QAspectJobPtr>(); } QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() override { return QVector<Qt3DCore::QAspectJobPtr>(); } Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() override { return Qt3DCore::QAspectJobPtr(); } Qt3DCore::QAspectJobPtr rayCastingJob() override { return Qt3DCore::QAspectJobPtr(); } diff --git a/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp index 584b675ee..c34372f70 100644 --- a/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp +++ b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp @@ -926,6 +926,9 @@ private Q_SLOTS: SUPPORTS_FEATURE(GraphicsHelperInterface::DrawBuffersBlend, false); SUPPORTS_FEATURE(GraphicsHelperInterface::Tessellation, false); SUPPORTS_FEATURE(GraphicsHelperInterface::BlitFramebuffer, false); + SUPPORTS_FEATURE(GraphicsHelperInterface::IndirectDrawing, false); + SUPPORTS_FEATURE(GraphicsHelperInterface::MapBuffer, true); + SUPPORTS_FEATURE(GraphicsHelperInterface::Fences, false); } @@ -1524,6 +1527,36 @@ private Q_SLOTS: // Not supported by GL2 } + void fenceSync() + { + QSKIP("Initialization failed, OpenGL 2.0 functions not supported"); + // Not supported by GL2 + } + + void clientWaitSync() + { + QSKIP("Initialization failed, OpenGL 2.0 functions not supported"); + // Not supported by GL2 + } + + void waitSync() + { + QSKIP("Initialization failed, OpenGL 2.0 functions not supported"); + // Not supported by GL2 + } + + void wasSyncSignaled() + { + QSKIP("Initialization failed, OpenGL 2.0 functions not supported"); + // Not supported by GL2 + } + + void deleteSync() + { + QSKIP("Initialization failed, OpenGL 2.0 functions not supported"); + // Not supported by GL2 + } + private: QScopedPointer<QWindow> m_window; QOpenGLContext m_glContext; diff --git a/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp b/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp index 648eaaddb..3ef8de6ec 100644 --- a/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp +++ b/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp @@ -2151,6 +2151,105 @@ private Q_SLOTS: QCOMPARE(p, GL_FRONT); } + void fenceSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + + // THEN + QVERIFY(sync != nullptr); + QCOMPARE(m_func->glIsSync(sync), GL_TRUE); + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + } + + void clientWaitSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + QElapsedTimer t; + t.start(); + + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + + m_glHelper.clientWaitSync(sync, 1000000); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + qDebug() << t.nsecsElapsed(); + } + + void waitSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + m_func->glFlush(); + m_glHelper.waitSync(sync); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + } + + void wasSyncSignaled() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + m_func->glFlush(); + m_glHelper.waitSync(sync); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + + // Shouldn't loop forever + while (!m_glHelper.wasSyncSignaled(sync)) + ; + } + + void deleteSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + m_glHelper.clientWaitSync(sync, GLuint64(-1)); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + QVERIFY(m_glHelper.wasSyncSignaled(sync) == true); + + // WHEN + m_glHelper.deleteSync(sync); + + // THEN + QCOMPARE(m_func->glIsSync(sync), GL_FALSE); + } + private: QScopedPointer<QWindow> m_window; QOpenGLContext m_glContext; diff --git a/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp b/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp index 06a3c41cd..a6a41ffd4 100644 --- a/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp +++ b/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp @@ -2251,6 +2251,105 @@ private Q_SLOTS: QCOMPARE(p, GL_FRONT); } + void fenceSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + + // THEN + QVERIFY(sync != nullptr); + QCOMPARE(m_func->glIsSync(sync), GL_TRUE); + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + } + + void clientWaitSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + QElapsedTimer t; + t.start(); + + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + + m_glHelper.clientWaitSync(sync, 1000000); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + qDebug() << t.nsecsElapsed(); + } + + void waitSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + m_func->glFlush(); + m_glHelper.waitSync(sync); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + } + + void wasSyncSignaled() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + m_func->glFlush(); + m_glHelper.waitSync(sync); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + + // Shouldn't loop forever + while (!m_glHelper.wasSyncSignaled(sync)) + ; + } + + void deleteSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + m_glHelper.clientWaitSync(sync, GLuint64(-1)); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + QVERIFY(m_glHelper.wasSyncSignaled(sync) == true); + + // WHEN + m_glHelper.deleteSync(sync); + + // THEN + QCOMPARE(m_func->glIsSync(sync), GL_FALSE); + } + private: QScopedPointer<QWindow> m_window; QOpenGLContext m_glContext; diff --git a/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp index 39bd15021..6632f65de 100644 --- a/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp +++ b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp @@ -1430,7 +1430,7 @@ private Q_SLOTS: void supportsFeature() { - for (int i = 0; i <= GraphicsHelperInterface::BlitFramebuffer; ++i) + for (int i = 0; i <= GraphicsHelperInterface::Fences; ++i) QVERIFY(m_glHelper.supportsFeature(static_cast<GraphicsHelperInterface::Feature>(i))); } @@ -2349,6 +2349,105 @@ private Q_SLOTS: QCOMPARE(p, GL_FRONT); } + void fenceSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + + // THEN + QVERIFY(sync != nullptr); + QCOMPARE(m_func->glIsSync(sync), GL_TRUE); + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + } + + void clientWaitSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + QElapsedTimer t; + t.start(); + + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + + m_glHelper.clientWaitSync(sync, 1000000); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + qDebug() << t.nsecsElapsed(); + } + + void waitSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + m_func->glFlush(); + m_glHelper.waitSync(sync); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + } + + void wasSyncSignaled() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + m_func->glFlush(); + m_glHelper.waitSync(sync); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + + // Shouldn't loop forever + while (!m_glHelper.wasSyncSignaled(sync)) + ; + } + + void deleteSync() + { + if (!m_initializationSuccessful) + QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported"); + + m_func->glGetError(); + + // WHEN + GLsync sync = reinterpret_cast<GLsync>(m_glHelper.fenceSync()); + m_glHelper.clientWaitSync(sync, GLuint64(-1)); + + // THEN + const GLint error = m_func->glGetError(); + QVERIFY(error == 0); + QVERIFY(m_glHelper.wasSyncSignaled(sync) == true); + + // WHEN + m_glHelper.deleteSync(sync); + + // THEN + QCOMPARE(m_func->glIsSync(sync), GL_FALSE); + } + private: QScopedPointer<QWindow> m_window; QOpenGLContext m_glContext; diff --git a/tests/auto/render/renderer/tst_renderer.cpp b/tests/auto/render/renderer/tst_renderer.cpp index 9f6007181..bd1f7185e 100644 --- a/tests/auto/render/renderer/tst_renderer.cpp +++ b/tests/auto/render/renderer/tst_renderer.cpp @@ -44,6 +44,88 @@ public : ~tst_Renderer() {} private Q_SLOTS: + + void checkPreRenderBinJobs() + { + // GIVEN + Qt3DRender::Render::NodeManagers nodeManagers; + Qt3DRender::Render::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + Qt3DRender::Render::OffscreenSurfaceHelper offscreenHelper(&renderer); + Qt3DRender::Render::RenderSettings settings; + // owned by FG manager + Qt3DRender::Render::ViewportNode *fgRoot = new Qt3DRender::Render::ViewportNode(); + const Qt3DCore::QNodeId fgRootId = Qt3DCore::QNodeId::createId(); + + nodeManagers.frameGraphManager()->appendNode(fgRootId, fgRoot); + settings.setActiveFrameGraphId(fgRootId); + + renderer.setNodeManagers(&nodeManagers); + renderer.setSettings(&settings); + renderer.setOffscreenSurfaceHelper(&offscreenHelper); + renderer.initialize(); + + // Ensure invoke calls are performed + QCoreApplication::processEvents(); + + // WHEN (nothing dirty, no buffers, no layers to be rebuilt, no materials to be rebuilt) + QVector<Qt3DCore::QAspectJobPtr> jobs = renderer.preRenderingJobs(); + + // THEN + QCOMPARE(jobs.size(), + 1 + // PickBoundingVolumeJob + 1); // RayCastingJob + + // WHEN + renderer.addRenderCaptureSendRequest(Qt3DCore::QNodeId::createId()); + jobs = renderer.preRenderingJobs(); + + // THEN + QCOMPARE(jobs.size(), + 1 + // PickBoundingVolumeJob + 1 + // RayCastingJob + 1); // SendRenderCaptureJob + + // WHEN + renderer.m_sendBufferCaptureJob->addRequest({nullptr, {}}); + jobs = renderer.preRenderingJobs(); + + // THEN + QCOMPARE(jobs.size(), + 1 + // PickBoundingVolumeJob + 1 + // RayCastingJob + 1); // SendBufferCaptureJob + // Note: pending render buffer captures are only cleared when the job is run + + // WHEN + renderer.m_updatedSetFences.push_back({Qt3DCore::QNodeId(), nullptr}); + jobs = renderer.preRenderingJobs(); + + // THEN + QCOMPARE(jobs.size(), + 1 + // PickBoundingVolumeJob + 1 + // RayCastingJob + 1 + // SendBufferCaptureJob + 1); // SendSetFenceHandlesJob + // Note: pending set fence handles are only cleared when the job is run + + // WHEN + renderer.m_updatedTextureProperties.push_back({{}, {}}); + jobs = renderer.preRenderingJobs(); + + // THEN + QCOMPARE(jobs.size(), + 1 + // PickBoundingVolumeJob + 1 + // RayCastingJob + 1 + // SendBufferCaptureJob + 1 + // SendSetFenceHandlesJob + 1); // SendTextureChangesToFrontend + + // Note: pending texture changes are only cleared when the job is run + + // Properly shutdown command thread + renderer.shutdown(); + } + void checkRenderBinJobs() { // GIVEN @@ -90,7 +172,6 @@ private Q_SLOTS: QCOMPARE(jobs.size(), 1 + // updateLevelOfDetailJob 1 + // cleanupJob - 1 + // sendBufferCaptureJob 1 + // VAOGatherer 1 + // updateSkinningPaletteJob singleRenderViewJobCount); // Only valid for the first call to renderBinJobs(), since subsequent calls won't have the renderqueue reset @@ -98,19 +179,6 @@ private Q_SLOTS: renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); // WHEN - renderer.addRenderCaptureSendRequest(Qt3DCore::QNodeId::createId()); - jobs = renderer.renderBinJobs(); - - // THEN - QCOMPARE(jobs.size(), - 1 + // updateLevelOfDetailJob - 1 + // cleanupJob - 1 + // sendBufferCaptureJob - 1 + // sendRenderCaptureJob - 1 + // VAOGatherer - 1); // updateSkinningPaletteJob - - // WHEN renderer.markDirty(Qt3DRender::Render::AbstractRenderer::EntityEnabledDirty, nullptr); jobs = renderer.renderBinJobs(); @@ -118,7 +186,6 @@ private Q_SLOTS: QCOMPARE(jobs.size(), 1 + // updateLevelOfDetailJob 1 + // cleanupJob - 1 + // sendBufferCaptureJob 1 + // VAOGatherer 1 + // updateSkinningPaletteJob 1); // EntityEnabledDirty @@ -133,7 +200,6 @@ private Q_SLOTS: QCOMPARE(jobs.size(), 1 + // updateLevelOfDetailJob 1 + // cleanupJob - 1 + // sendBufferCaptureJob 1 + // VAOGatherer 1 + // WorldTransformJob 1 + // UpdateWorldBoundingVolume @@ -151,7 +217,6 @@ private Q_SLOTS: QCOMPARE(jobs.size(), 1 + // updateLevelOfDetailJob 1 + // cleanupJob - 1 + // sendBufferCaptureJob 1 + // VAOGatherer 1 + // CalculateBoundingVolumeJob 1 + // UpdateMeshTriangleListJob @@ -168,7 +233,6 @@ private Q_SLOTS: QCOMPARE(jobs.size(), 1 + // updateLevelOfDetailJob 1 + // cleanupJob - 1 + // sendBufferCaptureJob 1 + // VAOGatherer 1 + // updateSkinningPaletteJob 1); // BufferGathererJob @@ -183,7 +247,6 @@ private Q_SLOTS: QCOMPARE(jobs.size(), 1 + // updateLevelOfDetailJob 1 + // cleanupJob - 1 + // sendBufferCaptureJob 1 + // VAOGatherer 1 + // TexturesGathererJob 1 + // updateSkinningPaletteJob @@ -191,6 +254,19 @@ private Q_SLOTS: renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + + // WHEN + renderer.markDirty(Qt3DRender::Render::AbstractRenderer::FrameGraphDirty, nullptr); + jobs = renderer.renderBinJobs(); + + QCOMPARE(jobs.size(), + 1 + // updateLevelOfDetailJob + 1 + // cleanupJob + 1 + // VAOGatherer + 1); // updateSkinningPaletteJob + + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + // WHEN renderer.markDirty(Qt3DRender::Render::AbstractRenderer::AllDirty, nullptr); jobs = renderer.renderBinJobs(); @@ -208,7 +284,6 @@ private Q_SLOTS: 1 + // updateSkinningPaletteJob 1 + // updateLevelOfDetailJob 1 + // cleanupJob - 1 + // sendBufferCaptureJob 1 + // VAOGatherer 1 + // BufferGathererJob 1 + // TexturesGathererJob |