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