From 9486a8a4b60a678280db2c625064ca78b3aaf489 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 21 Sep 2018 07:53:11 +0200 Subject: Complete ES 3.1 and 3.2 helpers Which didn't handle indirect drawing, compute and tessellation Since ES 3.1/3.2 don't provide API for glShaderStorageBlockBinding, code was adjusted to use the default binding points and not require that API. Change-Id: Ie4dcd05f0a1d72e4a25f49b5fae138dc605ba5e3 Task-number: QTBUG-70660 Reviewed-by: Sean Harmer --- .../opengl/graphicshelpers/graphicshelperes3_1.cpp | 168 +++++++++++++++++++++ .../opengl/graphicshelpers/graphicshelperes3_1_p.h | 8 + .../opengl/graphicshelpers/graphicshelperes3_2.cpp | 20 +++ .../opengl/graphicshelpers/graphicshelperes3_2_p.h | 3 + .../opengl/graphicshelpers/submissioncontext.cpp | 10 +- .../renderers/opengl/renderer/renderview.cpp | 1 + .../opengl/renderer/shaderparameterpack_p.h | 1 + .../graphicshelpergl4/tst_graphicshelpergl4.cpp | 21 ++- 8 files changed, 228 insertions(+), 4 deletions(-) diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp index 135e83aec..a555b67ef 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp @@ -53,10 +53,114 @@ QT_BEGIN_NAMESPACE #ifndef GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A #endif +#ifndef GL_ACTIVE_RESOURCES +#define GL_ACTIVE_RESOURCES 0x92F5 +#endif +#ifndef GL_BUFFER_BINDING +#define GL_BUFFER_BINDING 0x9302 +#endif +#ifndef GL_BUFFER_DATA_SIZE +#define GL_BUFFER_DATA_SIZE 0x9303 +#endif +#ifndef GL_NUM_ACTIVE_VARIABLES +#define GL_NUM_ACTIVE_VARIABLES 0x9304 +#endif +#ifndef GL_SHADER_STORAGE_BLOCK +#define GL_SHADER_STORAGE_BLOCK 0x92E6 +#endif +#ifndef GL_ALL_BARRIER_BITS +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF +#endif +#ifndef GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#endif +#ifndef GL_ELEMENT_ARRAY_BARRIER_BIT +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#endif +#ifndef GL_UNIFORM_BARRIER_BIT +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#endif +#ifndef GL_TEXTURE_FETCH_BARRIER_BIT +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#endif +#ifndef GL_SHADER_IMAGE_ACCESS_BARRIER_BIT +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#endif +#ifndef GL_COMMAND_BARRIER_BIT +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#endif +#ifndef GL_PIXEL_BUFFER_BARRIER_BIT +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#endif +#ifndef GL_TEXTURE_UPDATE_BARRIER_BIT +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#endif +#ifndef GL_BUFFER_UPDATE_BARRIER_BIT +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#endif +#ifndef GL_FRAMEBUFFER_BARRIER_BIT +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#endif +#ifndef GL_TRANSFORM_FEEDBACK_BARRIER_BIT +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 +#endif +#ifndef GL_ATOMIC_COUNTER_BARRIER_BIT +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#endif +#ifndef GL_SHADER_STORAGE_BARRIER_BIT +#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 +#endif + namespace Qt3DRender { namespace Render { +namespace { + +GLbitfield memoryBarrierGLBitfield(QMemoryBarrier::Operations barriers) +{ + GLbitfield bits = 0; + + if (barriers.testFlag(QMemoryBarrier::All)) { + bits |= GL_ALL_BARRIER_BITS; + return bits; + } + + if (barriers.testFlag(QMemoryBarrier::VertexAttributeArray)) + bits |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::ElementArray)) + bits |= GL_ELEMENT_ARRAY_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::Uniform)) + bits |= GL_UNIFORM_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::TextureFetch)) + bits |= GL_TEXTURE_FETCH_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::ShaderImageAccess)) + bits |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::Command)) + bits |= GL_COMMAND_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::PixelBuffer)) + bits |= GL_PIXEL_BUFFER_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::TextureUpdate)) + bits |= GL_TEXTURE_UPDATE_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::BufferUpdate)) + bits |= GL_BUFFER_UPDATE_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::FrameBuffer)) + bits |= GL_FRAMEBUFFER_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::TransformFeedback)) + bits |= GL_TRANSFORM_FEEDBACK_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::AtomicCounter)) + bits |= GL_ATOMIC_COUNTER_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::ShaderStorage)) + bits |= GL_SHADER_STORAGE_BARRIER_BIT; + if (barriers.testFlag(QMemoryBarrier::QueryBuffer)) + qWarning() << "QueryBuffer barrier not supported by ES 3.1"; + + return bits; +} + +} // anonymous + + GraphicsHelperES3_1::GraphicsHelperES3_1() { } @@ -65,6 +169,70 @@ GraphicsHelperES3_1::~GraphicsHelperES3_1() { } +bool GraphicsHelperES3_1::supportsFeature(GraphicsHelperInterface::Feature feature) const +{ + switch (feature) { + case GraphicsHelperInterface::Compute: + case GraphicsHelperInterface::ShaderStorageObject: + case GraphicsHelperInterface::IndirectDrawing: + return true; + default: + break; + } + return GraphicsHelperES3::supportsFeature(feature); +} + +void GraphicsHelperES3_1::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) +{ + m_extraFuncs->glDispatchCompute(wx, wy, wz); +} + +void GraphicsHelperES3_1::memoryBarrier(QMemoryBarrier::Operations barriers) +{ + m_extraFuncs->glMemoryBarrier(memoryBarrierGLBitfield(barriers)); +} + +void GraphicsHelperES3_1::drawArraysIndirect(GLenum mode, void *indirect) +{ + m_extraFuncs->glDrawArraysIndirect(mode, indirect); +} + +void GraphicsHelperES3_1::drawElementsIndirect(GLenum mode, GLenum type, void *indirect) +{ + m_extraFuncs->glDrawElementsIndirect(mode, type, indirect); +} + +void GraphicsHelperES3_1::bindShaderStorageBlock(GLuint , GLuint , GLuint ) +{ + // ES 3.1 has no API for that, bindings have to be specified directly in the shader + // with layout(std430, binding = 3) + qWarning() << "ES 3.1 has no bindShaderStorageBlock API, it uses binding declaration from the shader storage block"; +} + +QVector GraphicsHelperES3_1::programShaderStorageBlocks(GLuint programId) +{ + QVector blocks; + GLint nbrActiveShaderStorageBlocks = 0; + m_extraFuncs->glGetProgramInterfaceiv(programId, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &nbrActiveShaderStorageBlocks); + blocks.reserve(nbrActiveShaderStorageBlocks); + for (GLint i = 0; i < nbrActiveShaderStorageBlocks; ++i) { + QByteArray storageBlockName(256, '\0'); + GLsizei length = 0; + ShaderStorageBlock storageBlock; + m_extraFuncs->glGetProgramResourceName(programId, GL_SHADER_STORAGE_BLOCK, i, 256, &length, storageBlockName.data()); + storageBlock.m_index = i; + storageBlock.m_name = QString::fromUtf8(storageBlockName.left(length)); + GLenum prop = GL_BUFFER_BINDING; + m_extraFuncs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_binding); + prop = GL_BUFFER_DATA_SIZE; + m_extraFuncs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_size); + prop = GL_NUM_ACTIVE_VARIABLES; + m_extraFuncs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_activeVariablesCount); + blocks.push_back(storageBlock); + } + return blocks; +} + UniformType GraphicsHelperES3_1::uniformTypeFromGLType(GLenum glType) { switch (glType) { diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h index 70a584380..2c130fbf5 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h @@ -64,6 +64,14 @@ public: GraphicsHelperES3_1(); ~GraphicsHelperES3_1(); + bool supportsFeature(Feature feature) const override; + void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) override; + void memoryBarrier(QMemoryBarrier::Operations barriers) override; + void drawArraysIndirect(GLenum mode,void *indirect) override; + void drawElementsIndirect(GLenum mode, GLenum type, void *indirect) override; + void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override; + QVector programShaderStorageBlocks(GLuint programId) override; + // QGraphicHelperInterface interface UniformType uniformTypeFromGLType(GLenum glType) override; uint uniformByteSize(const ShaderUniform &description) override; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp index 6290d091d..9dce08e4f 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp @@ -52,6 +52,10 @@ QT_BEGIN_NAMESPACE #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #endif +#ifndef GL_PATCH_VERTICES +#define GL_PATCH_VERTICES 36466 +#endif + namespace Qt3DRender { namespace Render { @@ -63,6 +67,17 @@ GraphicsHelperES3_2::~GraphicsHelperES3_2() { } +bool GraphicsHelperES3_2::supportsFeature(GraphicsHelperInterface::Feature feature) const +{ + switch (feature) { + case GraphicsHelperInterface::Tessellation: + return true; + default: + break; + } + return GraphicsHelperES3_1::supportsFeature(feature); +} + bool GraphicsHelperES3_2::frameBufferNeedsRenderBuffer(const Attachment &attachment) { Q_UNUSED(attachment); @@ -97,6 +112,11 @@ void GraphicsHelperES3_2::bindFrameBufferAttachment(QOpenGLTexture *texture, con texture->release(); } +void GraphicsHelperES3_2::setVerticesPerPatch(GLint verticesPerPatch) +{ + m_extraFuncs->glPatchParameteri(GL_PATCH_VERTICES, verticesPerPatch); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h index 787bba5f0..ed71b1e3e 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h @@ -64,9 +64,12 @@ public: GraphicsHelperES3_2(); ~GraphicsHelperES3_2(); + bool supportsFeature(Feature feature) const override; + // QGraphicHelperInterface interface void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override; bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override; + void setVerticesPerPatch(GLint verticesPerPatch) override; }; } // namespace Render diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp index 7bb0713ee..26ee94305 100644 --- a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp +++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp @@ -1291,15 +1291,19 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) // Bind Shader Storage block to SSBO and update SSBO const QVector blockToSSBOs = parameterPack.shaderStorageBuffers(); - int ssboIndex = 0; for (const BlockToSSBO b : blockToSSBOs) { Buffer *cpuBuffer = m_renderer->nodeManagers()->bufferManager()->lookupResource(b.m_bufferID); GLBuffer *ssbo = glBufferForRenderBuffer(cpuBuffer, GLBuffer::ShaderStorageBuffer); - bindShaderStorageBlock(shader->programId(), b.m_blockIndex, ssboIndex); + + // bindShaderStorageBlock + // This is currently not required as we are introspecting the bindingIndex + // value from the shaders and not replacing them, making such a call useless + // bindShaderStorageBlock(shader->programId(), b.m_blockIndex, b.m_bindingIndex); + // Needed to avoid conflict where the buffer would already // be bound as a VertexArray bindGLBuffer(ssbo, GLBuffer::ShaderStorageBuffer); - ssbo->bindBufferBase(this, ssboIndex++, GLBuffer::ShaderStorageBuffer); + ssbo->bindBufferBase(this, b.m_bindingIndex, GLBuffer::ShaderStorageBuffer); // TO DO: Make sure that there's enough binding points } diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp index c29448570..66299e430 100644 --- a/src/render/renderers/opengl/renderer/renderview.cpp +++ b/src/render/renderers/opengl/renderer/renderview.cpp @@ -884,6 +884,7 @@ void RenderView::setShaderStorageValue(ShaderParameterPack &uniformPack, BlockToSSBO shaderStorageBlock; shaderStorageBlock.m_blockIndex = block.m_index; shaderStorageBlock.m_bufferID = buffer->peerId(); + shaderStorageBlock.m_bindingIndex = block.m_binding; uniformPack.setShaderStorageBuffer(shaderStorageBlock); // Buffer update to GL buffer will be done at render time } diff --git a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h index 5703bb17b..fe9ab3995 100644 --- a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h +++ b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h @@ -83,6 +83,7 @@ QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, BlockToUBO, Q_MOVABLE_TYPE) struct BlockToSSBO { int m_blockIndex; + int m_bindingIndex; Qt3DCore::QNodeId m_bufferID; }; QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, BlockToSSBO, Q_PRIMITIVE_TYPE) diff --git a/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp index 5a96cf116..39bd15021 100644 --- a/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp +++ b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp @@ -185,7 +185,7 @@ const QByteArray computeShader = QByteArrayLiteral( " vec4 direction;\n" \ " vec4 color;\n" \ "};\n" \ - "layout (std140, binding = 0) coherent buffer Particles\n" \ + "layout (std140, binding = 6) coherent buffer Particles\n" \ "{\n" \ " ParticleData particles[];\n" \ "} data;\n" \ @@ -508,11 +508,29 @@ private Q_SLOTS: GLint index = m_func->glGetProgramResourceIndex(shaderProgram.programId(), GL_SHADER_STORAGE_BLOCK, "Particles"); + // THEN + GLint binding = -1; + GLenum prop = GL_BUFFER_BINDING; + m_func->glGetProgramResourceiv(shaderProgram.programId(), + GL_SHADER_STORAGE_BLOCK, + index, + 1, &prop, + 4, NULL, &binding); + QCOMPARE(binding, 6); + + // WHEN m_glHelper.bindShaderStorageBlock(shaderProgram.programId(), index, 1); // THEN const GLint error = m_func->glGetError(); QVERIFY(error == 0); + + m_func->glGetProgramResourceiv(shaderProgram.programId(), + GL_SHADER_STORAGE_BLOCK, + index, + 1, &prop, + 4, NULL, &binding); + QCOMPARE(binding, 1); } void bindUniformBlock() @@ -1286,6 +1304,7 @@ private Q_SLOTS: QCOMPARE(block.m_name, QStringLiteral("Particles")); QCOMPARE(block.m_activeVariablesCount, 3); QCOMPARE(block.m_index, 0); + QCOMPARE(block.m_binding, 6); QCOMPARE(block.m_size, (4 + 4 + 4) * 4); } -- cgit v1.2.3