2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
37 struct CommandBuffer::Impl
39 Impl( CommandBuffer& owner, CommandPool& commandPool, uint32_t poolIndex, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer commandBuffer )
41 mGraphics( commandPool.GetGraphics() ),
42 mOwnerCommandPool( commandPool ),
43 mPoolAllocationIndex( poolIndex ),
44 mAllocateInfo( allocateInfo ),
45 mCommandBuffer( commandBuffer )
51 mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(),
55 void ReleaseCommandBuffer()
59 // tell pool the buffer is not in use anymore
60 mOwnerCommandPool.ReleaseCommandBuffer(mOwner, false);
69 bool IsResourceAdded( Handle<T> resourceHandle )
71 for( auto&& res : mResources )
73 if( res == resourceHandle )
82 bool PushResource( Handle<T> resourceHandle )
84 if( !IsResourceAdded( resourceHandle ) )
86 mResources.push_back( VkTypeCast<VkManaged>( resourceHandle ) );
95 void Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
97 assert( !mRecording && "CommandBuffer already is in the recording state" );
98 auto info = vk::CommandBufferBeginInfo{};
99 info.setPInheritanceInfo( inheritanceInfo );
100 info.setFlags( usageFlags );
102 // set the inheritance option
103 auto inheritance = vk::CommandBufferInheritanceInfo{}.setSubpass( 0 );
105 if( mAllocateInfo.level == vk::CommandBufferLevel::eSecondary )
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 );
114 VkAssert( mCommandBuffer.begin( info ) );
123 assert( mRecording && "CommandBuffer is not in the recording state!" );
124 VkAssert( mCommandBuffer.end() );
130 assert( !mRecording && "Can't reset command buffer during recording!" );
131 assert( mCommandBuffer && "Invalid command buffer!" );
132 mCommandBuffer.reset( vk::CommandBufferResetFlagBits::eReleaseResources );
139 assert( mCommandBuffer && "Invalid command buffer!" );
140 mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(), mCommandBuffer );
144 /** Push wait semaphores */
145 void PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
146 const std::vector<vk::PipelineStageFlags>& stages )
148 mWaitSemaphores = semaphores;
149 mWaitStages = stages;
152 /** Push signal semaphores */
153 void PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
155 mSignalSemaphores = semaphores;
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 )
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 )
169 vkBuffers.emplace_back( buffer->GetVkBuffer() );
170 PushResource( buffer );
173 mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets );
176 void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
179 assert( ( buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer ) &&
180 "The buffer used as index buffer has wrong usage flags!" );
182 PushResource( buffer );
183 mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
186 void BindGraphicsPipeline( Handle<Pipeline> pipeline )
188 PushResource( pipeline );
189 mCurrentPipeline = pipeline;
190 mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
193 void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
194 Handle<Pipeline> pipeline,
196 uint32_t descriptorSetCount )
199 PushResource( pipeline );
200 std::vector<vk::DescriptorSet> vkSets;
201 vkSets.reserve( descriptorSets.size() );
202 for( auto&& set : descriptorSets )
204 vkSets.emplace_back( set->GetVkDescriptorSet() );
208 // TODO: support dynamic offsets
209 mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics,
210 pipeline->GetVkPipelineLayout(),
218 void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
220 mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
224 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
226 mCommandBuffer.drawIndexed(
227 indexCount, instanceCount, firstIndex, static_cast<int32_t>( vertexOffset ), firstInstance );
230 const std::vector<Handle<VkManaged>> GetResources() const
236 void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
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();
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() ) );
251 mCurrentRenderPass = renderPass;
252 mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
255 void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
257 mCurrentRenderPass = renderPassBeginInfo.renderPass;
258 mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
263 mCurrentRenderPass = nullptr;
264 mCommandBuffer.endRenderPass();
267 void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
269 auto vkBuffers = std::vector<vk::CommandBuffer>{};
270 vkBuffers.reserve( commandBuffers.size() );
271 for( auto&& buf : commandBuffers )
273 vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
277 mCommandBuffer.executeCommands( vkBuffers );
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 )
290 if( !imageBarriers.empty() )
292 for( auto&& imageBarrier : imageBarriers )
294 ImageRef imageResource{};
295 if( (imageResource = mGraphics.FindImage( imageBarrier.image )) )
297 PushResource( imageResource );
301 //@ todo other resource tracking
303 mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
306 void CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage, vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
308 PushResource( srcBuffer );
309 PushResource( dstImage );
311 mCommandBuffer.copyBufferToImage( srcBuffer->GetVkBuffer(), dstImage->GetVkImage(), dstLayout, regions );
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
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() } );
331 CommandBuffer& mOwner;
333 CommandPool& mOwnerCommandPool;
334 uint32_t mPoolAllocationIndex;
335 vk::CommandBufferAllocateInfo mAllocateInfo{};
337 vk::CommandBuffer mCommandBuffer{};
339 // semaphores per command buffer
340 std::vector<vk::Semaphore> mSignalSemaphores{};
341 std::vector<vk::Semaphore> mWaitSemaphores{};
342 std::vector<vk::PipelineStageFlags> mWaitStages{};
344 std::vector<Handle<VkManaged>> mResources; // used resources
346 PipelineRef mCurrentPipeline;
348 vk::RenderPass mCurrentRenderPass;
350 FenceRef mFinishedFence;
352 bool mRecording{false};
357 * Class: CommandBuffer
361 CommandBuffer::CommandBuffer( CommandPool& commandPool,
363 const vk::CommandBufferAllocateInfo& allocateInfo,
364 vk::CommandBuffer vkCommandBuffer )
366 mImpl = MakeUnique<Impl>( *this, commandPool, poolIndex, allocateInfo, vkCommandBuffer );
369 CommandBuffer::~CommandBuffer()
373 /** Begin recording */
374 void CommandBuffer::Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
376 mImpl->Begin( usageFlags, inheritanceInfo );
379 /** Finish recording */
380 void CommandBuffer::End()
385 /** Reset command buffer */
386 void CommandBuffer::Reset()
391 /** Free command buffer */
392 void CommandBuffer::Free()
397 /** Push wait semaphores */
398 void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
399 const std::vector<vk::PipelineStageFlags>& stages )
401 mImpl->PushWaitSemaphores( semaphores, stages );
404 /** Push signal semaphores */
405 void CommandBuffer::PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
407 mImpl->PushSignalSemaphores( semaphores );
410 const std::vector<vk::Semaphore>& CommandBuffer::GetSignalSemaphores() const
412 return mImpl->mSignalSemaphores;
415 const std::vector<vk::Semaphore>& CommandBuffer::GetSWaitSemaphores() const
417 return mImpl->mWaitSemaphores;
420 const std::vector<vk::PipelineStageFlags>& CommandBuffer::GetWaitSemaphoreStages() const
422 return mImpl->mWaitStages;
425 vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
427 return mImpl->mCommandBuffer;
430 bool CommandBuffer::IsPrimary() const
432 return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
435 void CommandBuffer::BindVertexBuffers( uint32_t firstBinding,
436 uint32_t bindingCount,
437 std::vector<Handle<Buffer>> buffers,
438 const vk::DeviceSize* pOffsets )
440 mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
443 void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
445 mImpl->BindIndexBuffer( buffer, offset, indexType );
448 void CommandBuffer::BindVertexBuffer( uint32_t binding,
449 const Dali::Graphics::Vulkan::Handle<Buffer>& buffer,
450 vk::DeviceSize offset )
452 mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>( {buffer} ), &offset );
455 void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
457 mImpl->BindGraphicsPipeline( pipeline );
460 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
461 Handle<Pipeline> pipeline,
463 uint32_t descriptorSetCount )
465 mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
468 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
471 mImpl->BindDescriptorSets(
472 descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>( descriptorSets.size() ) );
475 void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
477 mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
480 void CommandBuffer::DrawIndexed(
481 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
483 mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
486 void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
488 mImpl->BeginRenderPass( framebufferId, bufferIndex );
491 void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
493 mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
496 void CommandBuffer::EndRenderPass()
498 mImpl->EndRenderPass();
501 void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
503 mImpl->ExecuteCommands( commandBuffers );
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 )
513 mImpl->PipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
516 void CommandBuffer::CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage,
517 vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
519 mImpl->CopyBufferToImage( srcBuffer, dstImage, dstLayout, regions );
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
530 return mImpl->ImageLayoutTransitionBarrier( image,
531 srcAccessMask, dstAccessMask,
532 oldLayout, newLayout,
536 vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
537 vk::ImageLayout oldLayout,
538 vk::ImageLayout newLayout,
539 vk::ImageAspectFlags aspectMask
543 vk::AccessFlags srcAccessMask, dstAccessMask;
544 vk::PipelineStageFlags srcStageMask, dstStageMask;
548 case vk::ImageLayout::ePreinitialized:
549 case vk::ImageLayout::eUndefined:
552 srcStageMask = vk::PipelineStageFlagBits::eTopOfPipe;
555 case vk::ImageLayout::ePresentSrcKHR:
557 srcAccessMask = vk::AccessFlagBits::eColorAttachmentRead;
558 srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
561 case vk::ImageLayout::eTransferSrcOptimal:
563 srcAccessMask = vk::AccessFlagBits::eMemoryRead;
564 srcStageMask = vk::PipelineStageFlagBits::eTransfer;
567 case vk::ImageLayout::eTransferDstOptimal:
569 srcAccessMask = vk::AccessFlagBits::eMemoryWrite;
570 srcStageMask = vk::PipelineStageFlagBits::eTransfer;
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:
586 case vk::ImageLayout::ePresentSrcKHR:
588 dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
589 dstStageMask = vk::PipelineStageFlagBits::eBottomOfPipe;
592 case vk::ImageLayout::eTransferSrcOptimal:
594 dstAccessMask = vk::AccessFlagBits::eMemoryRead;
595 dstStageMask = vk::PipelineStageFlagBits::eTransfer;
598 case vk::ImageLayout::eTransferDstOptimal:
600 dstAccessMask = vk::AccessFlagBits::eMemoryWrite;
601 dstStageMask = vk::PipelineStageFlagBits::eTransfer;
604 case vk::ImageLayout::eShaderReadOnlyOptimal:
606 dstAccessMask = vk::AccessFlagBits::eMemoryRead;
607 dstStageMask = vk::PipelineStageFlagBits::eVertexShader;
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:
622 return mImpl->ImageLayoutTransitionBarrier( image,
623 srcAccessMask, dstAccessMask,
624 oldLayout, newLayout,
628 uint32_t CommandBuffer::GetPoolAllocationIndex() const
630 return mImpl->mPoolAllocationIndex;
633 bool CommandBuffer::OnDestroy()
635 mImpl->ReleaseCommandBuffer();
639 } // namespace Vulkan
640 } // namespace Graphics