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