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 );
143 #pragma GCC diagnostic pop
145 /** Push wait semaphores */
146 void PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
147 const std::vector<vk::PipelineStageFlags>& stages )
149 mWaitSemaphores = semaphores;
150 mWaitStages = stages;
153 /** Push signal semaphores */
154 void PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
156 mSignalSemaphores = semaphores;
159 // TODO: handles should be synchronized
160 void BindVertexBuffers( uint32_t firstBinding,
161 uint32_t bindingCount,
162 std::vector<Handle<Buffer>> buffers,
163 const vk::DeviceSize* pOffsets )
165 // update list of used resources and create an array of VkBuffers
166 std::vector<vk::Buffer> vkBuffers;
167 vkBuffers.reserve( buffers.size() );
168 for( auto&& buffer : buffers )
170 vkBuffers.emplace_back( buffer->GetVkBuffer() );
171 PushResource( buffer );
174 mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets );
177 void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
180 assert( ( buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer ) &&
181 "The buffer used as index buffer has wrong usage flags!" );
183 PushResource( buffer );
184 mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
187 void BindGraphicsPipeline( Handle<Pipeline> pipeline )
189 PushResource( pipeline );
190 mCurrentPipeline = pipeline;
191 mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
194 void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
195 Handle<Pipeline> pipeline,
197 uint32_t descriptorSetCount )
200 PushResource( pipeline );
201 std::vector<vk::DescriptorSet> vkSets;
202 vkSets.reserve( descriptorSets.size() );
203 for( auto&& set : descriptorSets )
205 vkSets.emplace_back( set->GetVkDescriptorSet() );
209 // TODO: support dynamic offsets
210 mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics,
211 pipeline->GetVkPipelineLayout(),
219 void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
221 mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
225 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
227 mCommandBuffer.drawIndexed(
228 indexCount, instanceCount, firstIndex, static_cast<int32_t>( vertexOffset ), firstInstance );
231 const std::vector<Handle<VkManaged>> GetResources() const
237 void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
239 auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
240 auto surface = mGraphics.GetSurface( 0u );
241 auto frameBuffer = swapchain->GetCurrentFramebuffer();
242 auto renderPass = frameBuffer->GetVkRenderPass();
243 auto clearValues = frameBuffer->GetDefaultClearValues();
245 auto info = vk::RenderPassBeginInfo{};
246 info.setFramebuffer( frameBuffer->GetVkFramebuffer() );
247 info.setRenderPass( renderPass );
248 info.setClearValueCount( U32( clearValues.size() ) );
249 info.setPClearValues( clearValues.data() );
250 info.setRenderArea( vk::Rect2D( {0, 0}, surface->GetSize() ) );
252 mCurrentRenderPass = renderPass;
253 mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
256 void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
258 mCurrentRenderPass = renderPassBeginInfo.renderPass;
259 mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
264 mCurrentRenderPass = nullptr;
265 mCommandBuffer.endRenderPass();
268 void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
270 auto vkBuffers = std::vector<vk::CommandBuffer>{};
271 vkBuffers.reserve( commandBuffers.size() );
272 for( auto&& buf : commandBuffers )
274 vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
278 mCommandBuffer.executeCommands( vkBuffers );
281 void PipelineBarrier( vk::PipelineStageFlags srcStageMask,
282 vk::PipelineStageFlags dstStageMask,
283 vk::DependencyFlags dependencyFlags,
284 std::vector<vk::MemoryBarrier> memoryBarriers,
285 std::vector<vk::BufferMemoryBarrier> bufferBarriers,
286 std::vector<vk::ImageMemoryBarrier> imageBarriers )
291 if( !imageBarriers.empty() )
293 for( auto&& imageBarrier : imageBarriers )
295 ImageRef imageResource{};
296 if( imageResource = mGraphics.FindImage( imageBarrier.image ) )
298 PushResource( imageResource );
302 //@ todo other resource tracking
304 mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
307 void CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage, vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
309 PushResource( srcBuffer );
310 PushResource( dstImage );
312 mCommandBuffer.copyBufferToImage( srcBuffer->GetVkBuffer(), dstImage->GetVkImage(), dstLayout, regions );
315 vk::ImageMemoryBarrier ImageLayoutTransitionBarrier( ImageRef image,
316 const vk::AccessFlags& srcAccessMask,
317 const vk::AccessFlags& dstAccessMask,
318 vk::ImageLayout oldLayout,
319 vk::ImageLayout newLayout,
320 const vk::ImageAspectFlags& aspectMask
323 return vk::ImageMemoryBarrier{}
324 .setNewLayout( newLayout )
325 .setImage( image->GetVkImage() )
326 .setOldLayout( oldLayout )
327 .setSrcAccessMask( srcAccessMask )
328 .setDstAccessMask( dstAccessMask )
329 .setSubresourceRange( vk::ImageSubresourceRange{ aspectMask, 0, image->GetLevelCount(), 0, image->GetLayerCount() } );
332 CommandBuffer& mOwner;
334 CommandPool& mOwnerCommandPool;
335 uint32_t mPoolAllocationIndex;
336 vk::CommandBufferAllocateInfo mAllocateInfo{};
338 vk::CommandBuffer mCommandBuffer{};
340 // semaphores per command buffer
341 std::vector<vk::Semaphore> mSignalSemaphores{};
342 std::vector<vk::Semaphore> mWaitSemaphores{};
343 std::vector<vk::PipelineStageFlags> mWaitStages{};
345 std::vector<Handle<VkManaged>> mResources; // used resources
347 PipelineRef mCurrentPipeline;
349 vk::RenderPass mCurrentRenderPass;
351 FenceRef mFinishedFence;
353 bool mRecording{false};
358 * Class: CommandBuffer
362 CommandBuffer::CommandBuffer( CommandPool& commandPool,
364 const vk::CommandBufferAllocateInfo& allocateInfo,
365 vk::CommandBuffer vkCommandBuffer )
367 mImpl = MakeUnique<Impl>( *this, commandPool, poolIndex, allocateInfo, vkCommandBuffer );
370 CommandBuffer::~CommandBuffer()
374 /** Begin recording */
375 void CommandBuffer::Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
377 mImpl->Begin( usageFlags, inheritanceInfo );
380 /** Finish recording */
381 void CommandBuffer::End()
386 /** Reset command buffer */
387 void CommandBuffer::Reset()
392 /** Free command buffer */
393 void CommandBuffer::Free()
398 /** Push wait semaphores */
399 void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
400 const std::vector<vk::PipelineStageFlags>& stages )
402 mImpl->PushWaitSemaphores( semaphores, stages );
405 /** Push signal semaphores */
406 void CommandBuffer::PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
408 mImpl->PushSignalSemaphores( semaphores );
411 const std::vector<vk::Semaphore>& CommandBuffer::GetSignalSemaphores() const
413 return mImpl->mSignalSemaphores;
416 const std::vector<vk::Semaphore>& CommandBuffer::GetSWaitSemaphores() const
418 return mImpl->mWaitSemaphores;
421 const std::vector<vk::PipelineStageFlags>& CommandBuffer::GetWaitSemaphoreStages() const
423 return mImpl->mWaitStages;
426 vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
428 return mImpl->mCommandBuffer;
431 bool CommandBuffer::IsPrimary() const
433 return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
436 void CommandBuffer::BindVertexBuffers( uint32_t firstBinding,
437 uint32_t bindingCount,
438 std::vector<Handle<Buffer>> buffers,
439 const vk::DeviceSize* pOffsets )
441 mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
444 void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
446 mImpl->BindIndexBuffer( buffer, offset, indexType );
449 void CommandBuffer::BindVertexBuffer( uint32_t binding,
450 Dali::Graphics::Vulkan::Handle<Buffer> buffer,
451 vk::DeviceSize offset )
453 mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>( {buffer} ), &offset );
456 void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
458 mImpl->BindGraphicsPipeline( pipeline );
461 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
462 Handle<Pipeline> pipeline,
464 uint32_t descriptorSetCount )
466 mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
469 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
472 mImpl->BindDescriptorSets(
473 descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>( descriptorSets.size() ) );
476 void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
478 mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
481 void CommandBuffer::DrawIndexed(
482 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
484 mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
487 void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
489 mImpl->BeginRenderPass( framebufferId, bufferIndex );
492 void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
494 mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
497 void CommandBuffer::EndRenderPass()
499 mImpl->EndRenderPass();
502 void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
504 mImpl->ExecuteCommands( commandBuffers );
507 void CommandBuffer::PipelineBarrier( vk::PipelineStageFlags srcStageMask,
508 vk::PipelineStageFlags dstStageMask,
509 vk::DependencyFlags dependencyFlags,
510 std::vector<vk::MemoryBarrier> memoryBarriers,
511 std::vector<vk::BufferMemoryBarrier> bufferBarriers,
512 std::vector<vk::ImageMemoryBarrier> imageBarriers )
514 mImpl->PipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
517 void CommandBuffer::CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage,
518 vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
520 mImpl->CopyBufferToImage( srcBuffer, dstImage, dstLayout, regions );
523 vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
524 vk::AccessFlags srcAccessMask,
525 vk::AccessFlags dstAccessMask,
526 vk::ImageLayout oldLayout,
527 vk::ImageLayout newLayout,
528 vk::ImageAspectFlags aspectMask
531 return mImpl->ImageLayoutTransitionBarrier( image,
532 srcAccessMask, dstAccessMask,
533 oldLayout, newLayout,
537 vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
538 vk::ImageLayout newLayout,
539 vk::ImageAspectFlags aspectMask
543 vk::AccessFlags srcAccessMask, dstAccessMask;
544 vk::PipelineStageFlags srcStageMask, dstStageMask;
546 auto oldLayout = image->GetVkImageLayout();
550 case vk::ImageLayout::ePreinitialized:
551 case vk::ImageLayout::eUndefined:
554 srcStageMask = vk::PipelineStageFlagBits::eTopOfPipe;
557 case vk::ImageLayout::ePresentSrcKHR:
559 srcAccessMask = vk::AccessFlagBits::eColorAttachmentRead;
560 srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
563 case vk::ImageLayout::eTransferSrcOptimal:
565 srcAccessMask = vk::AccessFlagBits::eMemoryRead;
566 srcStageMask = vk::PipelineStageFlagBits::eTransfer;
569 case vk::ImageLayout::eTransferDstOptimal:
571 srcAccessMask = vk::AccessFlagBits::eMemoryWrite;
572 srcStageMask = vk::PipelineStageFlagBits::eTransfer;
575 case vk::ImageLayout::eGeneral:
576 case vk::ImageLayout::eColorAttachmentOptimal:
577 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
578 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
579 case vk::ImageLayout::eShaderReadOnlyOptimal:
580 case vk::ImageLayout::eSharedPresentKHR:
588 case vk::ImageLayout::ePresentSrcKHR:
590 dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
591 dstStageMask = vk::PipelineStageFlagBits::eBottomOfPipe;
594 case vk::ImageLayout::eTransferSrcOptimal:
596 dstAccessMask = vk::AccessFlagBits::eMemoryRead;
597 dstStageMask = vk::PipelineStageFlagBits::eTransfer;
600 case vk::ImageLayout::eTransferDstOptimal:
602 dstAccessMask = vk::AccessFlagBits::eMemoryWrite;
603 dstStageMask = vk::PipelineStageFlagBits::eTransfer;
606 case vk::ImageLayout::eShaderReadOnlyOptimal:
608 dstAccessMask = vk::AccessFlagBits::eMemoryRead;
609 dstStageMask = vk::PipelineStageFlagBits::eVertexShader;
612 case vk::ImageLayout::eUndefined:
613 case vk::ImageLayout::eGeneral:
614 case vk::ImageLayout::eColorAttachmentOptimal:
615 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
616 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
617 case vk::ImageLayout::ePreinitialized:
618 case vk::ImageLayout::eSharedPresentKHR:
624 return mImpl->ImageLayoutTransitionBarrier( image,
625 srcAccessMask, dstAccessMask,
626 oldLayout, newLayout,
630 uint32_t CommandBuffer::GetPoolAllocationIndex() const
632 return mImpl->mPoolAllocationIndex;
635 bool CommandBuffer::OnDestroy()
637 mImpl->ReleaseCommandBuffer();
641 } // namespace Vulkan
642 } // namespace Graphics