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-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>
35 struct CommandBuffer::Impl
37 Impl( CommandPool& commandPool, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer commandBuffer )
38 : mGraphics( commandPool.GetGraphics() ),
39 mOwnerCommandPool( commandPool ),
40 mAllocateInfo( allocateInfo ),
41 mCommandBuffer( commandBuffer )
55 bool IsResourceAdded( Handle<T> resourceHandle )
57 for( auto&& res : mResources )
59 if( res == resourceHandle )
68 bool PushResource( Handle<T> resourceHandle )
70 if( !IsResourceAdded( resourceHandle ) )
72 mResources.push_back( VkTypeCast<VkManaged>( resourceHandle ) );
81 void Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
83 assert( !mRecording && "CommandBuffer already is in the recording state" );
84 auto info = vk::CommandBufferBeginInfo{};
85 info.setPInheritanceInfo( inheritanceInfo );
86 info.setFlags( usageFlags );
88 // set the inheritance option
89 auto inheritance = vk::CommandBufferInheritanceInfo{}.setSubpass( 0 );
91 if( mAllocateInfo.level == vk::CommandBufferLevel::eSecondary )
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 );
99 VkAssert( mCommandBuffer.begin( info ) );
108 assert( mRecording && "CommandBuffer is not in the recording state!" );
109 VkAssert( mCommandBuffer.end() );
115 assert( !mRecording && "Can't reset command buffer during recording!" );
116 assert( mCommandBuffer && "Invalid command buffer!" );
117 mCommandBuffer.reset( vk::CommandBufferResetFlagBits::eReleaseResources );
124 assert( mCommandBuffer && "Invalid command buffer!" );
125 mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(), mCommandBuffer );
128 void ImageLayoutTransition( vk::Image image,
129 vk::ImageLayout oldLayout,
130 vk::ImageLayout newLayout,
131 vk::ImageAspectFlags aspectMask )
133 // just push new image barrier until any command is being called or buffer recording ends.
134 // it will make sure we batch barriers together rather than calling cmdPipelineBarrier
135 // for each separately
136 vk::AccessFlags srcAccessMask, dstAccessMask;
137 vk::PipelineStageFlags srcStageMask, dstStageMask;
139 // TODO: add other transitions
142 case vk::ImageLayout::eUndefined:
144 srcStageMask = vk::PipelineStageFlagBits::eTopOfPipe;
147 case vk::ImageLayout::ePresentSrcKHR:
149 srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
150 srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eColorAttachmentRead;
153 case vk::ImageLayout::eColorAttachmentOptimal:
155 srcStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eColorAttachmentOutput;
156 srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
159 case vk::ImageLayout::eGeneral:
160 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
161 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
162 case vk::ImageLayout::eShaderReadOnlyOptimal:
163 case vk::ImageLayout::eTransferSrcOptimal:
164 case vk::ImageLayout::eTransferDstOptimal:
165 case vk::ImageLayout::ePreinitialized:
166 case vk::ImageLayout::eSharedPresentKHR:
173 case vk::ImageLayout::eColorAttachmentOptimal:
175 dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;// | */vk::PipelineStageFlagBits::eFragmentShader;
176 dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eMemoryWrite;
179 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
181 dstStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eEarlyFragmentTests;
183 vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
186 case vk::ImageLayout::ePresentSrcKHR:
188 dstStageMask = vk::PipelineStageFlagBits::eBottomOfPipe;
189 dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eMemoryRead;
191 case vk::ImageLayout::eGeneral:
192 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
193 case vk::ImageLayout::eShaderReadOnlyOptimal:
194 case vk::ImageLayout::eTransferSrcOptimal:
195 case vk::ImageLayout::eTransferDstOptimal:
196 case vk::ImageLayout::ePreinitialized:
197 case vk::ImageLayout::eUndefined:
198 case vk::ImageLayout::eSharedPresentKHR:
204 RecordImageLayoutTransition(
205 image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, oldLayout, newLayout, aspectMask );
208 #pragma GCC diagnostic push
209 #pragma GCC diagnostic ignored "-Wframe-larger-than="
210 void RecordImageLayoutTransition( vk::Image image,
211 vk::AccessFlags srcAccessMask,
212 vk::AccessFlags dstAccessMask,
213 vk::PipelineStageFlags srcStageMask,
214 vk::PipelineStageFlags dstStageMask,
215 vk::ImageLayout oldLayout,
216 vk::ImageLayout newLayout,
217 vk::ImageAspectFlags aspectMask )
219 vk::ImageSubresourceRange subres;
220 subres.setLayerCount( 1 ).setBaseMipLevel( 0 ).setBaseArrayLayer( 0 ).setLevelCount( 1 ).setAspectMask(
223 auto barrier = vk::ImageMemoryBarrier{};
224 barrier.setImage( image )
225 .setSubresourceRange( subres )
226 .setSrcAccessMask( srcAccessMask )
227 .setDstAccessMask( dstAccessMask )
228 .setOldLayout( oldLayout )
229 .setNewLayout( newLayout );
231 // todo: implement barriers batching
232 mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, vk::DependencyFlags{}, nullptr, nullptr, barrier );
234 #pragma GCC diagnostic pop
236 /** Push wait semaphores */
237 void PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
238 const std::vector<vk::PipelineStageFlags>& stages )
240 mWaitSemaphores = semaphores;
241 mWaitStages = stages;
244 /** Push signal semaphores */
245 void PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
247 mSignalSemaphores = semaphores;
250 // TODO: handles should be synchronized
251 void BindVertexBuffers( uint32_t firstBinding,
252 uint32_t bindingCount,
253 std::vector<Handle<Buffer>> buffers,
254 const vk::DeviceSize* pOffsets )
256 // update list of used resources and create an array of VkBuffers
257 std::vector<vk::Buffer> vkBuffers;
258 vkBuffers.reserve( buffers.size() );
259 for( auto&& buffer : buffers )
261 vkBuffers.emplace_back( buffer->GetVkBuffer() );
262 PushResource( buffer );
265 mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets );
268 void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
271 assert( ( buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer ) &&
272 "The buffer used as index buffer has wrong usage flags!" );
274 PushResource( buffer );
275 mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
278 void BindGraphicsPipeline( Handle<Pipeline> pipeline )
280 PushResource( pipeline );
281 mCurrentPipeline = pipeline;
282 mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
285 void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
286 Handle<Pipeline> pipeline,
288 uint32_t descriptorSetCount )
291 PushResource( pipeline );
292 std::vector<vk::DescriptorSet> vkSets;
293 vkSets.reserve( descriptorSets.size() );
294 for( auto&& set : descriptorSets )
296 vkSets.emplace_back( set->GetVkDescriptorSet() );
300 // TODO: support dynamic offsets
301 mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics,
302 pipeline->GetVkPipelineLayout(),
310 void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
312 mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
316 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
318 mCommandBuffer.drawIndexed(
319 indexCount, instanceCount, firstIndex, static_cast<int32_t>( vertexOffset ), firstInstance );
322 const std::vector<Handle<VkManaged>> GetResources() const
328 void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
330 auto& surface = mGraphics.GetSurface( framebufferId );
331 auto renderPass = surface.GetRenderPass();
332 auto frameBuffer = surface.GetFramebuffer( bufferIndex );
333 auto clearValues = surface.GetClearValues();
335 auto info = vk::RenderPassBeginInfo{};
336 info.setFramebuffer( frameBuffer );
337 info.setRenderPass( renderPass );
338 info.setClearValueCount( U32( clearValues.size() ) );
339 info.setPClearValues( clearValues.data() );
340 info.setRenderArea( vk::Rect2D( {0, 0}, surface.GetSize() ) );
342 mCurrentRenderPass = renderPass;
343 mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
346 void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
348 mCurrentRenderPass = renderPassBeginInfo.renderPass;
349 mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
354 mCurrentRenderPass = nullptr;
355 mCommandBuffer.endRenderPass();
358 void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
360 auto vkBuffers = std::vector<vk::CommandBuffer>{};
361 vkBuffers.reserve( commandBuffers.size() );
362 for( auto&& buf : commandBuffers )
364 vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
368 mCommandBuffer.executeCommands( vkBuffers );
372 CommandPool& mOwnerCommandPool;
373 vk::CommandBufferAllocateInfo mAllocateInfo{};
375 vk::CommandBuffer mCommandBuffer{};
377 // semaphores per command buffer
378 std::vector<vk::Semaphore> mSignalSemaphores{};
379 std::vector<vk::Semaphore> mWaitSemaphores{};
380 std::vector<vk::PipelineStageFlags> mWaitStages{};
382 std::vector<Handle<VkManaged>> mResources; // used resources
384 PipelineRef mCurrentPipeline;
386 vk::RenderPass mCurrentRenderPass;
388 bool mRecording{false};
393 * Class: CommandBuffer
397 CommandBuffer::CommandBuffer( CommandPool& commandPool,
398 const vk::CommandBufferAllocateInfo& allocateInfo,
399 vk::CommandBuffer vkCommandBuffer )
401 mImpl = MakeUnique<Impl>( commandPool, allocateInfo, vkCommandBuffer );
404 CommandBuffer::~CommandBuffer()
408 /** Begin recording */
409 void CommandBuffer::Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
411 mImpl->Begin( usageFlags, inheritanceInfo );
414 /** Finish recording */
415 void CommandBuffer::End()
420 /** Reset command buffer */
421 void CommandBuffer::Reset()
426 /** Free command buffer */
427 void CommandBuffer::Free()
432 /** Records image layout transition barrier for one image */
433 void CommandBuffer::ImageLayoutTransition( vk::Image image,
434 vk::ImageLayout oldLayout,
435 vk::ImageLayout newLayout,
436 vk::ImageAspectFlags aspectMask )
438 mImpl->ImageLayoutTransition( image, oldLayout, newLayout, aspectMask );
442 void CommandBuffer::RecordImageLayoutTransition( vk::Image image,
443 vk::AccessFlags srcAccessMask,
444 vk::AccessFlags dstAccessMask,
445 vk::PipelineStageFlags srcStageMask,
446 vk::PipelineStageFlags dstStageMask,
447 vk::ImageLayout oldLayout,
448 vk::ImageLayout newLayout,
449 vk::ImageAspectFlags aspectMask )
451 mImpl->RecordImageLayoutTransition(
452 image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, oldLayout, newLayout, aspectMask );
455 /** Push wait semaphores */
456 void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
457 const std::vector<vk::PipelineStageFlags>& stages )
459 mImpl->PushWaitSemaphores( semaphores, stages );
462 /** Push signal semaphores */
463 void CommandBuffer::PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
465 mImpl->PushSignalSemaphores( semaphores );
468 const std::vector<vk::Semaphore>& CommandBuffer::GetSignalSemaphores() const
470 return mImpl->mSignalSemaphores;
473 const std::vector<vk::Semaphore>& CommandBuffer::GetSWaitSemaphores() const
475 return mImpl->mWaitSemaphores;
478 const std::vector<vk::PipelineStageFlags>& CommandBuffer::GetWaitSemaphoreStages() const
480 return mImpl->mWaitStages;
483 vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
485 return mImpl->mCommandBuffer;
488 bool CommandBuffer::IsPrimary() const
490 return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
493 void CommandBuffer::BindVertexBuffers( uint32_t firstBinding,
494 uint32_t bindingCount,
495 std::vector<Handle<Buffer>> buffers,
496 const vk::DeviceSize* pOffsets )
498 mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
501 void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
503 mImpl->BindIndexBuffer( buffer, offset, indexType );
506 void CommandBuffer::BindVertexBuffer( uint32_t binding,
507 Dali::Graphics::Vulkan::Handle<Buffer> buffer,
508 vk::DeviceSize offset )
510 mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>( {buffer} ), &offset );
513 void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
515 mImpl->BindGraphicsPipeline( pipeline );
518 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
519 Handle<Pipeline> pipeline,
521 uint32_t descriptorSetCount )
523 mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
526 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
529 mImpl->BindDescriptorSets(
530 descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>( descriptorSets.size() ) );
533 void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
535 mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
538 void CommandBuffer::DrawIndexed(
539 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
541 mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
544 void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
546 mImpl->BeginRenderPass( framebufferId, bufferIndex );
549 void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
551 mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
554 void CommandBuffer::EndRenderPass()
556 mImpl->EndRenderPass();
559 void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
561 mImpl->ExecuteCommands( commandBuffers );
564 } // namespace Vulkan
565 } // namespace Graphics