diff options
Diffstat (limited to 'src/render/renderers/opengl')
28 files changed, 769 insertions, 96 deletions
diff --git a/src/render/renderers/opengl/graphicshelpers/glfence_p.h b/src/render/renderers/opengl/graphicshelpers/glfence_p.h new file mode 100644 index 000000000..366065048 --- /dev/null +++ b/src/render/renderers/opengl/graphicshelpers/glfence_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GLFENCE_P_H +#define GLFENCE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGlobal> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +// GLsync is a pointer to a struct (unlike the rest of GL which used int ids) +// We cannot reference GLsync as it's only available since 3.2 We use FenceId +// to wrap that around and trust the GLHelpers will convert them accordingly. +using GLFence = void *; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + + +#endif // GLFENCE_P_H diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp index c5753195b..71540b1ad 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2.cpp @@ -318,6 +318,33 @@ void GraphicsHelperES2::drawBuffer(GLenum mode) qWarning() << "glDrawBuffer is not supported with OpenGL ES 2"; } +void *GraphicsHelperES2::fenceSync() +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; + return nullptr; +} + +void GraphicsHelperES2::clientWaitSync(void *, GLuint64 ) +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; +} + +void GraphicsHelperES2::waitSync(void *) +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; +} + +bool GraphicsHelperES2::wasSyncSignaled(void *) +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; + return false; +} + +void GraphicsHelperES2::deleteSync(void *) +{ + qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)"; +} + void GraphicsHelperES2::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h index 1c6df41b6..8c8dd34e9 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes2_p.h @@ -132,6 +132,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp index 34c1e7448..5e5d2e001 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp @@ -147,6 +147,26 @@ QT_BEGIN_NAMESPACE #define GL_READ_FRAMEBUFFER 0x8CA8 #endif +#ifndef GL_SIGNALED +#define GL_SIGNALED 0x9119 +#endif + +#ifndef GL_SYNC_STATUS +#define GL_SYNC_STATUS 0x9114 +#endif + +#ifndef GL_TIMEOUT_IGNORED +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#endif + +#ifndef GL_SYNC_GPU_COMMANDS_COMPLETE +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#endif + +#ifndef GL_SYNC_FLUSH_COMMANDS_BIT +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#endif + namespace Qt3DRender { namespace Render { @@ -307,6 +327,7 @@ bool GraphicsHelperES3::supportsFeature(GraphicsHelperInterface::Feature feature case BlitFramebuffer: case UniformBufferObject: case MapBuffer: + case Fences: return true; default: return false; @@ -439,6 +460,37 @@ uint GraphicsHelperES3::uniformByteSize(const ShaderUniform &description) return arrayStride ? rawByteSize * arrayStride : rawByteSize; } +void *GraphicsHelperES3::fenceSync() +{ + return m_extraFuncs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void GraphicsHelperES3::clientWaitSync(void *sync, GLuint64 nanoSecTimeout) +{ + m_extraFuncs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout); +} + +void GraphicsHelperES3::waitSync(void *sync) +{ + m_extraFuncs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED); +} + +bool GraphicsHelperES3::wasSyncSignaled(void *sync) +{ + GLint v; + m_extraFuncs->glGetSynciv(static_cast<GLsync>(sync), + GL_SYNC_STATUS, + sizeof(v), + nullptr, + &v); + return v == GL_SIGNALED; +} + +void GraphicsHelperES3::deleteSync(void *sync) +{ + m_extraFuncs->glDeleteSync(static_cast<GLsync>(sync)); +} + void GraphicsHelperES3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { m_extraFuncs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h index d4467cf7f..dc5cef10c 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h @@ -90,6 +90,12 @@ public: UniformType uniformTypeFromGLType(GLenum glType) override; uint uniformByteSize(const ShaderUniform &description) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + protected: QOpenGLExtraFunctions *m_extraFuncs = nullptr; }; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp index 6da8a9b6f..b6f3412b2 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp @@ -272,6 +272,33 @@ void GraphicsHelperGL2::drawBuffer(GLenum mode) m_funcs->glDrawBuffer(mode); } +void *GraphicsHelperGL2::fenceSync() +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; + return nullptr; +} + +void GraphicsHelperGL2::clientWaitSync(void *, GLuint64 ) +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; +} + +void GraphicsHelperGL2::waitSync(void *) +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; +} + +bool GraphicsHelperGL2::wasSyncSignaled(void *) +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; + return false; +} + +void GraphicsHelperGL2::deleteSync(void *) +{ + qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)"; +} + void GraphicsHelperGL2::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); @@ -412,6 +439,7 @@ bool GraphicsHelperGL2::supportsFeature(GraphicsHelperInterface::Feature feature case MRT: return (m_fboFuncs != nullptr); case TextureDimensionRetrieval: + case MapBuffer: return true; default: return false; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h index 2db75004f..b142b2623 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h @@ -132,6 +132,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp index a35c4e37f..5ff1a2ba5 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp @@ -334,6 +334,37 @@ void GraphicsHelperGL3_2::drawBuffer(GLenum mode) m_funcs->glDrawBuffer(mode); } +void *GraphicsHelperGL3_2::fenceSync() +{ + return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void GraphicsHelperGL3_2::clientWaitSync(void *sync, GLuint64 nanoSecTimeout) +{ + m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout); +} + +void GraphicsHelperGL3_2::waitSync(void *sync) +{ + m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED); +} + +bool GraphicsHelperGL3_2::wasSyncSignaled(void *sync) +{ + GLint v; + m_funcs->glGetSynciv(static_cast<GLsync>(sync), + GL_SYNC_STATUS, + sizeof(v), + nullptr, + &v); + return v == GL_SIGNALED; +} + +void GraphicsHelperGL3_2::deleteSync(void *sync) +{ + m_funcs->glDeleteSync(static_cast<GLsync>(sync)); +} + void GraphicsHelperGL3_2::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); @@ -481,6 +512,7 @@ bool GraphicsHelperGL3_2::supportsFeature(GraphicsHelperInterface::Feature featu case TextureDimensionRetrieval: case BindableFragmentOutputs: case BlitFramebuffer: + case Fences: return true; case Tessellation: return !m_tessFuncs.isNull(); diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h index 133295fd7..9e81345ad 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h @@ -134,6 +134,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp index b2512d84a..81081943d 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp @@ -330,6 +330,37 @@ void GraphicsHelperGL3_3::drawBuffer(GLenum mode) m_funcs->glDrawBuffer(mode); } +void *GraphicsHelperGL3_3::fenceSync() +{ + return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void GraphicsHelperGL3_3::clientWaitSync(void *sync, GLuint64 nanoSecTimeout) +{ + m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout); +} + +void GraphicsHelperGL3_3::waitSync(void *sync) +{ + m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED); +} + +bool GraphicsHelperGL3_3::wasSyncSignaled(void *sync) +{ + GLint v; + m_funcs->glGetSynciv(static_cast<GLsync>(sync), + GL_SYNC_STATUS, + sizeof(v), + nullptr, + &v); + return v == GL_SIGNALED; +} + +void GraphicsHelperGL3_3::deleteSync(void *sync) +{ + m_funcs->glDeleteSync(static_cast<GLsync>(sync)); +} + void GraphicsHelperGL3_3::blendEquation(GLenum mode) { m_funcs->glBlendEquation(mode); @@ -477,6 +508,7 @@ bool GraphicsHelperGL3_3::supportsFeature(GraphicsHelperInterface::Feature featu case TextureDimensionRetrieval: case BindableFragmentOutputs: case BlitFramebuffer: + case Fences: return true; case Tessellation: return !m_tessFuncs.isNull(); diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h index 0ecdd3620..c480e5258 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h @@ -134,6 +134,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp index ce1b8ac2b..22cbf7428 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp @@ -400,6 +400,39 @@ void GraphicsHelperGL4::drawBuffer(GLenum mode) m_funcs->glDrawBuffer(mode); } +void *GraphicsHelperGL4::fenceSync() +{ + return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void GraphicsHelperGL4::clientWaitSync(void *sync, GLuint64 nanoSecTimeout) +{ + qDebug() << Q_FUNC_INFO << sync << static_cast<GLsync>(sync); + GLenum e = m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout); + qDebug() << e; +} + +void GraphicsHelperGL4::waitSync(void *sync) +{ + m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED); +} + +bool GraphicsHelperGL4::wasSyncSignaled(void *sync) +{ + GLint v = 0; + m_funcs->glGetSynciv(static_cast<GLsync>(sync), + GL_SYNC_STATUS, + sizeof(v), + nullptr, + &v); + return v == GL_SIGNALED; +} + +void GraphicsHelperGL4::deleteSync(void *sync) +{ + m_funcs->glDeleteSync(static_cast<GLsync>(sync)); +} + void GraphicsHelperGL4::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) { m_funcs->glUniform1fv(location, count, values); @@ -746,6 +779,8 @@ bool GraphicsHelperGL4::supportsFeature(GraphicsHelperInterface::Feature feature case DrawBuffersBlend: case BlitFramebuffer: case IndirectDrawing: + case MapBuffer: + case Fences: return true; default: return false; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h index 3020b16d8..da62f4212 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h @@ -132,6 +132,12 @@ public: void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; + void *fenceSync() override; + void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override; + void waitSync(void *sync) override; + bool wasSyncSignaled(void *sync) override; + void deleteSync(void *sync) override; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override; void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h index e41325cb7..2a1688b7f 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h @@ -82,7 +82,8 @@ public: DrawBuffersBlend, BlitFramebuffer, IndirectDrawing, - MapBuffer + MapBuffer, + Fences }; enum FBOBindMode { @@ -155,6 +156,12 @@ public: virtual void readBuffer(GLenum mode) = 0; virtual void drawBuffer(GLenum mode) = 0; + virtual void *fenceSync() = 0; + virtual void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) = 0; + virtual void waitSync(void *sync) = 0; + virtual bool wasSyncSignaled(void *sync) = 0; + virtual void deleteSync(void *sync) = 0; + virtual void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) = 0; virtual void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) = 0; virtual void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) = 0; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri index c40f52374..ad08038c9 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri @@ -3,6 +3,7 @@ INCLUDEPATH += $$PWD HEADERS += \ + $$PWD/glfence_p.h \ $$PWD/graphicscontext_p.h \ $$PWD/graphicshelperinterface_p.h \ $$PWD/graphicshelperes2_p.h \ diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp index 59c2d4286..51f7cebd1 100644 --- a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp +++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp @@ -1088,6 +1088,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) @@ -1113,7 +1140,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) if (t != nullptr) { UniformValue &texUniform = uniformValues[namedTex.glslNameId]; if (texUniform.valueType() == UniformValue::TextureValue) { - const int texUnit = m_textureContext.activateTexture(TextureSubmissionContext::TextureScopeMaterial, t); + const int texUnit = m_textureContext.activateTexture(TextureSubmissionContext::TextureScopeMaterial, m_gl, t); texUniform.data<int>()[namedTex.uniformArrayIndex] = texUnit; if (texUnit == -1) { if (namedTex.glslNameId != irradianceId && diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h index 9b9bd7fa8..844e62f15 100644 --- a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h +++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h @@ -60,6 +60,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 @@ -147,6 +148,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/graphicshelpers/texturesubmissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp index 35fc1dc7c..67d0f9976 100644 --- a/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp +++ b/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp @@ -104,7 +104,9 @@ void TextureSubmissionContext::endDrawing() TextureExtRendererLocker::unlock(m_activeTextures[i].texture); } -int TextureSubmissionContext::activateTexture(TextureSubmissionContext::TextureScope scope, GLTexture *tex) +int TextureSubmissionContext::activateTexture(TextureSubmissionContext::TextureScope scope, + QOpenGLContext *m_gl, + GLTexture *tex) { // Returns the texture unit to use for the texture // This always return a valid unit, unless there are more textures than @@ -115,11 +117,20 @@ int TextureSubmissionContext::activateTexture(TextureSubmissionContext::TextureS if (onUnit == -1) return -1; - // Texture must have been created and updated at this point - QOpenGLTexture *glTex = tex->getGLTexture(); - if (glTex == nullptr) - return -1; - glTex->bind(uint(onUnit)); + const int sharedTextureId = tex->sharedTextureId(); + // We have a valid texture id provided by a shared context + if (sharedTextureId > 0) { + m_gl->functions()->glActiveTexture(GL_TEXTURE0 + onUnit); + const QAbstractTexture::Target target = tex->properties().target; + // For now we know that target values correspond to the GL values + m_gl->functions()->glBindTexture(target, tex->sharedTextureId()); + } else { + // Texture must have been created and updated at this point + QOpenGLTexture *glTex = tex->getGLTexture(); + if (glTex == nullptr) + return -1; + glTex->bind(uint(onUnit)); + } if (m_activeTextures[onUnit].texture != tex) { if (m_activeTextures[onUnit].texture) TextureExtRendererLocker::unlock(m_activeTextures[onUnit].texture); diff --git a/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h b/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h index d0c1565b2..3c84fe558 100644 --- a/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h +++ b/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h @@ -57,6 +57,8 @@ QT_BEGIN_NAMESPACE +class QOpenGLContext; + namespace Qt3DRender { namespace Render { @@ -78,7 +80,7 @@ public: void initialize(GraphicsContext *context); void endDrawing(); - int activateTexture(TextureScope scope, GLTexture* tex); + int activateTexture(TextureScope scope, QOpenGLContext *gl, GLTexture* tex); void deactivateTexture(GLTexture *tex); void deactivateTexturesWithScope(TextureScope ts); diff --git a/src/render/renderers/opengl/jobs/filtercompatibletechniquejob_p.h b/src/render/renderers/opengl/jobs/filtercompatibletechniquejob_p.h index 4f7a7146c..27b3d4ed2 100644 --- a/src/render/renderers/opengl/jobs/filtercompatibletechniquejob_p.h +++ b/src/render/renderers/opengl/jobs/filtercompatibletechniquejob_p.h @@ -64,7 +64,7 @@ namespace Render { class TechniqueManager; class Renderer; -class QT3DRENDERSHARED_PRIVATE_EXPORT FilterCompatibleTechniqueJob : public Qt3DCore::QAspectJob +class Q_3DRENDERSHARED_PRIVATE_EXPORT FilterCompatibleTechniqueJob : public Qt3DCore::QAspectJob { public: FilterCompatibleTechniqueJob(); diff --git a/src/render/renderers/opengl/jobs/materialparametergathererjob_p.h b/src/render/renderers/opengl/jobs/materialparametergathererjob_p.h index fbfac3364..6ba060841 100644 --- a/src/render/renderers/opengl/jobs/materialparametergathererjob_p.h +++ b/src/render/renderers/opengl/jobs/materialparametergathererjob_p.h @@ -70,7 +70,7 @@ class Renderer; // TO be executed for each FrameGraph branch with a given RenderPassFilter/TechniqueFilter -class QT3DRENDERSHARED_PRIVATE_EXPORT MaterialParameterGathererJob : public Qt3DCore::QAspectJob +class Q_3DRENDERSHARED_PRIVATE_EXPORT MaterialParameterGathererJob : public Qt3DCore::QAspectJob { public: MaterialParameterGathererJob(); 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 e9c582458..e7fa4615c 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -91,6 +91,7 @@ #include <Qt3DRender/private/renderviewbuilder_p.h> #include <Qt3DRender/private/commandthread_p.h> #include <Qt3DRender/private/glcommands_p.h> +#include <Qt3DRender/private/setfence_p.h> #include <Qt3DRender/qcameralens.h> #include <Qt3DCore/private/qeventfilterservice_p.h> @@ -196,6 +197,7 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_vaoGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering)) , m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering)) , m_sendTextureChangesToFrontendJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { sendTextureChangesToFrontend(); }, JobTypes::SendTextureChangesToFrontend)) + , m_sendSetFenceHandlesToFrontendJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { sendSetFenceHandlesToFrontend(); }, JobTypes::SendSetFenceHandlesToFrontend)) , m_introspectShaderJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { reloadDirtyShaders(); }, JobTypes::DirtyShaderGathering)) , m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading)) , m_updateEntityHierarchyJob(Render::UpdateEntityHierarchyJobPtr::create()) @@ -393,6 +395,9 @@ void Renderer::initialize() [this] { releaseGraphicsResources(); }); } + qCDebug(Backend) << "Qt3D shared context:" << ctx->shareContext(); + qCDebug(Backend) << "Qt global shared context:" << qt_gl_global_share_context(); + if (!ctx->shareContext()) { m_shareContext = new QOpenGLContext; m_shareContext->setFormat(ctx->format()); @@ -1097,7 +1102,7 @@ void Renderer::lookForDirtyTextures() } // Dirty meaning that something has changed on the texture - // either properties, parameters, generator or a texture image + // either properties, parameters, shared texture id, generator or a texture image if (texture->dirtyFlags() != Texture::NotDirty) m_dirtyTextures.push_back(handle); // Note: texture dirty flags are reset when actually updating the @@ -1183,7 +1188,7 @@ void Renderer::reloadDirtyShaders() // Executed in a job void Renderer::sendTextureChangesToFrontend() { - const QVector<QPair<TextureProperties, Qt3DCore::QNodeIdVector>> updateTextureProperties = std::move(m_updatedTextureProperties); + const QVector<QPair<Texture::TextureUpdateInfo, Qt3DCore::QNodeIdVector>> updateTextureProperties = std::move(m_updatedTextureProperties); for (const auto &pair : updateTextureProperties) { // Prepare change notification @@ -1202,6 +1207,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 @@ -1215,6 +1236,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) { @@ -1280,8 +1320,13 @@ void Renderer::updateGLResources() // Gather these information and store them to be distributed by a change next frame const QNodeIdVector referenceTextureIds = glTextureManager->referencedTextureIds(glTexture); // Store properties and referenceTextureIds - if (info.wasUpdated) - m_updatedTextureProperties.push_back({info.properties, referenceTextureIds}); + if (info.wasUpdated) { + Texture::TextureUpdateInfo updateInfo; + updateInfo.properties = info.properties; + updateInfo.handleType = QAbstractTexture::OpenGLTextureId; + updateInfo.handle = info.texture ? QVariant(info.texture->textureId()) : QVariant(); + m_updatedTextureProperties.push_back({updateInfo, referenceTextureIds}); + } } } } @@ -1303,18 +1348,21 @@ void Renderer::updateTexture(Texture *texture) return; // For implementing unique, non-shared, non-cached textures. - // for now, every texture is shared by default + // for now, every texture is shared by default except if: + // - texture is reference by a render attachment + // - texture is referencing a shared texture id + bool isUnique = texture->sharedTextureId() > 0; - bool isUnique = false; - - // TO DO: Update the vector once per frame (or in a job) - const QVector<HAttachment> activeRenderTargetOutputs = m_nodesManager->attachmentManager()->activeHandles(); - // A texture is unique if it's being reference by a render target output - for (const HAttachment &attachmentHandle : activeRenderTargetOutputs) { - RenderTargetOutput *attachment = m_nodesManager->attachmentManager()->data(attachmentHandle); - if (attachment->textureUuid() == texture->peerId()) { - isUnique = true; - break; + if (!isUnique) { + // TO DO: Update the vector once per frame (or in a job) + const QVector<HAttachment> activeRenderTargetOutputs = m_nodesManager->attachmentManager()->activeHandles(); + // A texture is unique if it's being reference by a render target output + for (const HAttachment &attachmentHandle : activeRenderTargetOutputs) { + RenderTargetOutput *attachment = m_nodesManager->attachmentManager()->data(attachmentHandle); + if (attachment->textureUuid() == texture->peerId()) { + isUnique = true; + break; + } } } @@ -1361,6 +1409,9 @@ void Renderer::updateTexture(Texture *texture) // we hold a reference to a unique or exclusive access to a shared texture // we can thus modify the texture directly. const Texture::DirtyFlags dirtyFlags = texture->dirtyFlags(); + if (dirtyFlags.testFlag(Texture::DirtySharedTextureId) && + !glTextureManager->setSharedTextureId(glTexture, texture->sharedTextureId())) + qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setSharedTextureId failed, should be non-shared"; if (dirtyFlags.testFlag(Texture::DirtyProperties) && !glTextureManager->setProperties(glTexture, texture->properties())) @@ -1394,6 +1445,7 @@ void Renderer::cleanupTexture(Qt3DCore::QNodeId cleanedUpTextureId) glTextureManager->abandon(glTexture, cleanedUpTextureId); } +// Called by SubmitRenderView void Renderer::downloadGLBuffers() { lookForDownloadableBuffers(); @@ -1478,6 +1530,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(); @@ -1642,6 +1733,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 @@ -1703,17 +1821,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 6443215a4..5b5f5c4f4 100644 --- a/src/render/renderers/opengl/renderer/renderer_p.h +++ b/src/render/renderers/opengl/renderer/renderer_p.h @@ -81,6 +81,7 @@ #include <Qt3DRender/private/updateentityhierarchyjob_p.h> #include <Qt3DRender/private/renderercache_p.h> #include <Qt3DRender/private/texture_p.h> +#include <Qt3DRender/private/glfence_p.h> #include <QHash> #include <QMatrix4x4> @@ -97,6 +98,10 @@ #include <functional> +#if defined(QT_BUILD_INTERNAL) +class tst_Renderer; +#endif + QT_BEGIN_NAMESPACE class QSurface; @@ -153,7 +158,7 @@ typedef QSharedPointer<UpdateLevelOfDetailJob> UpdateLevelOfDetailJobPtr; using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>; using IntrospectShadersJobPtr = GenericLambdaJobPtr<std::function<void()>>; -class QT3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer +class Q_3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer { public: explicit Renderer(QRenderAspect::RenderType type); @@ -197,6 +202,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; @@ -376,6 +382,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; @@ -386,6 +393,7 @@ private: void lookForDirtyTextures(); void reloadDirtyShaders(); void sendTextureChangesToFrontend(); + void sendSetFenceHandlesToFrontend(); QMutex m_abandonedVaosMutex; QVector<HVao> m_abandonedVaos; @@ -394,7 +402,8 @@ private: QVector<HBuffer> m_downloadableBuffers; QVector<HShader> m_dirtyShaders; QVector<HTexture> m_dirtyTextures; - QVector<QPair<TextureProperties, Qt3DCore::QNodeIdVector>> m_updatedTextureProperties; + QVector<QPair<Texture::TextureUpdateInfo, Qt3DCore::QNodeIdVector>> m_updatedTextureProperties; + QVector<QPair<Qt3DCore::QNodeId, GLFence>> m_updatedSetFences; bool m_ownedContext; @@ -406,6 +415,10 @@ private: friend class Qt3DRender::Debug::CommandExecuter; #endif +#ifdef QT_BUILD_INTERNAL + friend class ::tst_Renderer; +#endif + QMetaObject::Connection m_contextConnection; RendererCache m_cache; }; diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp index 47e6a8fb1..de25f55d1 100644 --- a/src/render/renderers/opengl/renderer/renderview.cpp +++ b/src/render/renderers/opengl/renderer/renderview.cpp @@ -715,6 +715,11 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En if ((computeJob = entity->renderComponent<ComputeCommand>()) != nullptr && computeJob->isEnabled()) { + // Note: if frameCount has reached 0 in the previous frame, isEnabled + // would be false + if (computeJob->runType() == QComputeCommand::Manual) + computeJob->updateFrameCount(); + const Qt3DCore::QNodeId materialComponentId = entity->componentUuid<Material>(); const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId); diff --git a/src/render/renderers/opengl/renderer/renderview_p.h b/src/render/renderers/opengl/renderer/renderview_p.h index cb3c74917..7ebcdb6bd 100644 --- a/src/render/renderers/opengl/renderer/renderview_p.h +++ b/src/render/renderers/opengl/renderer/renderview_p.h @@ -65,6 +65,7 @@ #include <Qt3DRender/private/qmemorybarrier_p.h> #include <Qt3DRender/private/qrendercapture_p.h> #include <Qt3DRender/private/qblitframebuffer_p.h> +#include <Qt3DRender/private/qwaitfence_p.h> #include <Qt3DCore/private/qframeallocator_p.h> #include <Qt3DRender/private/aligned_malloc_p.h> @@ -174,6 +175,13 @@ public: inline void appendProximityFilterId(const Qt3DCore::QNodeId proximityFilterId) { m_data.m_proximityFilterIds.push_back(proximityFilterId); } inline Qt3DCore::QNodeIdVector proximityFilterIds() const { return m_data.m_proximityFilterIds; } + inline void appendInsertFenceId(const Qt3DCore::QNodeId setFenceId) { m_insertFenceIds.push_back(setFenceId); } + // We prefix with get to avoid confusion when it is called + inline Qt3DCore::QNodeIdVector insertFenceIds() const { return m_insertFenceIds; } + + inline void appendWaitFence(const QWaitFenceData &data) { m_waitFences.push_back(data); } + inline QVector<QWaitFenceData> waitFences() const { return m_waitFences; } + inline void setRenderPassFilter(const RenderPassFilter *rpFilter) Q_DECL_NOTHROW { m_data.m_passFilter = rpFilter; } inline const RenderPassFilter *renderPassFilter() const Q_DECL_NOTHROW { return m_data.m_passFilter; } @@ -320,6 +328,8 @@ private: bool m_frustumCulling:1; int m_workGroups[3]; QMemoryBarrier::Operations m_memoryBarrier; + QVector<Qt3DCore::QNodeId> m_insertFenceIds; + QVector<QWaitFenceData> m_waitFences; // We do not use pointers to RenderNodes or Drawable's here so that the // render aspect is free to change the drawables on the next frame whilst diff --git a/src/render/renderers/opengl/textures/gltexture.cpp b/src/render/renderers/opengl/textures/gltexture.cpp index ce212de03..42deb4c2a 100644 --- a/src/render/renderers/opengl/textures/gltexture.cpp +++ b/src/render/renderers/opengl/textures/gltexture.cpp @@ -57,6 +57,11 @@ #include <Qt3DCore/qpropertynodeaddedchange.h> #include <Qt3DCore/qpropertynoderemovedchange.h> +#if !defined(QT_OPENGL_ES_2) +#include <QOpenGLFunctions_3_1> +#include <QOpenGLFunctions_4_5_Core> +#endif + QT_BEGIN_NAMESPACE using namespace Qt3DCore; @@ -75,6 +80,7 @@ GLTexture::GLTexture(TextureDataManager *texDataMgr, , m_textureImageDataManager(texImgDataMgr) , m_dataFunctor(texGen) , m_pendingDataFunctor(nullptr) + , m_sharedTextureId(-1) , m_externalRendering(false) { // make sure texture generator is executed @@ -181,39 +187,44 @@ GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture() m_properties.status = QAbstractTexture::Error; - // on the first invocation in the render thread, make sure to - // evaluate the texture data generator output - // (this might change some property values) - if (m_dataFunctor && !m_textureData) { - const bool successfullyLoadedTextureData = loadTextureDataFromGenerator(); - if (successfullyLoadedTextureData) { - setDirtyFlag(Properties, true); - needUpload = true; - } else { - if (m_pendingDataFunctor != m_dataFunctor.get()) { - qWarning() << "[Qt3DRender::GLTexture] No QTextureData generated from Texture Generator yet. Texture will be invalid for this frame"; - m_pendingDataFunctor = m_dataFunctor.get(); + const bool hasSharedTextureId = m_sharedTextureId > 0; + + // Only load texture data if we are not using a sharedTextureId + if (!hasSharedTextureId) { + // on the first invocation in the render thread, make sure to + // evaluate the texture data generator output + // (this might change some property values) + if (m_dataFunctor && !m_textureData) { + const bool successfullyLoadedTextureData = loadTextureDataFromGenerator(); + if (successfullyLoadedTextureData) { + setDirtyFlag(Properties, true); + needUpload = true; + } else { + if (m_pendingDataFunctor != m_dataFunctor.get()) { + qWarning() << "[Qt3DRender::GLTexture] No QTextureData generated from Texture Generator yet. Texture will be invalid for this frame"; + m_pendingDataFunctor = m_dataFunctor.get(); + } + textureInfo.properties.status = QAbstractTexture::Loading; + return textureInfo; } - textureInfo.properties.status = QAbstractTexture::Loading; - return textureInfo; } - } - // additional texture images may be defined through image data generators - if (testDirtyFlag(TextureData)) { - m_imageData.clear(); - loadTextureDataFromImages(); - needUpload = true; - } + // additional texture images may be defined through image data generators + if (testDirtyFlag(TextureData)) { + m_imageData.clear(); + loadTextureDataFromImages(); + needUpload = true; + } - // don't try to create the texture if the format was not set - if (m_properties.format == QAbstractTexture::Automatic) { - textureInfo.properties.status = QAbstractTexture::Error; - return textureInfo; + // don't try to create the texture if the format was not set + if (m_properties.format == QAbstractTexture::Automatic) { + textureInfo.properties.status = QAbstractTexture::Error; + return textureInfo; + } } // if the properties changed, we need to re-allocate the texture - if (testDirtyFlag(Properties)) { + if (testDirtyFlag(Properties) || testDirtyFlag(SharedTextureId)) { delete m_gl; m_gl = nullptr; textureInfo.wasUpdated = true; @@ -223,40 +234,48 @@ GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture() needUpload = true; } + m_properties.status = QAbstractTexture::Ready; - if (!m_gl) { - m_gl = buildGLTexture(); + if (hasSharedTextureId && testDirtyFlag(SharedTextureId)) { + // Update m_properties by doing introspection on the texture + introspectPropertiesFromSharedTextureId(); + } else { + // We only build a QOpenGLTexture if we have no shared textureId set if (!m_gl) { - textureInfo.properties.status = QAbstractTexture::Error; - return textureInfo; - } + m_gl = buildGLTexture(); + if (!m_gl) { + textureInfo.properties.status = QAbstractTexture::Error; + return textureInfo; + } - m_gl->allocateStorage(); - if (!m_gl->isStorageAllocated()) { - textureInfo.properties.status = QAbstractTexture::Error; - return textureInfo; + m_gl->allocateStorage(); + if (!m_gl->isStorageAllocated()) { + textureInfo.properties.status = QAbstractTexture::Error; + return textureInfo; + } } - } - m_properties.status = QAbstractTexture::Ready; - textureInfo.properties = m_properties; - textureInfo.texture = m_gl; + textureInfo.texture = m_gl; - // need to (re-)upload texture data? - if (needUpload) { - uploadGLTextureData(); - setDirtyFlag(TextureData, false); - } + // need to (re-)upload texture data? + if (needUpload) { + uploadGLTextureData(); + setDirtyFlag(TextureData, false); + } - // need to set texture parameters? - if (testDirtyFlag(Properties) || testDirtyFlag(Parameters)) { - updateGLTextureParameters(); + // need to set texture parameters? + if (testDirtyFlag(Properties) || testDirtyFlag(Parameters)) { + updateGLTextureParameters(); + } } + textureInfo.properties = m_properties; + // un-set properties and parameters. The TextureData flag might have been set by another thread // in the meantime, so don't clear that. setDirtyFlag(Properties, false); setDirtyFlag(Parameters, false); + setDirtyFlag(SharedTextureId, false); return textureInfo; } @@ -355,6 +374,14 @@ void GLTexture::setGenerator(const QTextureGeneratorPtr &generator) } } +void GLTexture::setSharedTextureId(int textureId) +{ + if (m_sharedTextureId != textureId) { + m_sharedTextureId = textureId; + setDirtyFlag(SharedTextureId); + } +} + // Return nullptr if // - context cannot be obtained // - texture hasn't yet been loaded @@ -403,8 +430,8 @@ QOpenGLTexture *GLTexture::buildGLTexture() // is written against GLES 1.0. if (m_properties.format == QAbstractTexture::RGB8_ETC1) { if ((ctx->isOpenGLES() && ctx->format().majorVersion() >= 3) - || ctx->hasExtension(QByteArrayLiteral("GL_OES_compressed_ETC2_RGB8_texture")) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_ES3_compatibility"))) + || ctx->hasExtension(QByteArrayLiteral("GL_OES_compressed_ETC2_RGB8_texture")) + || ctx->hasExtension(QByteArrayLiteral("GL_ARB_ES3_compatibility"))) format = m_properties.format = QAbstractTexture::RGB8_ETC2; } @@ -414,14 +441,14 @@ QOpenGLTexture *GLTexture::buildGLTexture() glTex->setSize(m_properties.width, m_properties.height, m_properties.depth); // Set layers count if texture array if (m_actualTarget == QAbstractTexture::Target1DArray || - m_actualTarget == QAbstractTexture::Target2DArray || - m_actualTarget == QAbstractTexture::Target2DMultisampleArray || - m_actualTarget == QAbstractTexture::TargetCubeMapArray) { + m_actualTarget == QAbstractTexture::Target2DArray || + m_actualTarget == QAbstractTexture::Target2DMultisampleArray || + m_actualTarget == QAbstractTexture::TargetCubeMapArray) { glTex->setLayers(m_properties.layers); } if (m_actualTarget == QAbstractTexture::Target2DMultisample || - m_actualTarget == QAbstractTexture::Target2DMultisampleArray) { + m_actualTarget == QAbstractTexture::Target2DMultisampleArray) { // Set samples count if multisampled texture // (multisampled textures don't have mipmaps) glTex->setSamples(m_properties.samples); @@ -497,8 +524,8 @@ void GLTexture::updateGLTextureParameters() { m_gl->setWrapMode(QOpenGLTexture::DirectionS, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeX)); if (m_actualTarget != QAbstractTexture::Target1D && - m_actualTarget != QAbstractTexture::Target1DArray && - m_actualTarget != QAbstractTexture::TargetBuffer) + m_actualTarget != QAbstractTexture::Target1DArray && + m_actualTarget != QAbstractTexture::TargetBuffer) m_gl->setWrapMode(QOpenGLTexture::DirectionT, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeY)); if (m_actualTarget == QAbstractTexture::Target3D) m_gl->setWrapMode(QOpenGLTexture::DirectionR, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeZ)); @@ -512,6 +539,129 @@ void GLTexture::updateGLTextureParameters() } } +void GLTexture::introspectPropertiesFromSharedTextureId() +{ + // We know that the context is active when this function is called + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx) { + qWarning() << Q_FUNC_INFO << "requires an OpenGL context"; + return; + } + QOpenGLFunctions *gl = ctx->functions(); + + // If the user has set the target format himself, we won't try to deduce it + if (m_properties.target != QAbstractTexture::TargetAutomatic) + return; + + const QAbstractTexture::Target targets[] = { + QAbstractTexture::Target2D, + QAbstractTexture::TargetCubeMap, +#ifndef QT_OPENGL_ES_2 + QAbstractTexture::Target1D, + QAbstractTexture::Target1DArray, + QAbstractTexture::Target3D, + QAbstractTexture::Target2DArray, + QAbstractTexture::TargetCubeMapArray, + QAbstractTexture::Target2DMultisample, + QAbstractTexture::Target2DMultisampleArray, + QAbstractTexture::TargetRectangle, + QAbstractTexture::TargetBuffer, +#endif + }; + +#ifndef QT_OPENGL_ES_2 + // Try to find texture target with GL 4.5 functions + const QPair<int, int> ctxGLVersion = ctx->format().version(); + if (ctxGLVersion.first > 4 || (ctxGLVersion.first == 4 && ctxGLVersion.second >= 5)) { + // Only for GL 4.5+ + QOpenGLFunctions_4_5_Core *gl5 = ctx->versionFunctions<QOpenGLFunctions_4_5_Core>(); +#ifdef GL_TEXTURE_TARGET + if (gl5 != nullptr) + gl5->glGetTextureParameteriv(m_sharedTextureId, GL_TEXTURE_TARGET, reinterpret_cast<int *>(&m_properties.target)); +#endif + } +#endif + + // If GL 4.5 function unavailable or not working, try a slower way + if (m_properties.target == QAbstractTexture::TargetAutomatic) { + // // OpenGL offers no proper way of querying for the target of a texture given its id + gl->glActiveTexture(GL_TEXTURE0); + + const GLenum targetBindings[] = { + GL_TEXTURE_BINDING_2D, + GL_TEXTURE_BINDING_CUBE_MAP, +#ifndef QT_OPENGL_ES_2 + GL_TEXTURE_BINDING_1D, + GL_TEXTURE_BINDING_1D_ARRAY, + GL_TEXTURE_BINDING_3D, + GL_TEXTURE_BINDING_2D_ARRAY, + GL_TEXTURE_BINDING_CUBE_MAP_ARRAY, + GL_TEXTURE_BINDING_2D_MULTISAMPLE, + GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, + GL_TEXTURE_BINDING_RECTANGLE, + GL_TEXTURE_BINDING_BUFFER +#endif + }; + + Q_ASSERT(sizeof(targetBindings) / sizeof(targetBindings[0] == sizeof(targets) / sizeof(targets[0]))); + + for (uint i = 0; i < sizeof(targetBindings) / sizeof(targetBindings[0]); ++i) { + const int target = targets[i]; + gl->glBindTexture(target, m_sharedTextureId); + int boundId = 0; + gl->glGetIntegerv(targetBindings[i], &boundId); + gl->glBindTexture(target, 0); + if (boundId == m_sharedTextureId) { + m_properties.target = static_cast<QAbstractTexture::Target>(target); + break; + } + } + } + + // Return early if we weren't able to find texture target + if (std::find(std::begin(targets), std::end(targets), m_properties.target) == std::end(targets)) { + qWarning() << "Unable to determine texture target for shared GL texture"; + return; + } + + // Bind texture once we know its target + gl->glBindTexture(m_properties.target, m_sharedTextureId); + + // TO DO: Improve by using glGetTextureParameters when available which + // support direct state access +#ifndef GL_TEXTURE_MAX_LEVEL +#define GL_TEXTURE_MAX_LEVEL 0x813D +#endif + +#ifndef GL_TEXTURE_WRAP_R +#define GL_TEXTURE_WRAP_R 0x8072 +#endif + + gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_MAX_LEVEL, reinterpret_cast<int *>(&m_properties.mipLevels)); + gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_MIN_FILTER, reinterpret_cast<int *>(&m_parameters.minificationFilter)); + gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_MAG_FILTER, reinterpret_cast<int *>(&m_parameters.magnificationFilter)); + gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_WRAP_R, reinterpret_cast<int *>(&m_parameters.wrapModeX)); + gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_WRAP_S, reinterpret_cast<int *>(&m_parameters.wrapModeY)); + gl->glGetTexParameteriv(int(m_properties.target), GL_TEXTURE_WRAP_T, reinterpret_cast<int *>(&m_parameters.wrapModeZ)); + +#ifndef QT_OPENGL_ES_2 + // Try to retrieve dimensions (not available on ES 2.0) + if (!ctx->isOpenGLES()) { + QOpenGLFunctions_3_1 *gl3 = ctx->versionFunctions<QOpenGLFunctions_3_1>(); + if (!gl3) { + qWarning() << "Failed to retrieve shared texture dimensions"; + return; + } + + gl3->glGetTexLevelParameteriv(int(m_properties.target), 0, GL_TEXTURE_WIDTH, reinterpret_cast<int *>(&m_properties.width)); + gl3->glGetTexLevelParameteriv(int(m_properties.target), 0, GL_TEXTURE_HEIGHT, reinterpret_cast<int *>(&m_properties.height)); + gl3->glGetTexLevelParameteriv(int(m_properties.target), 0, GL_TEXTURE_DEPTH, reinterpret_cast<int *>(&m_properties.depth)); + gl3->glGetTexLevelParameteriv(int(m_properties.target), 0, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<int *>(&m_properties.format)); + } +#endif + + gl->glBindTexture(m_properties.target, 0); +} } // namespace Render } // namespace Qt3DRender diff --git a/src/render/renderers/opengl/textures/gltexture_p.h b/src/render/renderers/opengl/textures/gltexture_p.h index ca9c0d5db..66f66926c 100644 --- a/src/render/renderers/opengl/textures/gltexture_p.h +++ b/src/render/renderers/opengl/textures/gltexture_p.h @@ -125,6 +125,7 @@ public: inline TextureProperties properties() const { return m_properties; } inline TextureParameters parameters() const { return m_parameters; } inline QTextureGeneratorPtr textureGenerator() const { return m_dataFunctor; } + inline int sharedTextureId() const { return m_sharedTextureId; } inline QVector<Image> images() const { return m_images; } inline QSize size() const { return QSize(m_properties.width, m_properties.height); } @@ -204,14 +205,15 @@ protected: void setProperties(const TextureProperties &props); void setImages(const QVector<Image> &images); void setGenerator(const QTextureGeneratorPtr &generator); + void setSharedTextureId(int textureId); private: enum DirtyFlag { TextureData = 0x01, // one or more image generators have been executed, data needs uploading to GPU Properties = 0x02, // texture needs to be (re-)created - Parameters = 0x04 // texture parameters need to be (re-)set - + Parameters = 0x04, // texture parameters need to be (re-)set + SharedTextureId = 0x08 // texture id from shared context }; bool testDirtyFlag(DirtyFlag flag) @@ -232,6 +234,7 @@ private: void loadTextureDataFromImages(); void uploadGLTextureData(); void updateGLTextureParameters(); + void introspectPropertiesFromSharedTextureId(); void destroyResources(); bool m_unique; @@ -257,6 +260,7 @@ private: QTextureDataPtr m_textureData; QVector<QTextureImageDataPtr> m_imageData; + int m_sharedTextureId; bool m_externalRendering; }; |