[Vulkan] Managed command buffer pool
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / vulkan-command-buffer.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // INTERNAL INCLUDES
19 #include <dali/graphics/vulkan/vulkan-types.h>
20 #include <dali/graphics/vulkan/vulkan-buffer.h>
21 #include <dali/graphics/vulkan/vulkan-command-buffer.h>
22 #include <dali/graphics/vulkan/vulkan-command-pool.h>
23 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
24 #include <dali/graphics/vulkan/vulkan-graphics.h>
25 #include <dali/graphics/vulkan/vulkan-image.h>
26 #include <dali/graphics/vulkan/vulkan-fence.h>
27 #include <dali/graphics/vulkan/vulkan-pipeline.h>
28 #include <dali/graphics/vulkan/vulkan-surface.h>
29 #include <dali/graphics/vulkan/vulkan-framebuffer.h>
30
31 namespace Dali
32 {
33 namespace Graphics
34 {
35 namespace Vulkan
36 {
37 struct CommandBuffer::Impl
38 {
39   Impl( CommandBuffer& owner, CommandPool& commandPool, uint32_t poolIndex, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer commandBuffer )
40   : mOwner( owner ),
41     mGraphics( commandPool.GetGraphics() ),
42     mOwnerCommandPool( commandPool ),
43     mPoolAllocationIndex( poolIndex ),
44     mAllocateInfo( allocateInfo ),
45     mCommandBuffer( commandBuffer )
46   {
47   }
48
49   ~Impl()
50   {
51     mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(),
52                                               1, &mCommandBuffer );
53   }
54
55   void ReleaseCommandBuffer()
56   {
57     mResources.clear();
58
59     // tell pool the buffer is not in use anymore
60     mOwnerCommandPool.ReleaseCommandBuffer(mOwner, false);
61   }
62
63   bool Initialise()
64   {
65     return true;
66   }
67
68   template<class T>
69   bool IsResourceAdded( Handle<T> resourceHandle )
70   {
71     for( auto&& res : mResources )
72     {
73       if( res == resourceHandle )
74       {
75         return true;
76       }
77     }
78     return false;
79   }
80
81   template<class T>
82   bool PushResource( Handle<T> resourceHandle )
83   {
84     if( !IsResourceAdded( resourceHandle ) )
85     {
86       mResources.push_back( VkTypeCast<VkManaged>( resourceHandle ) );
87       return true;
88     }
89     return false;
90   }
91
92   /**
93    *
94    */
95   void Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
96   {
97     assert( !mRecording && "CommandBuffer already is in the recording state" );
98     auto info = vk::CommandBufferBeginInfo{};
99     info.setPInheritanceInfo( inheritanceInfo );
100     info.setFlags( usageFlags );
101
102     // set the inheritance option
103     auto inheritance = vk::CommandBufferInheritanceInfo{}.setSubpass( 0 );
104
105     if( mAllocateInfo.level == vk::CommandBufferLevel::eSecondary )
106     {
107       // Render pass is obtained from the default framebuffer
108       // it's a legacy but little nicer
109       auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
110       inheritance.setRenderPass( swapchain->GetCurrentFramebuffer()->GetVkRenderPass() );
111       info.setPInheritanceInfo( &inheritance );
112     }
113
114     VkAssert( mCommandBuffer.begin( info ) );
115
116     mResources.clear();
117
118     mRecording = true;
119   }
120
121   void End()
122   {
123     assert( mRecording && "CommandBuffer is not in the recording state!" );
124     VkAssert( mCommandBuffer.end() );
125     mRecording = false;
126   }
127
128   void Reset()
129   {
130     assert( !mRecording && "Can't reset command buffer during recording!" );
131     assert( mCommandBuffer && "Invalid command buffer!" );
132     mCommandBuffer.reset( vk::CommandBufferResetFlagBits::eReleaseResources );
133
134     mResources.clear();
135   }
136
137   void Free()
138   {
139     assert( mCommandBuffer && "Invalid command buffer!" );
140     mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(), mCommandBuffer );
141   }
142
143 #pragma GCC diagnostic pop
144
145   /** Push wait semaphores */
146   void PushWaitSemaphores( const std::vector<vk::Semaphore>&          semaphores,
147                            const std::vector<vk::PipelineStageFlags>& stages )
148   {
149     mWaitSemaphores = semaphores;
150     mWaitStages     = stages;
151   }
152
153   /** Push signal semaphores */
154   void PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
155   {
156     mSignalSemaphores = semaphores;
157   }
158
159   // TODO: handles should be synchronized
160   void BindVertexBuffers( uint32_t                    firstBinding,
161                           uint32_t                    bindingCount,
162                           std::vector<Handle<Buffer>> buffers,
163                           const vk::DeviceSize*       pOffsets )
164   {
165     // update list of used resources and create an array of VkBuffers
166     std::vector<vk::Buffer> vkBuffers;
167     vkBuffers.reserve( buffers.size() );
168     for( auto&& buffer : buffers )
169     {
170       vkBuffers.emplace_back( buffer->GetVkBuffer() );
171       PushResource( buffer );
172     }
173
174     mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets );
175   }
176
177   void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
178   {
179     // validate
180     assert( ( buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer ) &&
181             "The buffer used as index buffer has wrong usage flags!" );
182
183     PushResource( buffer );
184     mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
185   }
186
187   void BindGraphicsPipeline( Handle<Pipeline> pipeline )
188   {
189     PushResource( pipeline );
190     mCurrentPipeline = pipeline;
191     mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
192   }
193
194   void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
195                            Handle<Pipeline>                                           pipeline,
196                            uint32_t                                                   firstSet,
197                            uint32_t                                                   descriptorSetCount )
198   {
199     // update resources
200     PushResource( pipeline );
201     std::vector<vk::DescriptorSet> vkSets;
202     vkSets.reserve( descriptorSets.size() );
203     for( auto&& set : descriptorSets )
204     {
205       vkSets.emplace_back( set->GetVkDescriptorSet() );
206       PushResource( set );
207     }
208
209     // TODO: support dynamic offsets
210     mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics,
211                                        pipeline->GetVkPipelineLayout(),
212                                        firstSet,
213                                        descriptorSetCount,
214                                        vkSets.data(),
215                                        0,
216                                        nullptr );
217   }
218
219   void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
220   {
221     mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
222   }
223
224   void DrawIndexed(
225     uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
226   {
227     mCommandBuffer.drawIndexed(
228       indexCount, instanceCount, firstIndex, static_cast<int32_t>( vertexOffset ), firstInstance );
229   }
230
231   const std::vector<Handle<VkManaged>> GetResources() const
232   {
233     return mResources;
234   }
235
236   // RENDER PASS
237   void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
238   {
239     auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
240     auto surface = mGraphics.GetSurface( 0u );
241     auto frameBuffer = swapchain->GetCurrentFramebuffer();
242     auto renderPass = frameBuffer->GetVkRenderPass();
243     auto clearValues = frameBuffer->GetDefaultClearValues();
244
245     auto info = vk::RenderPassBeginInfo{};
246     info.setFramebuffer( frameBuffer->GetVkFramebuffer() );
247     info.setRenderPass( renderPass );
248     info.setClearValueCount( U32( clearValues.size() ) );
249     info.setPClearValues( clearValues.data() );
250     info.setRenderArea( vk::Rect2D( {0, 0}, surface->GetSize() ) );
251
252     mCurrentRenderPass = renderPass;
253     mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
254   }
255
256   void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
257   {
258     mCurrentRenderPass = renderPassBeginInfo.renderPass;
259     mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
260   }
261
262   void EndRenderPass()
263   {
264     mCurrentRenderPass = nullptr;
265     mCommandBuffer.endRenderPass();
266   }
267
268   void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
269   {
270     auto vkBuffers = std::vector<vk::CommandBuffer>{};
271     vkBuffers.reserve( commandBuffers.size() );
272     for( auto&& buf : commandBuffers )
273     {
274       vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
275       PushResource( buf );
276     }
277
278     mCommandBuffer.executeCommands( vkBuffers );
279   }
280
281   void PipelineBarrier( vk::PipelineStageFlags srcStageMask,
282                         vk::PipelineStageFlags dstStageMask,
283                         vk::DependencyFlags dependencyFlags,
284                         std::vector<vk::MemoryBarrier> memoryBarriers,
285                         std::vector<vk::BufferMemoryBarrier> bufferBarriers,
286                         std::vector<vk::ImageMemoryBarrier> imageBarriers )
287   {
288     /*
289      * Track resources
290      */
291     if( !imageBarriers.empty() )
292     {
293       for( auto&& imageBarrier : imageBarriers )
294       {
295         ImageRef imageResource{};
296         if( imageResource = mGraphics.FindImage( imageBarrier.image ) )
297         {
298           PushResource( imageResource );
299         }
300       }
301     }
302     //@ todo other resource tracking
303
304     mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
305   }
306
307   void CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage, vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
308   {
309     PushResource( srcBuffer );
310     PushResource( dstImage );
311
312     mCommandBuffer.copyBufferToImage( srcBuffer->GetVkBuffer(), dstImage->GetVkImage(), dstLayout, regions );
313   }
314
315   vk::ImageMemoryBarrier ImageLayoutTransitionBarrier( ImageRef image,
316                                                       const vk::AccessFlags&        srcAccessMask,
317                                                       const vk::AccessFlags&        dstAccessMask,
318                                                       vk::ImageLayout        oldLayout,
319                                                       vk::ImageLayout        newLayout,
320                                                       const vk::ImageAspectFlags&   aspectMask
321   ) const
322   {
323     return vk::ImageMemoryBarrier{}
324          .setNewLayout( newLayout )
325          .setImage( image->GetVkImage() )
326          .setOldLayout( oldLayout )
327          .setSrcAccessMask( srcAccessMask )
328          .setDstAccessMask( dstAccessMask )
329          .setSubresourceRange( vk::ImageSubresourceRange{ aspectMask, 0, image->GetLevelCount(), 0, image->GetLayerCount() } );
330   }
331
332   CommandBuffer&                mOwner;
333   Graphics&                     mGraphics;
334   CommandPool&                  mOwnerCommandPool;
335   uint32_t                      mPoolAllocationIndex;
336   vk::CommandBufferAllocateInfo mAllocateInfo{};
337
338   vk::CommandBuffer mCommandBuffer{};
339
340   // semaphores per command buffer
341   std::vector<vk::Semaphore>          mSignalSemaphores{};
342   std::vector<vk::Semaphore>          mWaitSemaphores{};
343   std::vector<vk::PipelineStageFlags> mWaitStages{};
344
345   std::vector<Handle<VkManaged>> mResources; // used resources
346
347   PipelineRef mCurrentPipeline;
348
349   vk::RenderPass mCurrentRenderPass;
350
351   FenceRef       mFinishedFence;
352
353   bool mRecording{false};
354 };
355
356 /**
357  *
358  * Class: CommandBuffer
359  *
360  */
361
362 CommandBuffer::CommandBuffer( CommandPool&                         commandPool,
363                               uint32_t                             poolIndex,
364                               const vk::CommandBufferAllocateInfo& allocateInfo,
365                               vk::CommandBuffer                    vkCommandBuffer )
366 {
367   mImpl = MakeUnique<Impl>( *this, commandPool, poolIndex, allocateInfo, vkCommandBuffer );
368 }
369
370 CommandBuffer::~CommandBuffer()
371 {
372 }
373
374 /** Begin recording */
375 void CommandBuffer::Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
376 {
377   mImpl->Begin( usageFlags, inheritanceInfo );
378 }
379
380 /** Finish recording */
381 void CommandBuffer::End()
382 {
383   mImpl->End();
384 }
385
386 /** Reset command buffer */
387 void CommandBuffer::Reset()
388 {
389   mImpl->Reset();
390 }
391
392 /** Free command buffer */
393 void CommandBuffer::Free()
394 {
395   mImpl->Free();
396 }
397
398 /** Push wait semaphores */
399 void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>&          semaphores,
400                                         const std::vector<vk::PipelineStageFlags>& stages )
401 {
402   mImpl->PushWaitSemaphores( semaphores, stages );
403 }
404
405 /** Push signal semaphores */
406 void CommandBuffer::PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
407 {
408   mImpl->PushSignalSemaphores( semaphores );
409 }
410
411 const std::vector<vk::Semaphore>& CommandBuffer::GetSignalSemaphores() const
412 {
413   return mImpl->mSignalSemaphores;
414 }
415
416 const std::vector<vk::Semaphore>& CommandBuffer::GetSWaitSemaphores() const
417 {
418   return mImpl->mWaitSemaphores;
419 }
420
421 const std::vector<vk::PipelineStageFlags>& CommandBuffer::GetWaitSemaphoreStages() const
422 {
423   return mImpl->mWaitStages;
424 }
425
426 vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
427 {
428   return mImpl->mCommandBuffer;
429 }
430
431 bool CommandBuffer::IsPrimary() const
432 {
433   return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
434 }
435
436 void CommandBuffer::BindVertexBuffers( uint32_t                    firstBinding,
437                                        uint32_t                    bindingCount,
438                                        std::vector<Handle<Buffer>> buffers,
439                                        const vk::DeviceSize*       pOffsets )
440 {
441   mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
442 }
443
444 void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
445 {
446   mImpl->BindIndexBuffer( buffer, offset, indexType );
447 }
448
449 void CommandBuffer::BindVertexBuffer( uint32_t                               binding,
450                                       Dali::Graphics::Vulkan::Handle<Buffer> buffer,
451                                       vk::DeviceSize                         offset )
452 {
453   mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>( {buffer} ), &offset );
454 }
455
456 void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
457 {
458   mImpl->BindGraphicsPipeline( pipeline );
459 }
460
461 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
462                                         Handle<Pipeline>                                           pipeline,
463                                         uint32_t                                                   firstSet,
464                                         uint32_t                                                   descriptorSetCount )
465 {
466   mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
467 }
468
469 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
470                                         uint32_t                                                   firstSet )
471 {
472   mImpl->BindDescriptorSets(
473     descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>( descriptorSets.size() ) );
474 }
475
476 void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
477 {
478   mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
479 }
480
481 void CommandBuffer::DrawIndexed(
482   uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
483 {
484   mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
485 }
486
487 void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
488 {
489   mImpl->BeginRenderPass( framebufferId, bufferIndex );
490 }
491
492 void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
493 {
494   mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
495 }
496
497 void CommandBuffer::EndRenderPass()
498 {
499   mImpl->EndRenderPass();
500 }
501
502 void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
503 {
504   mImpl->ExecuteCommands( commandBuffers );
505 }
506
507 void CommandBuffer::PipelineBarrier( vk::PipelineStageFlags srcStageMask,
508                       vk::PipelineStageFlags dstStageMask,
509                       vk::DependencyFlags dependencyFlags,
510                       std::vector<vk::MemoryBarrier> memoryBarriers,
511                       std::vector<vk::BufferMemoryBarrier> bufferBarriers,
512                       std::vector<vk::ImageMemoryBarrier> imageBarriers )
513 {
514   mImpl->PipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
515 }
516
517 void CommandBuffer::CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage,
518                                        vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
519 {
520   mImpl->CopyBufferToImage( srcBuffer, dstImage, dstLayout, regions );
521 }
522
523 vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
524                                                      vk::AccessFlags        srcAccessMask,
525                                                      vk::AccessFlags        dstAccessMask,
526                                                      vk::ImageLayout        oldLayout,
527                                                      vk::ImageLayout        newLayout,
528                                                      vk::ImageAspectFlags   aspectMask
529 ) const
530 {
531   return mImpl->ImageLayoutTransitionBarrier( image,
532                                               srcAccessMask, dstAccessMask,
533                                               oldLayout, newLayout,
534                                               aspectMask  );
535 }
536
537 vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
538                                                      vk::ImageLayout        newLayout,
539                                                      vk::ImageAspectFlags   aspectMask
540 ) const
541 {
542
543   vk::AccessFlags  srcAccessMask, dstAccessMask;
544   vk::PipelineStageFlags srcStageMask, dstStageMask;
545
546   auto oldLayout = image->GetVkImageLayout();
547
548   switch( oldLayout )
549   {
550     case vk::ImageLayout::ePreinitialized:
551     case vk::ImageLayout::eUndefined:
552     {
553       srcAccessMask = {};
554       srcStageMask  = vk::PipelineStageFlagBits::eTopOfPipe;
555       break;
556     }
557     case vk::ImageLayout::ePresentSrcKHR:
558     {
559       srcAccessMask = vk::AccessFlagBits::eColorAttachmentRead;
560       srcStageMask  = vk::PipelineStageFlagBits::eColorAttachmentOutput;
561       break;
562     }
563     case vk::ImageLayout::eTransferSrcOptimal:
564     {
565       srcAccessMask = vk::AccessFlagBits::eMemoryRead;
566       srcStageMask  = vk::PipelineStageFlagBits::eTransfer;
567       break;
568     }
569     case vk::ImageLayout::eTransferDstOptimal:
570     {
571       srcAccessMask = vk::AccessFlagBits::eMemoryWrite;
572       srcStageMask  = vk::PipelineStageFlagBits::eTransfer;
573       break;
574     }
575     case vk::ImageLayout::eGeneral:
576     case vk::ImageLayout::eColorAttachmentOptimal:
577     case vk::ImageLayout::eDepthStencilAttachmentOptimal:
578     case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
579     case vk::ImageLayout::eShaderReadOnlyOptimal:
580     case vk::ImageLayout::eSharedPresentKHR:
581     {
582       break;
583     }
584   }
585
586   switch( newLayout )
587   {
588     case vk::ImageLayout::ePresentSrcKHR:
589     {
590       dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
591       dstStageMask  = vk::PipelineStageFlagBits::eBottomOfPipe;
592       break;
593     }
594     case vk::ImageLayout::eTransferSrcOptimal:
595     {
596       dstAccessMask = vk::AccessFlagBits::eMemoryRead;
597       dstStageMask  = vk::PipelineStageFlagBits::eTransfer;
598       break;
599     }
600     case vk::ImageLayout::eTransferDstOptimal:
601     {
602       dstAccessMask = vk::AccessFlagBits::eMemoryWrite;
603       dstStageMask  = vk::PipelineStageFlagBits::eTransfer;
604       break;
605     }
606     case vk::ImageLayout::eShaderReadOnlyOptimal:
607     {
608       dstAccessMask = vk::AccessFlagBits::eMemoryRead;
609       dstStageMask = vk::PipelineStageFlagBits::eVertexShader;
610       break;
611     }
612     case vk::ImageLayout::eUndefined:
613     case vk::ImageLayout::eGeneral:
614     case vk::ImageLayout::eColorAttachmentOptimal:
615     case vk::ImageLayout::eDepthStencilAttachmentOptimal:
616     case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
617     case vk::ImageLayout::ePreinitialized:
618     case vk::ImageLayout::eSharedPresentKHR:
619     {
620       break;
621     }
622   }
623
624   return mImpl->ImageLayoutTransitionBarrier( image,
625                                               srcAccessMask, dstAccessMask,
626                                               oldLayout, newLayout,
627                                               aspectMask  );
628 }
629
630 uint32_t CommandBuffer::GetPoolAllocationIndex() const
631 {
632   return mImpl->mPoolAllocationIndex;
633 }
634
635 bool CommandBuffer::OnDestroy()
636 {
637   mImpl->ReleaseCommandBuffer();
638   return true;
639 }
640
641 } // namespace Vulkan
642 } // namespace Graphics
643 } // namespace Dali