Merge "Change default vulkan SDK to a fixed version" into devel/vulkan
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / vulkan-command-buffer.cpp
1 /*
2  * Copyright (c) 2017 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-buffer.h>
20 #include <dali/graphics/vulkan/vulkan-command-buffer.h>
21 #include <dali/graphics/vulkan/vulkan-command-pool.h>
22 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
23 #include <dali/graphics/vulkan/vulkan-graphics.h>
24 #include <dali/graphics/vulkan/vulkan-image.h>
25 #include <dali/graphics/vulkan/vulkan-pipeline.h>
26 #include <dali/graphics/vulkan/vulkan-surface.h>
27 #include <dali/graphics/vulkan/vulkan-types.h>
28
29 namespace Dali
30 {
31 namespace Graphics
32 {
33 namespace Vulkan
34 {
35 struct CommandBuffer::Impl
36 {
37   Impl( CommandPool& commandPool, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer commandBuffer )
38   : mGraphics( commandPool.GetGraphics() ),
39     mOwnerCommandPool( commandPool ),
40     mAllocateInfo( allocateInfo ),
41     mCommandBuffer( commandBuffer )
42   {
43   }
44
45   ~Impl()
46   {
47   }
48
49   bool Initialise()
50   {
51     return true;
52   }
53
54   template<class T>
55   bool IsResourceAdded( Handle<T> resourceHandle )
56   {
57     for( auto&& res : mResources )
58     {
59       if( res == resourceHandle )
60       {
61         return true;
62       }
63     }
64     return false;
65   }
66
67   template<class T>
68   bool PushResource( Handle<T> resourceHandle )
69   {
70     if( !IsResourceAdded( resourceHandle ) )
71     {
72       mResources.push_back( VkTypeCast<VkManaged>( resourceHandle ) );
73       return true;
74     }
75     return false;
76   }
77
78   /**
79    *
80    */
81   void Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
82   {
83     assert( !mRecording && "CommandBuffer already is in the recording state" );
84     auto info = vk::CommandBufferBeginInfo{};
85     info.setPInheritanceInfo( inheritanceInfo );
86     info.setFlags( usageFlags );
87
88     // set the inheritance option
89     auto inheritance = vk::CommandBufferInheritanceInfo{}.setSubpass( 0 );
90
91     if( mAllocateInfo.level == vk::CommandBufferLevel::eSecondary )
92     {
93       // todo: sets render pass from 'default' surface, should be supplied from primary command buffer
94       // which has render pass associated within execution context
95       inheritance.setRenderPass( mGraphics.GetSurface( 0 ).GetRenderPass() );
96       info.setPInheritanceInfo( &inheritance );
97     }
98
99     VkAssert( mCommandBuffer.begin( info ) );
100
101     mResources.clear();
102
103     mRecording = true;
104   }
105
106   void End()
107   {
108     assert( mRecording && "CommandBuffer is not in the recording state!" );
109     VkAssert( mCommandBuffer.end() );
110     mRecording = false;
111   }
112
113   void Reset()
114   {
115     assert( !mRecording && "Can't reset command buffer during recording!" );
116     assert( mCommandBuffer && "Invalid command buffer!" );
117     mCommandBuffer.reset( vk::CommandBufferResetFlagBits::eReleaseResources );
118
119     mResources.clear();
120   }
121
122   void Free()
123   {
124     assert( mCommandBuffer && "Invalid command buffer!" );
125     mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(), mCommandBuffer );
126   }
127
128   void ImageLayoutTransition( vk::Image            image,
129                               vk::ImageLayout      oldLayout,
130                               vk::ImageLayout      newLayout,
131                               vk::ImageAspectFlags aspectMask )
132   {
133     // just push new image barrier until any command is being called or buffer recording ends.
134     // it will make sure we batch barriers together rather than calling cmdPipelineBarrier
135     // for each separately
136     vk::AccessFlags        srcAccessMask, dstAccessMask;
137     vk::PipelineStageFlags srcStageMask, dstStageMask;
138
139     // TODO: add other transitions
140     switch( oldLayout )
141     {
142       case vk::ImageLayout::eUndefined:
143       {
144         srcStageMask = vk::PipelineStageFlagBits::eTopOfPipe;
145       }
146       break;
147       case vk::ImageLayout::ePresentSrcKHR:
148       {
149         srcStageMask  = vk::PipelineStageFlagBits::eBottomOfPipe;
150         srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
151       }
152       break;
153       case vk::ImageLayout::eColorAttachmentOptimal:
154       {
155         srcStageMask  = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eColorAttachmentOutput;
156         srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
157       }
158       break;
159       case vk::ImageLayout::eGeneral:
160       case vk::ImageLayout::eDepthStencilAttachmentOptimal:
161       case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
162       case vk::ImageLayout::eShaderReadOnlyOptimal:
163       case vk::ImageLayout::eTransferSrcOptimal:
164       case vk::ImageLayout::eTransferDstOptimal:
165       case vk::ImageLayout::ePreinitialized:
166       case vk::ImageLayout::eSharedPresentKHR:
167       {
168       }
169     }
170
171     switch( newLayout )
172     {
173       case vk::ImageLayout::eColorAttachmentOptimal:
174       {
175         dstStageMask  = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eFragmentShader;
176         dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eHostWrite;
177         break;
178       }
179       case vk::ImageLayout::eDepthStencilAttachmentOptimal:
180       {
181         dstStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eEarlyFragmentTests;
182         dstAccessMask =
183           vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
184         break;
185       }
186       case vk::ImageLayout::ePresentSrcKHR:
187       {
188         dstStageMask  = vk::PipelineStageFlagBits::eBottomOfPipe;
189         dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eMemoryRead;
190       }
191       case vk::ImageLayout::eGeneral:
192       case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
193       case vk::ImageLayout::eShaderReadOnlyOptimal:
194       case vk::ImageLayout::eTransferSrcOptimal:
195       case vk::ImageLayout::eTransferDstOptimal:
196       case vk::ImageLayout::ePreinitialized:
197       case vk::ImageLayout::eUndefined:
198       case vk::ImageLayout::eSharedPresentKHR:
199       {
200         break;
201       }
202     }
203
204     RecordImageLayoutTransition(
205       image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, oldLayout, newLayout, aspectMask );
206   }
207
208 #pragma GCC diagnostic push
209 #pragma GCC diagnostic ignored "-Wframe-larger-than="
210   void RecordImageLayoutTransition( vk::Image              image,
211                                     vk::AccessFlags        srcAccessMask,
212                                     vk::AccessFlags        dstAccessMask,
213                                     vk::PipelineStageFlags srcStageMask,
214                                     vk::PipelineStageFlags dstStageMask,
215                                     vk::ImageLayout        oldLayout,
216                                     vk::ImageLayout        newLayout,
217                                     vk::ImageAspectFlags   aspectMask )
218   {
219     vk::ImageSubresourceRange subres;
220     subres.setLayerCount( 1 ).setBaseMipLevel( 0 ).setBaseArrayLayer( 0 ).setLevelCount( 1 ).setAspectMask(
221       aspectMask );
222
223     auto barrier = vk::ImageMemoryBarrier{};
224     barrier.setImage( image )
225       .setSubresourceRange( subres )
226       .setSrcAccessMask( srcAccessMask )
227       .setDstAccessMask( dstAccessMask )
228       .setOldLayout( oldLayout )
229       .setNewLayout( newLayout );
230     ;
231     // todo: implement barriers batching
232     mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, vk::DependencyFlags{}, nullptr, nullptr, barrier );
233   }
234 #pragma GCC diagnostic pop
235
236   /** Push wait semaphores */
237   void PushWaitSemaphores( const std::vector<vk::Semaphore>&          semaphores,
238                            const std::vector<vk::PipelineStageFlags>& stages )
239   {
240     mWaitSemaphores = semaphores;
241     mWaitStages     = stages;
242   }
243
244   /** Push signal semaphores */
245   void PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
246   {
247     mSignalSemaphores = semaphores;
248   }
249
250   // TODO: handles should be synchronized
251   void BindVertexBuffers( uint32_t                    firstBinding,
252                           uint32_t                    bindingCount,
253                           std::vector<Handle<Buffer>> buffers,
254                           const vk::DeviceSize*       pOffsets )
255   {
256     // update list of used resources and create an array of VkBuffers
257     std::vector<vk::Buffer> vkBuffers;
258     vkBuffers.reserve( buffers.size() );
259     for( auto&& buffer : buffers )
260     {
261       vkBuffers.emplace_back( buffer->GetVkBuffer() );
262       PushResource( buffer );
263     }
264
265     mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets );
266   }
267
268   void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
269   {
270     // validate
271     assert( ( buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer ) &&
272             "The buffer used as index buffer has wrong usage flags!" );
273
274     PushResource( buffer );
275     mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
276   }
277
278   void BindGraphicsPipeline( Handle<Pipeline> pipeline )
279   {
280     PushResource( pipeline );
281     mCurrentPipeline = pipeline;
282     mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
283   }
284
285   void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
286                            Handle<Pipeline>                                           pipeline,
287                            uint32_t                                                   firstSet,
288                            uint32_t                                                   descriptorSetCount )
289   {
290     // update resources
291     PushResource( pipeline );
292     std::vector<vk::DescriptorSet> vkSets;
293     vkSets.reserve( descriptorSets.size() );
294     for( auto&& set : descriptorSets )
295     {
296       vkSets.emplace_back( set->GetVkDescriptorSet() );
297       PushResource( set );
298     }
299
300     // TODO: support dynamic offsets
301     mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics,
302                                        pipeline->GetVkPipelineLayout(),
303                                        firstSet,
304                                        descriptorSetCount,
305                                        vkSets.data(),
306                                        0,
307                                        nullptr );
308   }
309
310   void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
311   {
312     mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
313   }
314
315   void DrawIndexed(
316     uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
317   {
318     mCommandBuffer.drawIndexed(
319       indexCount, instanceCount, firstIndex, static_cast<int32_t>( vertexOffset ), firstInstance );
320   }
321
322   const std::vector<Handle<VkManaged>> GetResources() const
323   {
324     return mResources;
325   }
326
327   // RENDER PASS
328   void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
329   {
330     auto& surface     = mGraphics.GetSurface( framebufferId );
331     auto  renderPass  = surface.GetRenderPass();
332     auto  frameBuffer = surface.GetFramebuffer( bufferIndex );
333     auto  clearValues = surface.GetClearValues();
334
335     auto info = vk::RenderPassBeginInfo{};
336     info.setFramebuffer( frameBuffer );
337     info.setRenderPass( renderPass );
338     info.setClearValueCount( U32( clearValues.size() ) );
339     info.setPClearValues( clearValues.data() );
340     info.setRenderArea( vk::Rect2D( {0, 0}, surface.GetSize() ) );
341
342     mCurrentRenderPass = renderPass;
343     mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
344   }
345
346   void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
347   {
348     mCurrentRenderPass = renderPassBeginInfo.renderPass;
349     mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
350   }
351
352   void EndRenderPass()
353   {
354     mCurrentRenderPass = nullptr;
355     mCommandBuffer.endRenderPass();
356   }
357
358   void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
359   {
360     auto vkBuffers = std::vector<vk::CommandBuffer>{};
361     vkBuffers.reserve( commandBuffers.size() );
362     for( auto&& buf : commandBuffers )
363     {
364       vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
365       PushResource( buf );
366     }
367
368     mCommandBuffer.executeCommands( vkBuffers );
369   }
370
371   Graphics&                     mGraphics;
372   CommandPool&                  mOwnerCommandPool;
373   vk::CommandBufferAllocateInfo mAllocateInfo{};
374
375   vk::CommandBuffer mCommandBuffer{};
376
377   // semaphores per command buffer
378   std::vector<vk::Semaphore>          mSignalSemaphores{};
379   std::vector<vk::Semaphore>          mWaitSemaphores{};
380   std::vector<vk::PipelineStageFlags> mWaitStages{};
381
382   std::vector<Handle<VkManaged>> mResources; // used resources
383
384   PipelineRef mCurrentPipeline;
385
386   vk::RenderPass mCurrentRenderPass;
387
388   bool mRecording{false};
389 };
390
391 /**
392  *
393  * Class: CommandBuffer
394  *
395  */
396
397 CommandBuffer::CommandBuffer( CommandPool&                         commandPool,
398                               const vk::CommandBufferAllocateInfo& allocateInfo,
399                               vk::CommandBuffer                    vkCommandBuffer )
400 {
401   mImpl = MakeUnique<Impl>( commandPool, allocateInfo, vkCommandBuffer );
402 }
403
404 CommandBuffer::~CommandBuffer()
405 {
406 }
407
408 /** Begin recording */
409 void CommandBuffer::Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
410 {
411   mImpl->Begin( usageFlags, inheritanceInfo );
412 }
413
414 /** Finish recording */
415 void CommandBuffer::End()
416 {
417   mImpl->End();
418 }
419
420 /** Reset command buffer */
421 void CommandBuffer::Reset()
422 {
423   mImpl->Reset();
424 }
425
426 /** Free command buffer */
427 void CommandBuffer::Free()
428 {
429   mImpl->Free();
430 }
431
432 /** Records image layout transition barrier for one image */
433 void CommandBuffer::ImageLayoutTransition( vk::Image            image,
434                                            vk::ImageLayout      oldLayout,
435                                            vk::ImageLayout      newLayout,
436                                            vk::ImageAspectFlags aspectMask )
437 {
438   mImpl->ImageLayoutTransition( image, oldLayout, newLayout, aspectMask );
439 }
440
441 void CommandBuffer::RecordImageLayoutTransition( vk::Image              image,
442                                                  vk::AccessFlags        srcAccessMask,
443                                                  vk::AccessFlags        dstAccessMask,
444                                                  vk::PipelineStageFlags srcStageMask,
445                                                  vk::PipelineStageFlags dstStageMask,
446                                                  vk::ImageLayout        oldLayout,
447                                                  vk::ImageLayout        newLayout,
448                                                  vk::ImageAspectFlags   aspectMask )
449 {
450   mImpl->RecordImageLayoutTransition(
451     image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, oldLayout, newLayout, aspectMask );
452 }
453
454 /** Push wait semaphores */
455 void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>&          semaphores,
456                                         const std::vector<vk::PipelineStageFlags>& stages )
457 {
458   mImpl->PushWaitSemaphores( semaphores, stages );
459 }
460
461 /** Push signal semaphores */
462 void CommandBuffer::PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
463 {
464   mImpl->PushSignalSemaphores( semaphores );
465 }
466
467 const std::vector<vk::Semaphore>& CommandBuffer::GetSignalSemaphores() const
468 {
469   return mImpl->mSignalSemaphores;
470 }
471
472 const std::vector<vk::Semaphore>& CommandBuffer::GetSWaitSemaphores() const
473 {
474   return mImpl->mWaitSemaphores;
475 }
476
477 const std::vector<vk::PipelineStageFlags>& CommandBuffer::GetWaitSemaphoreStages() const
478 {
479   return mImpl->mWaitStages;
480 }
481
482 vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
483 {
484   return mImpl->mCommandBuffer;
485 }
486
487 bool CommandBuffer::IsPrimary() const
488 {
489   return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
490 }
491
492 void CommandBuffer::BindVertexBuffers( uint32_t                    firstBinding,
493                                        uint32_t                    bindingCount,
494                                        std::vector<Handle<Buffer>> buffers,
495                                        const vk::DeviceSize*       pOffsets )
496 {
497   mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
498 }
499
500 void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
501 {
502   mImpl->BindIndexBuffer( buffer, offset, indexType );
503 }
504
505 void CommandBuffer::BindVertexBuffer( uint32_t                               binding,
506                                       Dali::Graphics::Vulkan::Handle<Buffer> buffer,
507                                       vk::DeviceSize                         offset )
508 {
509   mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>( {buffer} ), &offset );
510 }
511
512 void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
513 {
514   mImpl->BindGraphicsPipeline( pipeline );
515 }
516
517 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
518                                         Handle<Pipeline>                                           pipeline,
519                                         uint32_t                                                   firstSet,
520                                         uint32_t                                                   descriptorSetCount )
521 {
522   mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
523 }
524
525 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
526                                         uint32_t                                                   firstSet )
527 {
528   mImpl->BindDescriptorSets(
529     descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>( descriptorSets.size() ) );
530 }
531
532 void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
533 {
534   mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
535 }
536
537 void CommandBuffer::DrawIndexed(
538   uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
539 {
540   mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
541 }
542
543 void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
544 {
545   mImpl->BeginRenderPass( framebufferId, bufferIndex );
546 }
547
548 void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
549 {
550   mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
551 }
552
553 void CommandBuffer::EndRenderPass()
554 {
555   mImpl->EndRenderPass();
556 }
557
558 void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
559 {
560   mImpl->ExecuteCommands( commandBuffers );
561 }
562
563 } // namespace Vulkan
564 } // namespace Graphics
565 } // namespace Dali