From 9767934b70ebfdc8baa384786c6c5af420acd2b8 Mon Sep 17 00:00:00 2001 From: "adam.b" Date: Fri, 25 May 2018 14:06:18 +0100 Subject: [PATCH] [Vulkan] Indexed draw and topology support - Added index buffer and index draw support - Added setting the topology in rendered geometry Change-Id: I8b660bd154141a5b251d29f5a0cfcc613f229382 --- dali/graphics-api/graphics-api-render-command.h | 23 ++- dali/graphics/vulkan/api/vulkan-api-controller.cpp | 15 +- .../vulkan/api/vulkan-api-render-command.cpp | 27 ++- .../update/rendering/scene-graph-geometry.cpp | 29 ++- .../update/rendering/scene-graph-geometry.h | 39 ++-- .../update/rendering/scene-graph-renderer.cpp | 198 +++++++++++++++------ 6 files changed, 250 insertions(+), 81 deletions(-) diff --git a/dali/graphics-api/graphics-api-render-command.h b/dali/graphics-api/graphics-api-render-command.h index 6cc597e..a911c35 100644 --- a/dali/graphics-api/graphics-api-render-command.h +++ b/dali/graphics-api/graphics-api-render-command.h @@ -207,6 +207,14 @@ public: INDEXED_DRAW, }; + enum class Topology + { + TRIANGLES, + TRIANGLE_FAN, + TRIANGLE_STRIP, + LINES + }; + /** * Describes buffer attribute binding * @@ -493,6 +501,7 @@ public: Accessor shader { nullptr }; BlendState blendState {}; + Topology topology{ Topology::TRIANGLES }; RenderState& SetShader( Accessor value ) { @@ -506,6 +515,12 @@ public: return *this; } + RenderState& SetTopology( Topology value ) + { + topology = value; + return *this; + } + void* pNext{ nullptr }; }; @@ -595,6 +610,12 @@ public: return *this; } + RenderCommand& BindIndexBuffer( const IndexBufferBinding& binding ) + { + mIndexBufferBinding = binding; + return *this; + } + static std::vector NewVertexAttributeBufferBindings() { return std::vector{}; @@ -643,7 +664,7 @@ public: return mTextureBindings; } - const auto& GetIndexBufferBinding() const + const IndexBufferBinding& GetIndexBufferBinding() const { return mIndexBufferBinding; } diff --git a/dali/graphics/vulkan/api/vulkan-api-controller.cpp b/dali/graphics/vulkan/api/vulkan-api-controller.cpp index 2bcae9e..b0526ce 100644 --- a/dali/graphics/vulkan/api/vulkan-api-controller.cpp +++ b/dali/graphics/vulkan/api/vulkan-api-controller.cpp @@ -196,7 +196,20 @@ struct Controller::Impl // draw const auto& drawCommand = apiCommand->GetDrawCommand(); - cmdbuf->Draw( drawCommand.vertexCount, drawCommand.instanceCount, drawCommand.firstVertex, drawCommand.firstInstance ); + + const auto& indexBinding = apiCommand->GetIndexBufferBinding(); + if( indexBinding.buffer.Exists() ) + { + cmdbuf->BindIndexBuffer( static_cast(indexBinding.buffer.Get()).GetBufferRef(), + 0, vk::IndexType::eUint16 ); + cmdbuf->DrawIndexed( drawCommand.indicesCount, drawCommand.instanceCount, + drawCommand.firstIndex, 0, drawCommand.firstInstance ); + } + else + { + cmdbuf->Draw(drawCommand.vertexCount, drawCommand.instanceCount, drawCommand.firstVertex, + drawCommand.firstInstance); + } cmdbuf->End(); cmdBufRefs.emplace_back( cmdbuf ); } diff --git a/dali/graphics/vulkan/api/vulkan-api-render-command.cpp b/dali/graphics/vulkan/api/vulkan-api-render-command.cpp index 3fcdd12..ac31aab 100644 --- a/dali/graphics/vulkan/api/vulkan-api-render-command.cpp +++ b/dali/graphics/vulkan/api/vulkan-api-render-command.cpp @@ -78,6 +78,22 @@ RenderCommand::RenderCommand( VulkanAPI::Controller& controller, Vulkan::Graphic { } +uint32_t GetLocationIndex( const std::vector& attribs, uint32_t location ) +{ + auto retval = 0u; + + for( auto&& attr : attribs ) + { + if( attr.location == location ) + { + return retval; + } + retval++; + } + return -1u; +} + + ///@todo: needs pipeline factory rather than pipeline creation in place!!! bool RenderCommand::PreparePipeline() { @@ -130,7 +146,8 @@ bool RenderCommand::PreparePipeline() attributeDescriptions.emplace_back(vk::VertexInputAttributeDescription{} .setBinding(bindingDescriptions.back() .binding) - .setFormat(attribs[vb.location].format) + .setFormat(attribs[GetLocationIndex( attribs, vb.location)].format) + .setLocation( vb.location ) .setOffset(vb.offset)); } } @@ -334,10 +351,16 @@ const vk::PipelineDepthStencilStateCreateInfo* RenderCommand::PrepareDepthStenci const vk::PipelineInputAssemblyStateCreateInfo* RenderCommand::PrepareInputAssemblyStateCreateInfo() { + auto vkTopology = vk::PrimitiveTopology::eTriangleList; + if( mRenderState.topology == Topology::TRIANGLE_STRIP ) + { + vkTopology = vk::PrimitiveTopology::eTriangleStrip; + } + //@todo support topology and restart return &(mVulkanPipelineState->inputAssembly .setPrimitiveRestartEnable( true ) - .setTopology( vk::PrimitiveTopology::eTriangleStrip )); + .setTopology( vkTopology )); } const vk::PipelineMultisampleStateCreateInfo* RenderCommand::PrepareMultisampleStateCreateInfo() diff --git a/dali/internal/update/rendering/scene-graph-geometry.cpp b/dali/internal/update/rendering/scene-graph-geometry.cpp index 2be9653..1a9baee 100644 --- a/dali/internal/update/rendering/scene-graph-geometry.cpp +++ b/dali/internal/update/rendering/scene-graph-geometry.cpp @@ -22,6 +22,8 @@ #include #include +#include + namespace Dali { namespace Internal @@ -31,11 +33,13 @@ namespace SceneGraph Geometry::Geometry() : mGraphics( nullptr ), - mIndices(), + mIndexBuffer{ nullptr }, + mIndexBufferElementCount( 0 ), mGeometryType( Dali::Geometry::TRIANGLES ), mIndicesChanged(false), mHasBeenUpdated(false), - mAttributesChanged(true) + mAttributesChanged(true), + mHasIndexBuffer(false) { } @@ -56,8 +60,25 @@ void Geometry::AddPropertyBuffer( SceneGraph::PropertyBuffer* propertyBuffer ) void Geometry::SetIndexBuffer( Dali::Vector& indices ) { - mIndices.Swap( indices ); - mIndicesChanged = true; + // set new index buffer + auto& mController = mGraphics->GetController(); + + // create index buffer] + auto sizeInBytes = uint32_t(indices.Size() * sizeof(indices[0])); + auto indexBuffer = mController.CreateBuffer( + mController.GetBufferFactory() + .SetSize( uint32_t(indices.Size() * sizeof(indices[0])) ) + .SetUsage( Graphics::API::Buffer::UsageHint::INDEX_BUFFER ) + ); + + // transfer data + indexBuffer.Get().Write( indices.begin(), sizeInBytes, 0u ); + + mIndexBuffer = indexBuffer; + + mIndexBufferElementCount = uint32_t(indices.Size()); + + mHasIndexBuffer = true; } void Geometry::RemovePropertyBuffer( const SceneGraph::PropertyBuffer* propertyBuffer ) diff --git a/dali/internal/update/rendering/scene-graph-geometry.h b/dali/internal/update/rendering/scene-graph-geometry.h index 0cb85cc..c7e647b 100644 --- a/dali/internal/update/rendering/scene-graph-geometry.h +++ b/dali/internal/update/rendering/scene-graph-geometry.h @@ -101,19 +101,10 @@ public: mGeometryType = type; } - /** - * Upload the geometry if it has changed, set up the attributes and perform - * the Draw call corresponding to the geometry type - * @param[in] bufferIndex The current buffer index - * @param[in] attributeLocation The location for the attributes in the shader - * @param[in] elementBufferOffset The index of first element to draw if index buffer bound - * @param[in] elementBufferCount Number of elements to draw if index buffer bound, uses whole buffer when 0 - */ - void UploadAndDraw( Graphics::API::Controller& controller, - BufferIndex bufferIndex, - Vector& attributeLocation, - size_t elementBufferOffset, - size_t elementBufferCount ); + Type GetType() const + { + return mGeometryType; + } /** * @return @@ -123,24 +114,42 @@ public: return mVertexBuffers; } + Graphics::API::Accessor GetIndexBuffer() + { + return mIndexBuffer; + } + + bool HasIndexBuffer() const + { + return mHasIndexBuffer; + } + + uint32_t GetIndexBufferElementCount() const + { + return mIndexBufferElementCount; + } + + /* const Dali::Vector< unsigned short>& GetIndices() const { return mIndices; } + */ private: Integration::Graphics::Graphics* mGraphics; ///< Graphics interface object // PropertyBuffers Vector< SceneGraph::PropertyBuffer* > mVertexBuffers; - Dali::Vector< unsigned short> mIndices; - + Graphics::API::Accessor mIndexBuffer; + uint32_t mIndexBufferElementCount; Type mGeometryType; // Booleans bool mIndicesChanged : 1; bool mHasBeenUpdated : 1; bool mAttributesChanged : 1; + bool mHasIndexBuffer : 1; }; } // SceneGraph diff --git a/dali/internal/update/rendering/scene-graph-renderer.cpp b/dali/internal/update/rendering/scene-graph-renderer.cpp index 39c2841..d3ff176 100644 --- a/dali/internal/update/rendering/scene-graph-renderer.cpp +++ b/dali/internal/update/rendering/scene-graph-renderer.cpp @@ -250,138 +250,184 @@ void Renderer::UpdateUniformMap( BufferIndex updateBufferIndex ) void Renderer::PrepareRender( BufferIndex updateBufferIndex ) { - auto& controller = mGraphics->GetController(); + auto &controller = mGraphics->GetController(); // prepare all stuff - auto gfxShader = mShader->GetGfxObject(); + auto gfxShader = mShader->GetGfxObject(); - if( !mGfxRenderCommand ) + if (!mGfxRenderCommand) { mGfxRenderCommand = controller.AllocateRenderCommand(); } + if (!mShader->GetGfxObject() + .Exists()) + { + return; + } + /** * Prepare vertex attribute buffer bindings */ - uint32_t bindingIndex { 0u }; - uint32_t locationIndex { 0u }; - auto vertexAttributeBindings = Graphics::API::RenderCommand::NewVertexAttributeBufferBindings(); - for( auto&& vertexBuffer : mGeometry->GetVertexBuffers() ) + uint32_t bindingIndex{0u}; + uint32_t locationIndex{0u}; + auto vertexAttributeBindings = Graphics::API::RenderCommand::NewVertexAttributeBufferBindings(); + for (auto &&vertexBuffer : mGeometry->GetVertexBuffers()) { auto attributeCountInForBuffer = vertexBuffer->GetAttributeCount(); // update vertex buffer if necessary - vertexBuffer->Update( controller ); + vertexBuffer->Update(controller); - for( auto i = 0u; i < attributeCountInForBuffer; ++i ) + for (auto i = 0u; i < attributeCountInForBuffer; ++i) { // create binding per attribute auto binding = Graphics::API::RenderCommand::VertexAttributeBufferBinding{} - .SetOffset( (vertexBuffer->GetFormat()->components[i]).offset ) - .SetBinding( bindingIndex ) - .SetBuffer( vertexBuffer->GetGfxObject() ) - .SetInputAttributeRate( Graphics::API::RenderCommand::InputAttributeRate::PER_VERTEX ) - .SetLocation( locationIndex + i ) - .SetStride( vertexBuffer->GetFormat()->size ); - vertexAttributeBindings.emplace_back( binding ); + .SetOffset((vertexBuffer->GetFormat() + ->components[i]).offset) + .SetBinding(bindingIndex) + .SetBuffer(vertexBuffer->GetGfxObject()) + .SetInputAttributeRate(Graphics::API::RenderCommand::InputAttributeRate::PER_VERTEX) + .SetLocation(locationIndex + i) + .SetStride(vertexBuffer->GetFormat() + ->size); + vertexAttributeBindings.emplace_back(binding); } + locationIndex += attributeCountInForBuffer; } // Invalid input attributes! - if( mShader->GetGfxObject().Get().GetVertexAttributeLocations().size() != vertexAttributeBindings.size()) + if (mShader->GetGfxObject() + .Get() + .GetVertexAttributeLocations() + .size() != vertexAttributeBindings.size()) return; - UpdateUniformMap( updateBufferIndex ); + UpdateUniformMap(updateBufferIndex); - auto& shader = mShader->GetGfxObject().Get(); + auto &shader = mShader->GetGfxObject() + .Get(); auto uboCount = shader.GetUniformBlockCount(); - auto pushConstantsBindings = Graphics::API::RenderCommand::NewPushConstantsBindings( uboCount ); + auto pushConstantsBindings = Graphics::API::RenderCommand::NewPushConstantsBindings(uboCount); // allocate new command ( may be not necessary at all ) // mGfxRenderCommand = Graphics::API::RenderCommandBuilder().Build(); // see if we need to reallocate memory for each UBO // todo: do it only when shader has changed - if( mUboMemory.size() != uboCount ) + if (mUboMemory.size() != uboCount) { mUboMemory.resize(uboCount); } - for( auto i = 0u; i < uboCount; ++i ) + for (auto i = 0u; i < uboCount; ++i) { Graphics::API::ShaderDetails::UniformBlockInfo ubInfo; - std::cout<uniformName); + int arrayIndex = 0; + auto arrayLeftBracket = j->uniformName + .find('['); + if (arrayLeftBracket != std::string::npos) + { + auto arrayRightBracket = j->uniformName + .find(']'); + arrayIndex = std::atoi(&uniformName.c_str()[arrayLeftBracket + 1]); + std::cout << "UNIFORM NAME: " << j->uniformName << ", index: " << arrayIndex << std::endl; + uniformName = uniformName.substr(0, arrayLeftBracket); + } + auto uniformInfo = Graphics::API::ShaderDetails::UniformInfo{}; - if( shader.GetNamedUniform( j->uniformName, uniformInfo ) ) + if (shader.GetNamedUniform(uniformName, uniformInfo)) { // write into correct uniform buffer - auto dst = (mUboMemory[uniformInfo.bufferIndex].data()+uniformInfo.offset); - switch( j->propertyPtr->GetType() ) + auto dst = (mUboMemory[uniformInfo.bufferIndex].data() + uniformInfo.offset); + switch (j->propertyPtr + ->GetType()) { case Property::Type::FLOAT: case Property::Type::INTEGER: case Property::Type::BOOLEAN: { - std::cout << uniformInfo.name << ":["<propertyPtr->GetFloat( updateBufferIndex ), sizeof(float) ); + std::cout << uniformInfo.name << ":[" << uniformInfo.bufferIndex << "]: " << "Writing 32bit offset: " + << uniformInfo.offset << ", size: " << sizeof(float) << std::endl; + dst += sizeof(float) * arrayIndex; + memcpy(dst, &j->propertyPtr + ->GetFloat(updateBufferIndex), sizeof(float)); break; } case Property::Type::VECTOR2: { - std::cout << uniformInfo.name << ":["<propertyPtr->GetVector2( updateBufferIndex ), sizeof(Vector2) ); + std::cout << uniformInfo.name << ":[" << uniformInfo.bufferIndex << "]: " << "Writing vec2 offset: " + << uniformInfo.offset << ", size: " << sizeof(Vector2) << std::endl; + dst += /* sizeof(Vector2) * */arrayIndex * 16; // todo: use array stride from spirv + memcpy(dst, &j->propertyPtr + ->GetVector2(updateBufferIndex), sizeof(Vector2)); break; } case Property::Type::VECTOR3: { - std::cout << uniformInfo.name << ":["<propertyPtr->GetVector3( updateBufferIndex ), sizeof(Vector3) ); + std::cout << uniformInfo.name << ":[" << uniformInfo.bufferIndex << "]: " << "Writing vec3 offset: " + << uniformInfo.offset << ", size: " << sizeof(Vector3) << std::endl; + dst += sizeof(Vector3) * arrayIndex; + memcpy(dst, &j->propertyPtr + ->GetVector3(updateBufferIndex), sizeof(Vector3)); break; } case Property::Type::VECTOR4: { - std::cout << uniformInfo.name << ":["<propertyPtr->GetVector4( updateBufferIndex ), sizeof(Vector4) ); + std::cout << uniformInfo.name << ":[" << uniformInfo.bufferIndex << "]: " << "Writing vec4 offset: " + << uniformInfo.offset << ", size: " << sizeof(Vector4) << std::endl; + dst += sizeof(float) * arrayIndex; + memcpy(dst, &j->propertyPtr + ->GetVector4(updateBufferIndex), sizeof(Vector4)); break; } case Property::Type::MATRIX: { - std::cout << uniformInfo.name << ":["<propertyPtr->GetMatrix( updateBufferIndex ), sizeof(Matrix) ); + std::cout << uniformInfo.name << ":[" << uniformInfo.bufferIndex << "]: " << "Writing mat4 offset: " + << uniformInfo.offset << ", size: " << sizeof(Matrix) << std::endl; + dst += sizeof(Matrix) * arrayIndex; + memcpy(dst, &j->propertyPtr + ->GetMatrix(updateBufferIndex), sizeof(Matrix)); break; } case Property::Type::MATRIX3: { - std::cout << uniformInfo.name << ":["<propertyPtr->GetMatrix3( updateBufferIndex ), sizeof(Matrix3) ); + std::cout << uniformInfo.name << ":[" << uniformInfo.bufferIndex << "]: " << "Writing mat3 offset: " + << uniformInfo.offset << ", size: " << sizeof(Matrix3) << std::endl; + dst += sizeof(Matrix3) * arrayIndex; + memcpy(dst, &j->propertyPtr + ->GetMatrix3(updateBufferIndex), sizeof(Matrix3)); break; } default: - {} + { + } } } } @@ -391,11 +437,11 @@ void Renderer::PrepareRender( BufferIndex updateBufferIndex ) * Prepare textures */ auto textureBindings = Graphics::API::RenderCommand::NewTextureBindings(); - auto samplers = shader.GetSamplers(); + auto samplers = shader.GetSamplers(); - if( mTextureSet ) + if (mTextureSet) { - if(!samplers.empty()) + if (!samplers.empty()) { for (auto i = 0u; i < mTextureSet->GetTextureCount(); ++i) { @@ -416,24 +462,60 @@ void Renderer::PrepareRender( BufferIndex updateBufferIndex ) // todo: this may be deferred until all render items are sorted, otherwise // certain optimisations cannot be done - const auto& vb = mGeometry->GetVertexBuffers()[0]; - //vb->Update() + const auto &vb = mGeometry->GetVertexBuffers()[0]; + + // set optional index buffer + bool usesIndexBuffer{false}; + auto topology = Graphics::API::RenderCommand::Topology::TRIANGLE_STRIP; + if ((usesIndexBuffer = mGeometry->HasIndexBuffer())) + { + mGfxRenderCommand->BindIndexBuffer(Graphics::API::RenderCommand::IndexBufferBinding() + .SetBuffer(mGeometry->GetIndexBuffer()) + .SetOffset(0) + ); + } + auto type = mGeometry->GetType(); + switch (type) + { + case Dali::Geometry::Type::TRIANGLE_STRIP: + { + topology = Graphics::API::RenderCommand::Topology::TRIANGLE_STRIP; + break; + } + default: + { + topology = Graphics::API::RenderCommand::Topology::TRIANGLES; + } + } mGfxRenderCommand->PushConstants( std::move(pushConstantsBindings) ); mGfxRenderCommand->BindVertexBuffers( std::move(vertexAttributeBindings) ); mGfxRenderCommand->BindTextures( std::move(textureBindings) ); mGfxRenderCommand->BindRenderState( Graphics::API::RenderCommand::RenderState{} .SetShader( mShader->GetGfxObject() ) - .SetBlendState( { mBlendMode != BlendMode::OFF }) ); - mGfxRenderCommand->Draw( std::move(Graphics::API::RenderCommand::DrawCommand{} - .SetFirstVertex(0u) - .SetDrawType( Graphics::API::RenderCommand::DrawType::VERTEX_DRAW ) - .SetFirstInstance(0u) - .SetVertexCount( vb->GetElementCount() ) - .SetInstanceCount( 1u ))); + .SetBlendState( { mBlendMode != BlendMode::OFF }) + .SetTopology( topology )); + if(usesIndexBuffer) + { + mGfxRenderCommand->Draw(std::move(Graphics::API::RenderCommand::DrawCommand{} + .SetFirstIndex( uint32_t(mIndexedDrawFirstElement) ) + .SetDrawType(Graphics::API::RenderCommand::DrawType::INDEXED_DRAW) + .SetFirstInstance(0u) + .SetIndicesCount( mGeometry->GetIndexBufferElementCount() ) + .SetInstanceCount(1u))); + } + else + { + mGfxRenderCommand->Draw(std::move(Graphics::API::RenderCommand::DrawCommand{} + .SetFirstVertex(0u) + .SetDrawType(Graphics::API::RenderCommand::DrawType::VERTEX_DRAW) + .SetFirstInstance(0u) + .SetVertexCount(vb->GetElementCount()) + .SetInstanceCount(1u))); + } std::cout << "done\n"; } -- 2.7.4