[Vulkan] graphics controller, multiple pipelines
[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
144   /** Push wait semaphores */
145   void PushWaitSemaphores( const std::vector<vk::Semaphore>&          semaphores,
146                            const std::vector<vk::PipelineStageFlags>& stages )
147   {
148     mWaitSemaphores = semaphores;
149     mWaitStages     = stages;
150   }
151
152   /** Push signal semaphores */
153   void PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
154   {
155     mSignalSemaphores = semaphores;
156   }
157
158   // TODO: handles should be synchronized
159   void BindVertexBuffers( uint32_t                    firstBinding,
160                           uint32_t                    bindingCount,
161                           std::vector<Handle<Buffer>> buffers,
162                           const vk::DeviceSize*       pOffsets )
163   {
164     // update list of used resources and create an array of VkBuffers
165     std::vector<vk::Buffer> vkBuffers;
166     vkBuffers.reserve( buffers.size() );
167     for( auto&& buffer : buffers )
168     {
169       vkBuffers.emplace_back( buffer->GetVkBuffer() );
170       PushResource( buffer );
171     }
172
173     mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets );
174   }
175
176   void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
177   {
178     // validate
179     assert( ( buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer ) &&
180             "The buffer used as index buffer has wrong usage flags!" );
181
182     PushResource( buffer );
183     mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
184   }
185
186   void BindGraphicsPipeline( Handle<Pipeline> pipeline )
187   {
188     PushResource( pipeline );
189     mCurrentPipeline = pipeline;
190     mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
191   }
192
193   void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
194                            Handle<Pipeline>                                           pipeline,
195                            uint32_t                                                   firstSet,
196                            uint32_t                                                   descriptorSetCount )
197   {
198     // update resources
199     PushResource( pipeline );
200     std::vector<vk::DescriptorSet> vkSets;
201     vkSets.reserve( descriptorSets.size() );
202     for( auto&& set : descriptorSets )
203     {
204       vkSets.emplace_back( set->GetVkDescriptorSet() );
205       PushResource( set );
206     }
207
208     // TODO: support dynamic offsets
209     mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics,
210                                        pipeline->GetVkPipelineLayout(),
211                                        firstSet,
212                                        descriptorSetCount,
213                                        vkSets.data(),
214                                        0,
215                                        nullptr );
216   }
217
218   void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
219   {
220     mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
221   }
222
223   void DrawIndexed(
224     uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
225   {
226     mCommandBuffer.drawIndexed(
227       indexCount, instanceCount, firstIndex, static_cast<int32_t>( vertexOffset ), firstInstance );
228   }
229
230   const std::vector<Handle<VkManaged>> GetResources() const
231   {
232     return mResources;
233   }
234
235   // RENDER PASS
236   void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
237   {
238     auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
239     auto surface = mGraphics.GetSurface( 0u );
240     auto frameBuffer = swapchain->GetCurrentFramebuffer();
241     auto renderPass = frameBuffer->GetVkRenderPass();
242     auto clearValues = frameBuffer->GetDefaultClearValues();
243
244     auto info = vk::RenderPassBeginInfo{};
245     info.setFramebuffer( frameBuffer->GetVkFramebuffer() );
246     info.setRenderPass( renderPass );
247     info.setClearValueCount( U32( clearValues.size() ) );
248     info.setPClearValues( clearValues.data() );
249     info.setRenderArea( vk::Rect2D( {0, 0}, surface->GetSize() ) );
250
251     mCurrentRenderPass = renderPass;
252     mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
253   }
254
255   void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
256   {
257     mCurrentRenderPass = renderPassBeginInfo.renderPass;
258     mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
259   }
260
261   void EndRenderPass()
262   {
263     mCurrentRenderPass = nullptr;
264     mCommandBuffer.endRenderPass();
265   }
266
267   void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
268   {
269     auto vkBuffers = std::vector<vk::CommandBuffer>{};
270     vkBuffers.reserve( commandBuffers.size() );
271     for( auto&& buf : commandBuffers )
272     {
273       vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
274       PushResource( buf );
275     }
276
277     mCommandBuffer.executeCommands( vkBuffers );
278   }
279
280   void PipelineBarrier( vk::PipelineStageFlags srcStageMask,
281                         vk::PipelineStageFlags dstStageMask,
282                         vk::DependencyFlags dependencyFlags,
283                         std::vector<vk::MemoryBarrier> memoryBarriers,
284                         std::vector<vk::BufferMemoryBarrier> bufferBarriers,
285                         std::vector<vk::ImageMemoryBarrier> imageBarriers )
286   {
287     /*
288      * Track resources
289      */
290     if( !imageBarriers.empty() )
291     {
292       for( auto&& imageBarrier : imageBarriers )
293       {
294         ImageRef imageResource{};
295         if( (imageResource = mGraphics.FindImage( imageBarrier.image )) )
296         {
297           PushResource( imageResource );
298         }
299       }
300     }
301     //@ todo other resource tracking
302
303     mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
304   }
305
306   void CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage, vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
307   {
308     PushResource( srcBuffer );
309     PushResource( dstImage );
310
311     mCommandBuffer.copyBufferToImage( srcBuffer->GetVkBuffer(), dstImage->GetVkImage(), dstLayout, regions );
312   }
313
314   vk::ImageMemoryBarrier ImageLayoutTransitionBarrier( ImageRef image,
315                                                       const vk::AccessFlags&        srcAccessMask,
316                                                       const vk::AccessFlags&        dstAccessMask,
317                                                       vk::ImageLayout        oldLayout,
318                                                       vk::ImageLayout        newLayout,
319                                                       const vk::ImageAspectFlags&   aspectMask
320   ) const
321   {
322     return vk::ImageMemoryBarrier{}
323          .setNewLayout( newLayout )
324          .setImage( image->GetVkImage() )
325          .setOldLayout( oldLayout )
326          .setSrcAccessMask( srcAccessMask )
327          .setDstAccessMask( dstAccessMask )
328          .setSubresourceRange( vk::ImageSubresourceRange{ aspectMask, 0, image->GetLevelCount(), 0, image->GetLayerCount() } );
329   }
330
331   CommandBuffer&                mOwner;
332   Graphics&                     mGraphics;
333   CommandPool&                  mOwnerCommandPool;
334   uint32_t                      mPoolAllocationIndex;
335   vk::CommandBufferAllocateInfo mAllocateInfo{};
336
337   vk::CommandBuffer mCommandBuffer{};
338
339   // semaphores per command buffer
340   std::vector<vk::Semaphore>          mSignalSemaphores{};
341   std::vector<vk::Semaphore>          mWaitSemaphores{};
342   std::vector<vk::PipelineStageFlags> mWaitStages{};
343
344   std::vector<Handle<VkManaged>> mResources; // used resources
345
346   PipelineRef mCurrentPipeline;
347
348   vk::RenderPass mCurrentRenderPass;
349
350   FenceRef       mFinishedFence;
351
352   bool mRecording{false};
353 };
354
355 /**
356  *
357  * Class: CommandBuffer
358  *
359  */
360
361 CommandBuffer::CommandBuffer( CommandPool&                         commandPool,
362                               uint32_t                             poolIndex,
363                               const vk::CommandBufferAllocateInfo& allocateInfo,
364                               vk::CommandBuffer                    vkCommandBuffer )
365 {
366   mImpl = MakeUnique<Impl>( *this, commandPool, poolIndex, allocateInfo, vkCommandBuffer );
367 }
368
369 CommandBuffer::~CommandBuffer()
370 {
371 }
372
373 /** Begin recording */
374 void CommandBuffer::Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
375 {
376   mImpl->Begin( usageFlags, inheritanceInfo );
377 }
378
379 /** Finish recording */
380 void CommandBuffer::End()
381 {
382   mImpl->End();
383 }
384
385 /** Reset command buffer */
386 void CommandBuffer::Reset()
387 {
388   mImpl->Reset();
389 }
390
391 /** Free command buffer */
392 void CommandBuffer::Free()
393 {
394   mImpl->Free();
395 }
396
397 /** Push wait semaphores */
398 void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>&          semaphores,
399                                         const std::vector<vk::PipelineStageFlags>& stages )
400 {
401   mImpl->PushWaitSemaphores( semaphores, stages );
402 }
403
404 /** Push signal semaphores */
405 void CommandBuffer::PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
406 {
407   mImpl->PushSignalSemaphores( semaphores );
408 }
409
410 const std::vector<vk::Semaphore>& CommandBuffer::GetSignalSemaphores() const
411 {
412   return mImpl->mSignalSemaphores;
413 }
414
415 const std::vector<vk::Semaphore>& CommandBuffer::GetSWaitSemaphores() const
416 {
417   return mImpl->mWaitSemaphores;
418 }
419
420 const std::vector<vk::PipelineStageFlags>& CommandBuffer::GetWaitSemaphoreStages() const
421 {
422   return mImpl->mWaitStages;
423 }
424
425 vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
426 {
427   return mImpl->mCommandBuffer;
428 }
429
430 bool CommandBuffer::IsPrimary() const
431 {
432   return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
433 }
434
435 void CommandBuffer::BindVertexBuffers( uint32_t                    firstBinding,
436                                        uint32_t                    bindingCount,
437                                        std::vector<Handle<Buffer>> buffers,
438                                        const vk::DeviceSize*       pOffsets )
439 {
440   mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
441 }
442
443 void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
444 {
445   mImpl->BindIndexBuffer( buffer, offset, indexType );
446 }
447
448 void CommandBuffer::BindVertexBuffer( uint32_t                               binding,
449                                       const Dali::Graphics::Vulkan::Handle<Buffer>& buffer,
450                                       vk::DeviceSize                         offset )
451 {
452   mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>( {buffer} ), &offset );
453 }
454
455 void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
456 {
457   mImpl->BindGraphicsPipeline( pipeline );
458 }
459
460 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
461                                         Handle<Pipeline>                                           pipeline,
462                                         uint32_t                                                   firstSet,
463                                         uint32_t                                                   descriptorSetCount )
464 {
465   mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
466 }
467
468 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
469                                         uint32_t                                                   firstSet )
470 {
471   mImpl->BindDescriptorSets(
472     descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>( descriptorSets.size() ) );
473 }
474
475 void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
476 {
477   mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
478 }
479
480 void CommandBuffer::DrawIndexed(
481   uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
482 {
483   mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
484 }
485
486 void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
487 {
488   mImpl->BeginRenderPass( framebufferId, bufferIndex );
489 }
490
491 void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
492 {
493   mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
494 }
495
496 void CommandBuffer::EndRenderPass()
497 {
498   mImpl->EndRenderPass();
499 }
500
501 void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
502 {
503   mImpl->ExecuteCommands( commandBuffers );
504 }
505
506 void CommandBuffer::PipelineBarrier( vk::PipelineStageFlags srcStageMask,
507                       vk::PipelineStageFlags dstStageMask,
508                       vk::DependencyFlags dependencyFlags,
509                       std::vector<vk::MemoryBarrier> memoryBarriers,
510                       std::vector<vk::BufferMemoryBarrier> bufferBarriers,
511                       std::vector<vk::ImageMemoryBarrier> imageBarriers )
512 {
513   mImpl->PipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
514 }
515
516 void CommandBuffer::CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage,
517                                        vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
518 {
519   mImpl->CopyBufferToImage( srcBuffer, dstImage, dstLayout, regions );
520 }
521
522 vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
523                                                      vk::AccessFlags        srcAccessMask,
524                                                      vk::AccessFlags        dstAccessMask,
525                                                      vk::ImageLayout        oldLayout,
526                                                      vk::ImageLayout        newLayout,
527                                                      vk::ImageAspectFlags   aspectMask
528 ) const
529 {
530   return mImpl->ImageLayoutTransitionBarrier( image,
531                                               srcAccessMask, dstAccessMask,
532                                               oldLayout, newLayout,
533                                               aspectMask  );
534 }
535
536 vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
537                                                      vk::ImageLayout        oldLayout,
538                                                      vk::ImageLayout        newLayout,
539                                                      vk::ImageAspectFlags   aspectMask
540 ) const
541 {
542
543   vk::AccessFlags  srcAccessMask, dstAccessMask;
544   vk::PipelineStageFlags srcStageMask, dstStageMask;
545
546   switch( oldLayout )
547   {
548     case vk::ImageLayout::ePreinitialized:
549     case vk::ImageLayout::eUndefined:
550     {
551       srcAccessMask = {};
552       srcStageMask  = vk::PipelineStageFlagBits::eTopOfPipe;
553       break;
554     }
555     case vk::ImageLayout::ePresentSrcKHR:
556     {
557       srcAccessMask = vk::AccessFlagBits::eColorAttachmentRead;
558       srcStageMask  = vk::PipelineStageFlagBits::eColorAttachmentOutput;
559       break;
560     }
561     case vk::ImageLayout::eTransferSrcOptimal:
562     {
563       srcAccessMask = vk::AccessFlagBits::eMemoryRead;
564       srcStageMask  = vk::PipelineStageFlagBits::eTransfer;
565       break;
566     }
567     case vk::ImageLayout::eTransferDstOptimal:
568     {
569       srcAccessMask = vk::AccessFlagBits::eMemoryWrite;
570       srcStageMask  = vk::PipelineStageFlagBits::eTransfer;
571       break;
572     }
573     case vk::ImageLayout::eGeneral:
574     case vk::ImageLayout::eColorAttachmentOptimal:
575     case vk::ImageLayout::eDepthStencilAttachmentOptimal:
576     case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
577     case vk::ImageLayout::eShaderReadOnlyOptimal:
578     case vk::ImageLayout::eSharedPresentKHR:
579     {
580       break;
581     }
582   }
583
584   switch( newLayout )
585   {
586     case vk::ImageLayout::ePresentSrcKHR:
587     {
588       dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
589       dstStageMask  = vk::PipelineStageFlagBits::eBottomOfPipe;
590       break;
591     }
592     case vk::ImageLayout::eTransferSrcOptimal:
593     {
594       dstAccessMask = vk::AccessFlagBits::eMemoryRead;
595       dstStageMask  = vk::PipelineStageFlagBits::eTransfer;
596       break;
597     }
598     case vk::ImageLayout::eTransferDstOptimal:
599     {
600       dstAccessMask = vk::AccessFlagBits::eMemoryWrite;
601       dstStageMask  = vk::PipelineStageFlagBits::eTransfer;
602       break;
603     }
604     case vk::ImageLayout::eShaderReadOnlyOptimal:
605     {
606       dstAccessMask = vk::AccessFlagBits::eMemoryRead;
607       dstStageMask = vk::PipelineStageFlagBits::eVertexShader;
608       break;
609     }
610     case vk::ImageLayout::eUndefined:
611     case vk::ImageLayout::eGeneral:
612     case vk::ImageLayout::eColorAttachmentOptimal:
613     case vk::ImageLayout::eDepthStencilAttachmentOptimal:
614     case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
615     case vk::ImageLayout::ePreinitialized:
616     case vk::ImageLayout::eSharedPresentKHR:
617     {
618       break;
619     }
620   }
621
622   return mImpl->ImageLayoutTransitionBarrier( image,
623                                               srcAccessMask, dstAccessMask,
624                                               oldLayout, newLayout,
625                                               aspectMask  );
626 }
627
628 uint32_t CommandBuffer::GetPoolAllocationIndex() const
629 {
630   return mImpl->mPoolAllocationIndex;
631 }
632
633 bool CommandBuffer::OnDestroy()
634 {
635   mImpl->ReleaseCommandBuffer();
636   return true;
637 }
638
639 } // namespace Vulkan
640 } // namespace Graphics
641 } // namespace Dali