[Vulkan] Indexed draw and topology support
authoradam.b <jsr184@gmail.com>
Fri, 25 May 2018 13:06:18 +0000 (14:06 +0100)
committeradam.b <jsr184@gmail.com>
Fri, 25 May 2018 15:51:13 +0000 (16:51 +0100)
- 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
dali/graphics/vulkan/api/vulkan-api-controller.cpp
dali/graphics/vulkan/api/vulkan-api-render-command.cpp
dali/internal/update/rendering/scene-graph-geometry.cpp
dali/internal/update/rendering/scene-graph-geometry.h
dali/internal/update/rendering/scene-graph-renderer.cpp

index 6cc597e..a911c35 100644 (file)
@@ -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> shader { nullptr };
     BlendState blendState {};
+    Topology topology{ Topology::TRIANGLES };
 
     RenderState& SetShader( Accessor<Shader> 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<VertexAttributeBufferBinding> NewVertexAttributeBufferBindings()
   {
     return std::vector<VertexAttributeBufferBinding>{};
@@ -643,7 +664,7 @@ public:
     return mTextureBindings;
   }
 
-  const auto& GetIndexBufferBinding() const
+  const IndexBufferBinding& GetIndexBufferBinding() const
   {
     return mIndexBufferBinding;
   }
index 2bcae9e..b0526ce 100644 (file)
@@ -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<const VulkanAPI::Buffer&>(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 );
     }
index 3fcdd12..ac31aab 100644 (file)
@@ -78,6 +78,22 @@ RenderCommand::RenderCommand( VulkanAPI::Controller& controller, Vulkan::Graphic
 {
 }
 
+uint32_t GetLocationIndex( const std::vector<Vulkan::SpirV::SPIRVVertexInputAttribute>& 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()
index 2be9653..1a9baee 100644 (file)
@@ -22,6 +22,8 @@
 #include <dali/internal/common/buffer-index.h>
 #include <dali/internal/update/rendering/scene-graph-property-buffer.h>
 
+#include <dali/graphics-api/graphics-api-buffer.h>
+
 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<unsigned short>& 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 )
index 0cb85cc..c7e647b 100644 (file)
@@ -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<uint32_t>& attributeLocation,
-                      size_t elementBufferOffset,
-                      size_t elementBufferCount );
+  Type GetType() const
+  {
+    return mGeometryType;
+  }
 
   /**
    * @return
@@ -123,24 +114,42 @@ public:
     return mVertexBuffers;
   }
 
+  Graphics::API::Accessor<Graphics::API::Buffer> 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<Graphics::API::Buffer> mIndexBuffer;
+  uint32_t mIndexBufferElementCount;
   Type mGeometryType;
 
   // Booleans
   bool mIndicesChanged : 1;
   bool mHasBeenUpdated : 1;
   bool mAttributesChanged : 1;
+  bool mHasIndexBuffer : 1;
 };
 
 } // SceneGraph
index 39c2841..d3ff176 100644 (file)
@@ -250,138 +250,184 @@ void Renderer::UpdateUniformMap( BufferIndex updateBufferIndex )
 
 void Renderer::PrepareRender( BufferIndex updateBufferIndex )
 {
-  autocontroller = 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<<sizeof(ubInfo) << std::endl;
+    std::cout << sizeof(ubInfo) << std::endl;
 
-    shader.GetUniformBlock( i, ubInfo );
+    shader.GetUniformBlock(i, ubInfo);
 
-    if( mUboMemory[i].size() != ubInfo.size )
+    if (mUboMemory[i].size() != ubInfo.size)
     {
-      mUboMemory[i].resize( ubInfo.size );
+      mUboMemory[i].resize(ubInfo.size);
     }
 
     // Set push constant bindings
     auto &pushBinding = pushConstantsBindings[i];
-    pushBinding.data = mUboMemory[i].data();
-    pushBinding.size = uint32_t(mUboMemory[i].size());
+    pushBinding.data    = mUboMemory[i].data();
+    pushBinding.size    = uint32_t(mUboMemory[i].size());
     pushBinding.binding = ubInfo.binding;
   }
 
   // add built-in uniforms
 
   // write to memory
-  for( auto&& i : mCollectedUniformMap )
+  for (auto &&i : mCollectedUniformMap)
   {
-    for( auto&& j : i )
+    for (auto &&j : i)
     {
+      std::string uniformName(j->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 << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing 32bit offset: " << uniformInfo.offset << ", size: " << sizeof(float) << std::endl;
-            memcpy( dst, &j->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 << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing vec2 offset: " << uniformInfo.offset << ", size: " << sizeof(Vector2) << std::endl;
-            memcpy( dst, &j->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 << ":["<<uniformInfo.bufferIndex<<"]: " <<  "Writing vec3 offset: " << uniformInfo.offset << ", size: " << sizeof(Vector3) << std::endl;
-            memcpy( dst, &j->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 << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing vec4 offset: " << uniformInfo.offset << ", size: " << sizeof(Vector4) << std::endl;
-            memcpy( dst, &j->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 << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing mat4 offset: " << uniformInfo.offset << ", size: " << sizeof(Matrix) << std::endl;
-            memcpy( dst, &j->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 << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing mat3 offset: " << uniformInfo.offset << ", size: " << sizeof(Matrix3) << std::endl;
-            memcpy( dst, &j->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";
 }