[Vulkan] graphics controller, multiple pipelines
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / vulkan-command-buffer.cpp
index 501cd26..ff64a71 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 
 // INTERNAL INCLUDES
+#include <dali/graphics/vulkan/vulkan-types.h>
+#include <dali/graphics/vulkan/vulkan-buffer.h>
 #include <dali/graphics/vulkan/vulkan-command-buffer.h>
 #include <dali/graphics/vulkan/vulkan-command-pool.h>
+#include <dali/graphics/vulkan/vulkan-descriptor-set.h>
 #include <dali/graphics/vulkan/vulkan-graphics.h>
+#include <dali/graphics/vulkan/vulkan-image.h>
+#include <dali/graphics/vulkan/vulkan-fence.h>
+#include <dali/graphics/vulkan/vulkan-pipeline.h>
+#include <dali/graphics/vulkan/vulkan-surface.h>
+#include <dali/graphics/vulkan/vulkan-framebuffer.h>
 
 namespace Dali
 {
@@ -26,182 +34,606 @@ namespace Graphics
 {
 namespace Vulkan
 {
-
-CommandBuffer::CommandBuffer(Graphics& graphics, CommandPool& ownerPool)
-: CommandBuffer(graphics, ownerPool,
-                vk::CommandBufferAllocateInfo().setCommandBufferCount(1).setLevel(vk::CommandBufferLevel::ePrimary))
+struct CommandBuffer::Impl
 {
-}
+  Impl( CommandBuffer& owner, CommandPool& commandPool, uint32_t poolIndex, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer commandBuffer )
+  : mOwner( owner ),
+    mGraphics( commandPool.GetGraphics() ),
+    mOwnerCommandPool( commandPool ),
+    mPoolAllocationIndex( poolIndex ),
+    mAllocateInfo( allocateInfo ),
+    mCommandBuffer( commandBuffer )
+  {
+  }
 
-CommandBuffer::CommandBuffer(Graphics& graphics, CommandPool& ownerPool,
-                             const vk::CommandBufferAllocateInfo& allocateInfo)
-: mGraphics(graphics), mCommandPool(ownerPool), mRecording(false)
-{
-  assert(allocateInfo.commandBufferCount == 1 && "Number of buffers to allocate must be equal 1!");
-  mCommandBuffer = VkAssert(mGraphics.GetDevice().allocateCommandBuffers(allocateInfo))[0];
-}
+  ~Impl()
+  {
+    mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(),
+                                              1, &mCommandBuffer );
+  }
 
-CommandBuffer::~CommandBuffer()
-{
-  if(mCommandBuffer)
+  void ReleaseCommandBuffer()
   {
-    mGraphics.GetDevice().freeCommandBuffers(mCommandPool.GetPool(), mCommandBuffer);
+    mResources.clear();
+
+    // tell pool the buffer is not in use anymore
+    mOwnerCommandPool.ReleaseCommandBuffer(mOwner, false);
   }
-}
 
-/** Begin recording */
-void CommandBuffer::Begin(vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo)
-{
-  assert(!mRecording && "CommandBuffer already is in the recording state");
-  auto info = vk::CommandBufferBeginInfo{};
-  info.setPInheritanceInfo(inheritanceInfo);
-  info.setFlags(usageFlags);
-  VkAssert(mCommandBuffer.begin(info));
-  mRecording = true;
-}
+  bool Initialise()
+  {
+    return true;
+  }
 
-/** Finish recording */
-void CommandBuffer::End()
-{
-  assert(mRecording && "CommandBuffer is not in the recording state!");
-  VkAssert(mCommandBuffer.end());
-  mRecording = false;
-}
+  template<class T>
+  bool IsResourceAdded( Handle<T> resourceHandle )
+  {
+    for( auto&& res : mResources )
+    {
+      if( res == resourceHandle )
+      {
+        return true;
+      }
+    }
+    return false;
+  }
 
-/** Reset command buffer */
-void CommandBuffer::Reset()
-{
-  assert(!mRecording && "Can't reset command buffer during recording!");
-  assert(mCommandBuffer && "Invalid command buffer!");
-  mCommandBuffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources);
-}
+  template<class T>
+  bool PushResource( Handle<T> resourceHandle )
+  {
+    if( !IsResourceAdded( resourceHandle ) )
+    {
+      mResources.push_back( VkTypeCast<VkManaged>( resourceHandle ) );
+      return true;
+    }
+    return false;
+  }
 
-/** Free command buffer */
-void CommandBuffer::Free()
-{
-  assert(mCommandBuffer && "Invalid command buffer!");
-  mGraphics.GetDevice().freeCommandBuffers(mCommandPool.GetPool(), mCommandBuffer);
-}
+  /**
+   *
+   */
+  void Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
+  {
+    assert( !mRecording && "CommandBuffer already is in the recording state" );
+    auto info = vk::CommandBufferBeginInfo{};
+    info.setPInheritanceInfo( inheritanceInfo );
+    info.setFlags( usageFlags );
 
-/** Records image layout transition barrier for one image */
-void CommandBuffer::ImageLayoutTransition(vk::Image            image,
-                                          vk::ImageLayout      oldLayout,
-                                          vk::ImageLayout      newLayout,
-                                          vk::ImageAspectFlags aspectMask)
-{
-  // must be in recording state
+    // set the inheritance option
+    auto inheritance = vk::CommandBufferInheritanceInfo{}.setSubpass( 0 );
 
-  // just push new image barrier until any command is being called or buffer recording ends.
-  // it will make sure we batch barriers together rather than calling cmdPipelineBarrier
-  // for each separately
-  vk::AccessFlags        srcAccessMask, dstAccessMask;
-  vk::PipelineStageFlags srcStageMask, dstStageMask;
+    if( mAllocateInfo.level == vk::CommandBufferLevel::eSecondary )
+    {
+      // Render pass is obtained from the default framebuffer
+      // it's a legacy but little nicer
+      auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
+      inheritance.setRenderPass( swapchain->GetCurrentFramebuffer()->GetVkRenderPass() );
+      info.setPInheritanceInfo( &inheritance );
+    }
+
+    VkAssert( mCommandBuffer.begin( info ) );
 
-  // TODO: add other transitions
-  switch(oldLayout)
+    mResources.clear();
+
+    mRecording = true;
+  }
+
+  void End()
   {
-  case vk::ImageLayout::eUndefined:
+    assert( mRecording && "CommandBuffer is not in the recording state!" );
+    VkAssert( mCommandBuffer.end() );
+    mRecording = false;
+  }
+
+  void Reset()
   {
-    srcStageMask = vk::PipelineStageFlagBits::eTopOfPipe;
+    assert( !mRecording && "Can't reset command buffer during recording!" );
+    assert( mCommandBuffer && "Invalid command buffer!" );
+    mCommandBuffer.reset( vk::CommandBufferResetFlagBits::eReleaseResources );
+
+    mResources.clear();
   }
-  break;
-  case vk::ImageLayout::ePresentSrcKHR:
+
+  void Free()
   {
-    srcStageMask = vk::PipelineStageFlagBits::eBottomOfPipe;
-    srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
+    assert( mCommandBuffer && "Invalid command buffer!" );
+    mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(), mCommandBuffer );
   }
-  break;
-  case vk::ImageLayout::eColorAttachmentOptimal:
+
+
+  /** Push wait semaphores */
+  void PushWaitSemaphores( const std::vector<vk::Semaphore>&          semaphores,
+                           const std::vector<vk::PipelineStageFlags>& stages )
   {
-    srcStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eColorAttachmentOutput;
-    srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
+    mWaitSemaphores = semaphores;
+    mWaitStages     = stages;
   }
-  break;
-  case vk::ImageLayout::eGeneral:
-  case vk::ImageLayout::eDepthStencilAttachmentOptimal:
-  case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
-  case vk::ImageLayout::eShaderReadOnlyOptimal:
-  case vk::ImageLayout::eTransferSrcOptimal:
-  case vk::ImageLayout::eTransferDstOptimal:
-  case vk::ImageLayout::ePreinitialized:
-  case vk::ImageLayout::eSharedPresentKHR:
+
+  /** Push signal semaphores */
+  void PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
   {
+    mSignalSemaphores = semaphores;
   }
+
+  // TODO: handles should be synchronized
+  void BindVertexBuffers( uint32_t                    firstBinding,
+                          uint32_t                    bindingCount,
+                          std::vector<Handle<Buffer>> buffers,
+                          const vk::DeviceSize*       pOffsets )
+  {
+    // update list of used resources and create an array of VkBuffers
+    std::vector<vk::Buffer> vkBuffers;
+    vkBuffers.reserve( buffers.size() );
+    for( auto&& buffer : buffers )
+    {
+      vkBuffers.emplace_back( buffer->GetVkBuffer() );
+      PushResource( buffer );
+    }
+
+    mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets );
+  }
+
+  void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
+  {
+    // validate
+    assert( ( buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer ) &&
+            "The buffer used as index buffer has wrong usage flags!" );
+
+    PushResource( buffer );
+    mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
+  }
+
+  void BindGraphicsPipeline( Handle<Pipeline> pipeline )
+  {
+    PushResource( pipeline );
+    mCurrentPipeline = pipeline;
+    mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
+  }
+
+  void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
+                           Handle<Pipeline>                                           pipeline,
+                           uint32_t                                                   firstSet,
+                           uint32_t                                                   descriptorSetCount )
+  {
+    // update resources
+    PushResource( pipeline );
+    std::vector<vk::DescriptorSet> vkSets;
+    vkSets.reserve( descriptorSets.size() );
+    for( auto&& set : descriptorSets )
+    {
+      vkSets.emplace_back( set->GetVkDescriptorSet() );
+      PushResource( set );
+    }
+
+    // TODO: support dynamic offsets
+    mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics,
+                                       pipeline->GetVkPipelineLayout(),
+                                       firstSet,
+                                       descriptorSetCount,
+                                       vkSets.data(),
+                                       0,
+                                       nullptr );
+  }
+
+  void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
+  {
+    mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
+  }
+
+  void DrawIndexed(
+    uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
+  {
+    mCommandBuffer.drawIndexed(
+      indexCount, instanceCount, firstIndex, static_cast<int32_t>( vertexOffset ), firstInstance );
+  }
+
+  const std::vector<Handle<VkManaged>> GetResources() const
+  {
+    return mResources;
+  }
+
+  // RENDER PASS
+  void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
+  {
+    auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
+    auto surface = mGraphics.GetSurface( 0u );
+    auto frameBuffer = swapchain->GetCurrentFramebuffer();
+    auto renderPass = frameBuffer->GetVkRenderPass();
+    auto clearValues = frameBuffer->GetDefaultClearValues();
+
+    auto info = vk::RenderPassBeginInfo{};
+    info.setFramebuffer( frameBuffer->GetVkFramebuffer() );
+    info.setRenderPass( renderPass );
+    info.setClearValueCount( U32( clearValues.size() ) );
+    info.setPClearValues( clearValues.data() );
+    info.setRenderArea( vk::Rect2D( {0, 0}, surface->GetSize() ) );
+
+    mCurrentRenderPass = renderPass;
+    mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
   }
 
-  switch(newLayout)
+  void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
   {
-  case vk::ImageLayout::eColorAttachmentOptimal:
+    mCurrentRenderPass = renderPassBeginInfo.renderPass;
+    mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
+  }
+
+  void EndRenderPass()
   {
-    dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eFragmentShader;
-    dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eHostWrite;
-    break;
+    mCurrentRenderPass = nullptr;
+    mCommandBuffer.endRenderPass();
   }
-  case vk::ImageLayout::eDepthStencilAttachmentOptimal:
+
+  void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
   {
-    dstStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eEarlyFragmentTests;
-    dstAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
-    break;
+    auto vkBuffers = std::vector<vk::CommandBuffer>{};
+    vkBuffers.reserve( commandBuffers.size() );
+    for( auto&& buf : commandBuffers )
+    {
+      vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
+      PushResource( buf );
+    }
+
+    mCommandBuffer.executeCommands( vkBuffers );
   }
-  case vk::ImageLayout::ePresentSrcKHR:
+
+  void PipelineBarrier( vk::PipelineStageFlags srcStageMask,
+                        vk::PipelineStageFlags dstStageMask,
+                        vk::DependencyFlags dependencyFlags,
+                        std::vector<vk::MemoryBarrier> memoryBarriers,
+                        std::vector<vk::BufferMemoryBarrier> bufferBarriers,
+                        std::vector<vk::ImageMemoryBarrier> imageBarriers )
   {
-    dstStageMask  = vk::PipelineStageFlagBits::eBottomOfPipe;
-    dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eMemoryRead;
+    /*
+     * Track resources
+     */
+    if( !imageBarriers.empty() )
+    {
+      for( auto&& imageBarrier : imageBarriers )
+      {
+        ImageRef imageResource{};
+        if( (imageResource = mGraphics.FindImage( imageBarrier.image )) )
+        {
+          PushResource( imageResource );
+        }
+      }
+    }
+    //@ todo other resource tracking
+
+    mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
   }
-  case vk::ImageLayout::eGeneral:
-  case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
-  case vk::ImageLayout::eShaderReadOnlyOptimal:
-  case vk::ImageLayout::eTransferSrcOptimal:
-  case vk::ImageLayout::eTransferDstOptimal:
-  case vk::ImageLayout::ePreinitialized:
-  case vk::ImageLayout::eUndefined:
-  case vk::ImageLayout::eSharedPresentKHR:
-  default:
+
+  void CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage, vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
   {
+    PushResource( srcBuffer );
+    PushResource( dstImage );
+
+    mCommandBuffer.copyBufferToImage( srcBuffer->GetVkBuffer(), dstImage->GetVkImage(), dstLayout, regions );
   }
+
+  vk::ImageMemoryBarrier ImageLayoutTransitionBarrier( ImageRef image,
+                                                      const vk::AccessFlags&        srcAccessMask,
+                                                      const vk::AccessFlags&        dstAccessMask,
+                                                      vk::ImageLayout        oldLayout,
+                                                      vk::ImageLayout        newLayout,
+                                                      const vk::ImageAspectFlags&   aspectMask
+  ) const
+  {
+    return vk::ImageMemoryBarrier{}
+         .setNewLayout( newLayout )
+         .setImage( image->GetVkImage() )
+         .setOldLayout( oldLayout )
+         .setSrcAccessMask( srcAccessMask )
+         .setDstAccessMask( dstAccessMask )
+         .setSubresourceRange( vk::ImageSubresourceRange{ aspectMask, 0, image->GetLevelCount(), 0, image->GetLayerCount() } );
   }
 
-  RecordImageLayoutTransition(image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask,
-                              oldLayout, newLayout, aspectMask);
+  CommandBuffer&                mOwner;
+  Graphics&                     mGraphics;
+  CommandPool&                  mOwnerCommandPool;
+  uint32_t                      mPoolAllocationIndex;
+  vk::CommandBufferAllocateInfo mAllocateInfo{};
+
+  vk::CommandBuffer mCommandBuffer{};
+
+  // semaphores per command buffer
+  std::vector<vk::Semaphore>          mSignalSemaphores{};
+  std::vector<vk::Semaphore>          mWaitSemaphores{};
+  std::vector<vk::PipelineStageFlags> mWaitStages{};
+
+  std::vector<Handle<VkManaged>> mResources; // used resources
+
+  PipelineRef mCurrentPipeline;
+
+  vk::RenderPass mCurrentRenderPass;
+
+  FenceRef       mFinishedFence;
+
+  bool mRecording{false};
+};
+
+/**
+ *
+ * Class: CommandBuffer
+ *
+ */
+
+CommandBuffer::CommandBuffer( CommandPool&                         commandPool,
+                              uint32_t                             poolIndex,
+                              const vk::CommandBufferAllocateInfo& allocateInfo,
+                              vk::CommandBuffer                    vkCommandBuffer )
+{
+  mImpl = MakeUnique<Impl>( *this, commandPool, poolIndex, allocateInfo, vkCommandBuffer );
 }
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wframe-larger-than="
-void CommandBuffer::RecordImageLayoutTransition(vk::Image image, vk::AccessFlags srcAccessMask,
-                                                vk::AccessFlags dstAccessMask, vk::PipelineStageFlags srcStageMask,
-                                                vk::PipelineStageFlags dstStageMask, vk::ImageLayout oldLayout,
-                                                vk::ImageLayout newLayout, vk::ImageAspectFlags aspectMask)
+CommandBuffer::~CommandBuffer()
 {
-  vk::ImageSubresourceRange subres;
-  subres.setLayerCount(1).setBaseMipLevel(0).setBaseArrayLayer(0).setLevelCount(1).setAspectMask(aspectMask);
+}
 
+/** Begin recording */
+void CommandBuffer::Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
+{
+  mImpl->Begin( usageFlags, inheritanceInfo );
+}
 
-  auto barrier = vk::ImageMemoryBarrier{};
-  barrier
-                     .setImage(image)
-                     .setSubresourceRange(subres)
-                     .setSrcAccessMask(srcAccessMask)
-                     .setDstAccessMask(dstAccessMask)
-                     .setOldLayout(oldLayout)
-                     .setNewLayout(newLayout);
-  ;
-  // todo: implement barriers batching
-  mCommandBuffer.pipelineBarrier(srcStageMask, dstStageMask, vk::DependencyFlags{}, nullptr, nullptr, barrier);
+/** Finish recording */
+void CommandBuffer::End()
+{
+  mImpl->End();
+}
+
+/** Reset command buffer */
+void CommandBuffer::Reset()
+{
+  mImpl->Reset();
+}
+
+/** Free command buffer */
+void CommandBuffer::Free()
+{
+  mImpl->Free();
 }
-#pragma GCC diagnostic pop
 
 /** Push wait semaphores */
-void CommandBuffer::PushWaitSemaphores(const std::vector< vk::Semaphore >&          semaphores,
-                                       const std::vector< vk::PipelineStageFlags >& stages)
+void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>&          semaphores,
+                                        const std::vector<vk::PipelineStageFlags>& stages )
 {
-  mWaitSemaphores = semaphores;
-  mWaitStages     = stages;
+  mImpl->PushWaitSemaphores( semaphores, stages );
 }
 
 /** Push signal semaphores */
-void CommandBuffer::PushSignalSemaphores(const std::vector< vk::Semaphore >& semaphores)
+void CommandBuffer::PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
+{
+  mImpl->PushSignalSemaphores( semaphores );
+}
+
+const std::vector<vk::Semaphore>& CommandBuffer::GetSignalSemaphores() const
+{
+  return mImpl->mSignalSemaphores;
+}
+
+const std::vector<vk::Semaphore>& CommandBuffer::GetSWaitSemaphores() const
+{
+  return mImpl->mWaitSemaphores;
+}
+
+const std::vector<vk::PipelineStageFlags>& CommandBuffer::GetWaitSemaphoreStages() const
+{
+  return mImpl->mWaitStages;
+}
+
+vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
+{
+  return mImpl->mCommandBuffer;
+}
+
+bool CommandBuffer::IsPrimary() const
+{
+  return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
+}
+
+void CommandBuffer::BindVertexBuffers( uint32_t                    firstBinding,
+                                       uint32_t                    bindingCount,
+                                       std::vector<Handle<Buffer>> buffers,
+                                       const vk::DeviceSize*       pOffsets )
+{
+  mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
+}
+
+void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
+{
+  mImpl->BindIndexBuffer( buffer, offset, indexType );
+}
+
+void CommandBuffer::BindVertexBuffer( uint32_t                               binding,
+                                      const Dali::Graphics::Vulkan::Handle<Buffer>& buffer,
+                                      vk::DeviceSize                         offset )
+{
+  mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>( {buffer} ), &offset );
+}
+
+void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
+{
+  mImpl->BindGraphicsPipeline( pipeline );
+}
+
+void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
+                                        Handle<Pipeline>                                           pipeline,
+                                        uint32_t                                                   firstSet,
+                                        uint32_t                                                   descriptorSetCount )
+{
+  mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
+}
+
+void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
+                                        uint32_t                                                   firstSet )
+{
+  mImpl->BindDescriptorSets(
+    descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>( descriptorSets.size() ) );
+}
+
+void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
+{
+  mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
+}
+
+void CommandBuffer::DrawIndexed(
+  uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
+{
+  mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
+}
+
+void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
+{
+  mImpl->BeginRenderPass( framebufferId, bufferIndex );
+}
+
+void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
+{
+  mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
+}
+
+void CommandBuffer::EndRenderPass()
+{
+  mImpl->EndRenderPass();
+}
+
+void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
+{
+  mImpl->ExecuteCommands( commandBuffers );
+}
+
+void CommandBuffer::PipelineBarrier( vk::PipelineStageFlags srcStageMask,
+                      vk::PipelineStageFlags dstStageMask,
+                      vk::DependencyFlags dependencyFlags,
+                      std::vector<vk::MemoryBarrier> memoryBarriers,
+                      std::vector<vk::BufferMemoryBarrier> bufferBarriers,
+                      std::vector<vk::ImageMemoryBarrier> imageBarriers )
+{
+  mImpl->PipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
+}
+
+void CommandBuffer::CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage,
+                                       vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
+{
+  mImpl->CopyBufferToImage( srcBuffer, dstImage, dstLayout, regions );
+}
+
+vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
+                                                     vk::AccessFlags        srcAccessMask,
+                                                     vk::AccessFlags        dstAccessMask,
+                                                     vk::ImageLayout        oldLayout,
+                                                     vk::ImageLayout        newLayout,
+                                                     vk::ImageAspectFlags   aspectMask
+) const
+{
+  return mImpl->ImageLayoutTransitionBarrier( image,
+                                              srcAccessMask, dstAccessMask,
+                                              oldLayout, newLayout,
+                                              aspectMask  );
+}
+
+vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
+                                                     vk::ImageLayout        oldLayout,
+                                                     vk::ImageLayout        newLayout,
+                                                     vk::ImageAspectFlags   aspectMask
+) const
+{
+
+  vk::AccessFlags  srcAccessMask, dstAccessMask;
+  vk::PipelineStageFlags srcStageMask, dstStageMask;
+
+  switch( oldLayout )
+  {
+    case vk::ImageLayout::ePreinitialized:
+    case vk::ImageLayout::eUndefined:
+    {
+      srcAccessMask = {};
+      srcStageMask  = vk::PipelineStageFlagBits::eTopOfPipe;
+      break;
+    }
+    case vk::ImageLayout::ePresentSrcKHR:
+    {
+      srcAccessMask = vk::AccessFlagBits::eColorAttachmentRead;
+      srcStageMask  = vk::PipelineStageFlagBits::eColorAttachmentOutput;
+      break;
+    }
+    case vk::ImageLayout::eTransferSrcOptimal:
+    {
+      srcAccessMask = vk::AccessFlagBits::eMemoryRead;
+      srcStageMask  = vk::PipelineStageFlagBits::eTransfer;
+      break;
+    }
+    case vk::ImageLayout::eTransferDstOptimal:
+    {
+      srcAccessMask = vk::AccessFlagBits::eMemoryWrite;
+      srcStageMask  = vk::PipelineStageFlagBits::eTransfer;
+      break;
+    }
+    case vk::ImageLayout::eGeneral:
+    case vk::ImageLayout::eColorAttachmentOptimal:
+    case vk::ImageLayout::eDepthStencilAttachmentOptimal:
+    case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
+    case vk::ImageLayout::eShaderReadOnlyOptimal:
+    case vk::ImageLayout::eSharedPresentKHR:
+    {
+      break;
+    }
+  }
+
+  switch( newLayout )
+  {
+    case vk::ImageLayout::ePresentSrcKHR:
+    {
+      dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
+      dstStageMask  = vk::PipelineStageFlagBits::eBottomOfPipe;
+      break;
+    }
+    case vk::ImageLayout::eTransferSrcOptimal:
+    {
+      dstAccessMask = vk::AccessFlagBits::eMemoryRead;
+      dstStageMask  = vk::PipelineStageFlagBits::eTransfer;
+      break;
+    }
+    case vk::ImageLayout::eTransferDstOptimal:
+    {
+      dstAccessMask = vk::AccessFlagBits::eMemoryWrite;
+      dstStageMask  = vk::PipelineStageFlagBits::eTransfer;
+      break;
+    }
+    case vk::ImageLayout::eShaderReadOnlyOptimal:
+    {
+      dstAccessMask = vk::AccessFlagBits::eMemoryRead;
+      dstStageMask = vk::PipelineStageFlagBits::eVertexShader;
+      break;
+    }
+    case vk::ImageLayout::eUndefined:
+    case vk::ImageLayout::eGeneral:
+    case vk::ImageLayout::eColorAttachmentOptimal:
+    case vk::ImageLayout::eDepthStencilAttachmentOptimal:
+    case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
+    case vk::ImageLayout::ePreinitialized:
+    case vk::ImageLayout::eSharedPresentKHR:
+    {
+      break;
+    }
+  }
+
+  return mImpl->ImageLayoutTransitionBarrier( image,
+                                              srcAccessMask, dstAccessMask,
+                                              oldLayout, newLayout,
+                                              aspectMask  );
+}
+
+uint32_t CommandBuffer::GetPoolAllocationIndex() const
+{
+  return mImpl->mPoolAllocationIndex;
+}
+
+bool CommandBuffer::OnDestroy()
 {
-  mSignalSemaphores = semaphores;
+  mImpl->ReleaseCommandBuffer();
+  return true;
 }
 
 } // namespace Vulkan