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( CommandPool& commandPool, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer commandBuffer )
40 : mGraphics( commandPool.GetGraphics() ),
41 mOwnerCommandPool( commandPool ),
42 mAllocateInfo( allocateInfo ),
43 mCommandBuffer( commandBuffer )
50 mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(),
60 bool IsResourceAdded( Handle<T> resourceHandle )
62 for( auto&& res : mResources )
64 if( res == resourceHandle )
73 bool PushResource( Handle<T> resourceHandle )
75 if( !IsResourceAdded( resourceHandle ) )
77 mResources.push_back( VkTypeCast<VkManaged>( resourceHandle ) );
86 void Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
88 assert( !mRecording && "CommandBuffer already is in the recording state" );
89 auto info = vk::CommandBufferBeginInfo{};
90 info.setPInheritanceInfo( inheritanceInfo );
91 info.setFlags( usageFlags );
93 // set the inheritance option
94 auto inheritance = vk::CommandBufferInheritanceInfo{}.setSubpass( 0 );
96 if( mAllocateInfo.level == vk::CommandBufferLevel::eSecondary )
98 // Render pass is obtained from the default framebuffer
99 // it's a legacy but little nicer
100 auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
101 inheritance.setRenderPass( swapchain->GetCurrentFramebuffer()->GetVkRenderPass() );
102 info.setPInheritanceInfo( &inheritance );
105 VkAssert( mCommandBuffer.begin( info ) );
114 assert( mRecording && "CommandBuffer is not in the recording state!" );
115 VkAssert( mCommandBuffer.end() );
121 assert( !mRecording && "Can't reset command buffer during recording!" );
122 assert( mCommandBuffer && "Invalid command buffer!" );
123 mCommandBuffer.reset( vk::CommandBufferResetFlagBits::eReleaseResources );
130 assert( mCommandBuffer && "Invalid command buffer!" );
131 mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(), mCommandBuffer );
134 #pragma GCC diagnostic pop
136 /** Push wait semaphores */
137 void PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
138 const std::vector<vk::PipelineStageFlags>& stages )
140 mWaitSemaphores = semaphores;
141 mWaitStages = stages;
144 /** Push signal semaphores */
145 void PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
147 mSignalSemaphores = semaphores;
150 // TODO: handles should be synchronized
151 void BindVertexBuffers( uint32_t firstBinding,
152 uint32_t bindingCount,
153 std::vector<Handle<Buffer>> buffers,
154 const vk::DeviceSize* pOffsets )
156 // update list of used resources and create an array of VkBuffers
157 std::vector<vk::Buffer> vkBuffers;
158 vkBuffers.reserve( buffers.size() );
159 for( auto&& buffer : buffers )
161 vkBuffers.emplace_back( buffer->GetVkBuffer() );
162 PushResource( buffer );
165 mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets );
168 void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
171 assert( ( buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer ) &&
172 "The buffer used as index buffer has wrong usage flags!" );
174 PushResource( buffer );
175 mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
178 void BindGraphicsPipeline( Handle<Pipeline> pipeline )
180 PushResource( pipeline );
181 mCurrentPipeline = pipeline;
182 mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
185 void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
186 Handle<Pipeline> pipeline,
188 uint32_t descriptorSetCount )
191 PushResource( pipeline );
192 std::vector<vk::DescriptorSet> vkSets;
193 vkSets.reserve( descriptorSets.size() );
194 for( auto&& set : descriptorSets )
196 vkSets.emplace_back( set->GetVkDescriptorSet() );
200 // TODO: support dynamic offsets
201 mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics,
202 pipeline->GetVkPipelineLayout(),
210 void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
212 mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
216 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
218 mCommandBuffer.drawIndexed(
219 indexCount, instanceCount, firstIndex, static_cast<int32_t>( vertexOffset ), firstInstance );
222 const std::vector<Handle<VkManaged>> GetResources() const
228 void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
230 auto swapchain = mGraphics.GetSwapchainForFBID( 0u );
231 auto surface = mGraphics.GetSurface( 0u );
232 auto frameBuffer = swapchain->GetCurrentFramebuffer();
233 auto renderPass = frameBuffer->GetVkRenderPass();
234 auto clearValues = frameBuffer->GetDefaultClearValues();
236 auto info = vk::RenderPassBeginInfo{};
237 info.setFramebuffer( frameBuffer->GetVkFramebuffer() );
238 info.setRenderPass( renderPass );
239 info.setClearValueCount( U32( clearValues.size() ) );
240 info.setPClearValues( clearValues.data() );
241 info.setRenderArea( vk::Rect2D( {0, 0}, surface->GetSize() ) );
243 mCurrentRenderPass = renderPass;
244 mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
247 void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
249 mCurrentRenderPass = renderPassBeginInfo.renderPass;
250 mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
255 mCurrentRenderPass = nullptr;
256 mCommandBuffer.endRenderPass();
259 void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
261 auto vkBuffers = std::vector<vk::CommandBuffer>{};
262 vkBuffers.reserve( commandBuffers.size() );
263 for( auto&& buf : commandBuffers )
265 vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
269 mCommandBuffer.executeCommands( vkBuffers );
272 void PipelineBarrier( vk::PipelineStageFlags srcStageMask,
273 vk::PipelineStageFlags dstStageMask,
274 vk::DependencyFlags dependencyFlags,
275 std::vector<vk::MemoryBarrier> memoryBarriers,
276 std::vector<vk::BufferMemoryBarrier> bufferBarriers,
277 std::vector<vk::ImageMemoryBarrier> imageBarriers )
282 if( !imageBarriers.empty() )
284 for( auto&& imageBarrier : imageBarriers )
286 ImageRef imageResource{};
287 if( imageResource = mGraphics.FindImage( imageBarrier.image ) )
289 PushResource( imageResource );
293 //@ todo other resource tracking
295 mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
298 void CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage, vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
300 PushResource( srcBuffer );
301 PushResource( dstImage );
303 mCommandBuffer.copyBufferToImage( srcBuffer->GetVkBuffer(), dstImage->GetVkImage(), dstLayout, regions );
306 vk::ImageMemoryBarrier ImageLayoutTransitionBarrier( ImageRef image,
307 const vk::AccessFlags& srcAccessMask,
308 const vk::AccessFlags& dstAccessMask,
309 vk::ImageLayout oldLayout,
310 vk::ImageLayout newLayout,
311 const vk::ImageAspectFlags& aspectMask
314 return vk::ImageMemoryBarrier{}
315 .setNewLayout( newLayout )
316 .setImage( image->GetVkImage() )
317 .setOldLayout( oldLayout )
318 .setSrcAccessMask( srcAccessMask )
319 .setDstAccessMask( dstAccessMask )
320 .setSubresourceRange( vk::ImageSubresourceRange{ aspectMask, 0, image->GetLevelCount(), 0, image->GetLayerCount() } );
325 CommandPool& mOwnerCommandPool;
326 vk::CommandBufferAllocateInfo mAllocateInfo{};
328 vk::CommandBuffer mCommandBuffer{};
330 // semaphores per command buffer
331 std::vector<vk::Semaphore> mSignalSemaphores{};
332 std::vector<vk::Semaphore> mWaitSemaphores{};
333 std::vector<vk::PipelineStageFlags> mWaitStages{};
335 std::vector<Handle<VkManaged>> mResources; // used resources
337 PipelineRef mCurrentPipeline;
339 vk::RenderPass mCurrentRenderPass;
341 FenceRef mFinishedFence;
343 bool mRecording{false};
348 * Class: CommandBuffer
352 CommandBuffer::CommandBuffer( CommandPool& commandPool,
353 const vk::CommandBufferAllocateInfo& allocateInfo,
354 vk::CommandBuffer vkCommandBuffer )
356 mImpl = MakeUnique<Impl>( commandPool, allocateInfo, vkCommandBuffer );
359 CommandBuffer::~CommandBuffer()
363 /** Begin recording */
364 void CommandBuffer::Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
366 mImpl->Begin( usageFlags, inheritanceInfo );
369 /** Finish recording */
370 void CommandBuffer::End()
375 /** Reset command buffer */
376 void CommandBuffer::Reset()
381 /** Free command buffer */
382 void CommandBuffer::Free()
387 void CommandBuffer::OnRelease( uint32_t refcount )
389 VkManaged::OnRelease( refcount );
392 /** Push wait semaphores */
393 void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
394 const std::vector<vk::PipelineStageFlags>& stages )
396 mImpl->PushWaitSemaphores( semaphores, stages );
399 /** Push signal semaphores */
400 void CommandBuffer::PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
402 mImpl->PushSignalSemaphores( semaphores );
405 const std::vector<vk::Semaphore>& CommandBuffer::GetSignalSemaphores() const
407 return mImpl->mSignalSemaphores;
410 const std::vector<vk::Semaphore>& CommandBuffer::GetSWaitSemaphores() const
412 return mImpl->mWaitSemaphores;
415 const std::vector<vk::PipelineStageFlags>& CommandBuffer::GetWaitSemaphoreStages() const
417 return mImpl->mWaitStages;
420 vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
422 return mImpl->mCommandBuffer;
425 bool CommandBuffer::IsPrimary() const
427 return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
430 void CommandBuffer::BindVertexBuffers( uint32_t firstBinding,
431 uint32_t bindingCount,
432 std::vector<Handle<Buffer>> buffers,
433 const vk::DeviceSize* pOffsets )
435 mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
438 void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
440 mImpl->BindIndexBuffer( buffer, offset, indexType );
443 void CommandBuffer::BindVertexBuffer( uint32_t binding,
444 Dali::Graphics::Vulkan::Handle<Buffer> buffer,
445 vk::DeviceSize offset )
447 mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>( {buffer} ), &offset );
450 void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
452 mImpl->BindGraphicsPipeline( pipeline );
455 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
456 Handle<Pipeline> pipeline,
458 uint32_t descriptorSetCount )
460 mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
463 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
466 mImpl->BindDescriptorSets(
467 descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>( descriptorSets.size() ) );
470 void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
472 mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
475 void CommandBuffer::DrawIndexed(
476 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
478 mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
481 void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
483 mImpl->BeginRenderPass( framebufferId, bufferIndex );
486 void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
488 mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
491 void CommandBuffer::EndRenderPass()
493 mImpl->EndRenderPass();
496 void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
498 mImpl->ExecuteCommands( commandBuffers );
501 void CommandBuffer::PipelineBarrier( vk::PipelineStageFlags srcStageMask,
502 vk::PipelineStageFlags dstStageMask,
503 vk::DependencyFlags dependencyFlags,
504 std::vector<vk::MemoryBarrier> memoryBarriers,
505 std::vector<vk::BufferMemoryBarrier> bufferBarriers,
506 std::vector<vk::ImageMemoryBarrier> imageBarriers )
508 mImpl->PipelineBarrier( srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferBarriers, imageBarriers );
511 void CommandBuffer::CopyBufferToImage( BufferRef srcBuffer, ImageRef dstImage,
512 vk::ImageLayout dstLayout, std::vector<vk::BufferImageCopy> regions )
514 mImpl->CopyBufferToImage( srcBuffer, dstImage, dstLayout, regions );
517 vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
518 vk::AccessFlags srcAccessMask,
519 vk::AccessFlags dstAccessMask,
520 vk::ImageLayout oldLayout,
521 vk::ImageLayout newLayout,
522 vk::ImageAspectFlags aspectMask
525 return mImpl->ImageLayoutTransitionBarrier( image,
526 srcAccessMask, dstAccessMask,
527 oldLayout, newLayout,
531 vk::ImageMemoryBarrier CommandBuffer::ImageLayoutTransitionBarrier( ImageRef image,
532 vk::ImageLayout newLayout,
533 vk::ImageAspectFlags aspectMask
537 vk::AccessFlags srcAccessMask, dstAccessMask;
538 vk::PipelineStageFlags srcStageMask, dstStageMask;
540 auto oldLayout = image->GetVkImageLayout();
544 case vk::ImageLayout::ePreinitialized:
545 case vk::ImageLayout::eUndefined:
548 srcStageMask = vk::PipelineStageFlagBits::eTopOfPipe;
551 case vk::ImageLayout::ePresentSrcKHR:
553 srcAccessMask = vk::AccessFlagBits::eColorAttachmentRead;
554 srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
557 case vk::ImageLayout::eTransferSrcOptimal:
559 srcAccessMask = vk::AccessFlagBits::eMemoryRead;
560 srcStageMask = vk::PipelineStageFlagBits::eTransfer;
563 case vk::ImageLayout::eTransferDstOptimal:
565 srcAccessMask = vk::AccessFlagBits::eMemoryWrite;
566 srcStageMask = vk::PipelineStageFlagBits::eTransfer;
569 case vk::ImageLayout::eGeneral:
570 case vk::ImageLayout::eColorAttachmentOptimal:
571 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
572 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
573 case vk::ImageLayout::eShaderReadOnlyOptimal:
574 case vk::ImageLayout::eSharedPresentKHR:
582 case vk::ImageLayout::ePresentSrcKHR:
584 dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
585 dstStageMask = vk::PipelineStageFlagBits::eBottomOfPipe;
588 case vk::ImageLayout::eTransferSrcOptimal:
590 dstAccessMask = vk::AccessFlagBits::eMemoryRead;
591 dstStageMask = vk::PipelineStageFlagBits::eTransfer;
594 case vk::ImageLayout::eTransferDstOptimal:
596 dstAccessMask = vk::AccessFlagBits::eMemoryWrite;
597 dstStageMask = vk::PipelineStageFlagBits::eTransfer;
600 case vk::ImageLayout::eShaderReadOnlyOptimal:
602 dstAccessMask = vk::AccessFlagBits::eMemoryRead;
603 dstStageMask = vk::PipelineStageFlagBits::eVertexShader;
606 case vk::ImageLayout::eUndefined:
607 case vk::ImageLayout::eGeneral:
608 case vk::ImageLayout::eColorAttachmentOptimal:
609 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
610 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
611 case vk::ImageLayout::ePreinitialized:
612 case vk::ImageLayout::eSharedPresentKHR:
618 return mImpl->ImageLayoutTransitionBarrier( image,
619 srcAccessMask, dstAccessMask,
620 oldLayout, newLayout,
624 } // namespace Vulkan
625 } // namespace Graphics