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