2 * Copyright (c) 2017 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 ) );
105 assert( mRecording && "CommandBuffer is not in the recording state!" );
106 VkAssert( mCommandBuffer.end() );
112 assert( !mRecording && "Can't reset command buffer during recording!" );
113 assert( mCommandBuffer && "Invalid command buffer!" );
114 mCommandBuffer.reset( vk::CommandBufferResetFlagBits::eReleaseResources );
119 assert( mCommandBuffer && "Invalid command buffer!" );
120 mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(), mCommandBuffer );
123 void ImageLayoutTransition( vk::Image image,
124 vk::ImageLayout oldLayout,
125 vk::ImageLayout newLayout,
126 vk::ImageAspectFlags aspectMask )
128 // just push new image barrier until any command is being called or buffer recording ends.
129 // it will make sure we batch barriers together rather than calling cmdPipelineBarrier
130 // for each separately
131 vk::AccessFlags srcAccessMask, dstAccessMask;
132 vk::PipelineStageFlags srcStageMask, dstStageMask;
134 // TODO: add other transitions
137 case vk::ImageLayout::eUndefined:
139 srcStageMask = vk::PipelineStageFlagBits::eTopOfPipe;
142 case vk::ImageLayout::ePresentSrcKHR:
144 srcStageMask = vk::PipelineStageFlagBits::eBottomOfPipe;
145 srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
148 case vk::ImageLayout::eColorAttachmentOptimal:
150 srcStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eColorAttachmentOutput;
151 srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
154 case vk::ImageLayout::eGeneral:
155 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
156 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
157 case vk::ImageLayout::eShaderReadOnlyOptimal:
158 case vk::ImageLayout::eTransferSrcOptimal:
159 case vk::ImageLayout::eTransferDstOptimal:
160 case vk::ImageLayout::ePreinitialized:
161 case vk::ImageLayout::eSharedPresentKHR:
168 case vk::ImageLayout::eColorAttachmentOptimal:
170 dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eFragmentShader;
171 dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eHostWrite;
174 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
176 dstStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eEarlyFragmentTests;
178 vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
181 case vk::ImageLayout::ePresentSrcKHR:
183 dstStageMask = vk::PipelineStageFlagBits::eBottomOfPipe;
184 dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eMemoryRead;
186 case vk::ImageLayout::eGeneral:
187 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
188 case vk::ImageLayout::eShaderReadOnlyOptimal:
189 case vk::ImageLayout::eTransferSrcOptimal:
190 case vk::ImageLayout::eTransferDstOptimal:
191 case vk::ImageLayout::ePreinitialized:
192 case vk::ImageLayout::eUndefined:
193 case vk::ImageLayout::eSharedPresentKHR:
199 RecordImageLayoutTransition(
200 image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, oldLayout, newLayout, aspectMask );
203 #pragma GCC diagnostic push
204 #pragma GCC diagnostic ignored "-Wframe-larger-than="
205 void RecordImageLayoutTransition( vk::Image image,
206 vk::AccessFlags srcAccessMask,
207 vk::AccessFlags dstAccessMask,
208 vk::PipelineStageFlags srcStageMask,
209 vk::PipelineStageFlags dstStageMask,
210 vk::ImageLayout oldLayout,
211 vk::ImageLayout newLayout,
212 vk::ImageAspectFlags aspectMask )
214 vk::ImageSubresourceRange subres;
215 subres.setLayerCount( 1 ).setBaseMipLevel( 0 ).setBaseArrayLayer( 0 ).setLevelCount( 1 ).setAspectMask(
218 auto barrier = vk::ImageMemoryBarrier{};
219 barrier.setImage( image )
220 .setSubresourceRange( subres )
221 .setSrcAccessMask( srcAccessMask )
222 .setDstAccessMask( dstAccessMask )
223 .setOldLayout( oldLayout )
224 .setNewLayout( newLayout );
226 // todo: implement barriers batching
227 mCommandBuffer.pipelineBarrier( srcStageMask, dstStageMask, vk::DependencyFlags{}, nullptr, nullptr, barrier );
229 #pragma GCC diagnostic pop
231 /** Push wait semaphores */
232 void PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
233 const std::vector<vk::PipelineStageFlags>& stages )
235 mWaitSemaphores = semaphores;
236 mWaitStages = stages;
239 /** Push signal semaphores */
240 void PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
242 mSignalSemaphores = semaphores;
245 // TODO: handles should be synchronized
246 void BindVertexBuffers( uint32_t firstBinding,
247 uint32_t bindingCount,
248 std::vector<Handle<Buffer>> buffers,
249 const vk::DeviceSize* pOffsets )
251 // update list of used resources and create an array of VkBuffers
252 std::vector<vk::Buffer> vkBuffers;
253 vkBuffers.reserve( buffers.size() );
254 for( auto&& buffer : buffers )
256 vkBuffers.emplace_back( buffer->GetVkBuffer() );
257 PushResource( buffer );
260 mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets );
263 void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
266 assert( ( buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer ) &&
267 "The buffer used as index buffer has wrong usage flags!" );
269 PushResource( buffer );
270 mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
273 void BindGraphicsPipeline( Handle<Pipeline> pipeline )
275 PushResource( pipeline );
276 mCurrentPipeline = pipeline;
277 mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
280 void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
281 Handle<Pipeline> pipeline,
283 uint32_t descriptorSetCount )
286 PushResource( pipeline );
287 std::vector<vk::DescriptorSet> vkSets;
288 vkSets.reserve( descriptorSets.size() );
289 for( auto&& set : descriptorSets )
291 vkSets.emplace_back( set->GetVkDescriptorSet() );
295 // TODO: support dynamic offsets
296 mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics,
297 pipeline->GetVkPipelineLayout(),
305 void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
307 mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
311 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
313 mCommandBuffer.drawIndexed(
314 indexCount, instanceCount, firstIndex, static_cast<int32_t>( vertexOffset ), firstInstance );
317 const std::vector<Handle<VkManaged>> GetResources() const
323 void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
325 auto& surface = mGraphics.GetSurface( framebufferId );
326 auto renderPass = surface.GetRenderPass();
327 auto frameBuffer = surface.GetFramebuffer( bufferIndex );
328 auto clearValues = surface.GetClearValues();
330 auto info = vk::RenderPassBeginInfo{};
331 info.setFramebuffer( frameBuffer );
332 info.setRenderPass( renderPass );
333 info.setClearValueCount( U32( clearValues.size() ) );
334 info.setPClearValues( clearValues.data() );
335 info.setRenderArea( vk::Rect2D( {0, 0}, surface.GetSize() ) );
337 mCurrentRenderPass = renderPass;
338 mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
341 void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
343 mCurrentRenderPass = renderPassBeginInfo.renderPass;
344 mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
349 mCurrentRenderPass = nullptr;
350 mCommandBuffer.endRenderPass();
353 void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
355 auto vkBuffers = std::vector<vk::CommandBuffer>{};
356 vkBuffers.reserve( commandBuffers.size() );
357 for( auto&& buf : commandBuffers )
359 vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
363 mCommandBuffer.executeCommands( vkBuffers );
367 CommandPool& mOwnerCommandPool;
368 vk::CommandBufferAllocateInfo mAllocateInfo{};
370 vk::CommandBuffer mCommandBuffer{};
372 // semaphores per command buffer
373 std::vector<vk::Semaphore> mSignalSemaphores{};
374 std::vector<vk::Semaphore> mWaitSemaphores{};
375 std::vector<vk::PipelineStageFlags> mWaitStages{};
377 std::vector<Handle<VkManaged>> mResources; // used resources
379 PipelineRef mCurrentPipeline;
381 vk::RenderPass mCurrentRenderPass;
383 bool mRecording{false};
388 * Class: CommandBuffer
392 CommandBuffer::CommandBuffer( CommandPool& commandPool,
393 const vk::CommandBufferAllocateInfo& allocateInfo,
394 vk::CommandBuffer vkCommandBuffer )
396 mImpl = MakeUnique<Impl>( commandPool, allocateInfo, vkCommandBuffer );
399 CommandBuffer::~CommandBuffer()
403 /** Begin recording */
404 void CommandBuffer::Begin( vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo )
406 mImpl->Begin( usageFlags, inheritanceInfo );
409 /** Finish recording */
410 void CommandBuffer::End()
415 /** Reset command buffer */
416 void CommandBuffer::Reset()
421 /** Free command buffer */
422 void CommandBuffer::Free()
427 /** Records image layout transition barrier for one image */
428 void CommandBuffer::ImageLayoutTransition( vk::Image image,
429 vk::ImageLayout oldLayout,
430 vk::ImageLayout newLayout,
431 vk::ImageAspectFlags aspectMask )
433 mImpl->ImageLayoutTransition( image, oldLayout, newLayout, aspectMask );
436 void CommandBuffer::RecordImageLayoutTransition( vk::Image image,
437 vk::AccessFlags srcAccessMask,
438 vk::AccessFlags dstAccessMask,
439 vk::PipelineStageFlags srcStageMask,
440 vk::PipelineStageFlags dstStageMask,
441 vk::ImageLayout oldLayout,
442 vk::ImageLayout newLayout,
443 vk::ImageAspectFlags aspectMask )
445 mImpl->RecordImageLayoutTransition(
446 image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, oldLayout, newLayout, aspectMask );
449 /** Push wait semaphores */
450 void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
451 const std::vector<vk::PipelineStageFlags>& stages )
453 mImpl->PushWaitSemaphores( semaphores, stages );
456 /** Push signal semaphores */
457 void CommandBuffer::PushSignalSemaphores( const std::vector<vk::Semaphore>& semaphores )
459 mImpl->PushSignalSemaphores( semaphores );
462 const std::vector<vk::Semaphore>& CommandBuffer::GetSignalSemaphores() const
464 return mImpl->mSignalSemaphores;
467 const std::vector<vk::Semaphore>& CommandBuffer::GetSWaitSemaphores() const
469 return mImpl->mWaitSemaphores;
472 const std::vector<vk::PipelineStageFlags>& CommandBuffer::GetWaitSemaphoreStages() const
474 return mImpl->mWaitStages;
477 vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
479 return mImpl->mCommandBuffer;
482 bool CommandBuffer::IsPrimary() const
484 return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
487 void CommandBuffer::BindVertexBuffers( uint32_t firstBinding,
488 uint32_t bindingCount,
489 std::vector<Handle<Buffer>> buffers,
490 const vk::DeviceSize* pOffsets )
492 mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
495 void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType )
497 mImpl->BindIndexBuffer( buffer, offset, indexType );
500 void CommandBuffer::BindVertexBuffer( uint32_t binding,
501 Dali::Graphics::Vulkan::Handle<Buffer> buffer,
502 vk::DeviceSize offset )
504 mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>( {buffer} ), &offset );
507 void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
509 mImpl->BindGraphicsPipeline( pipeline );
512 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
513 Handle<Pipeline> pipeline,
515 uint32_t descriptorSetCount )
517 mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
520 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
523 mImpl->BindDescriptorSets(
524 descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>( descriptorSets.size() ) );
527 void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
529 mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
532 void CommandBuffer::DrawIndexed(
533 uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
535 mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
538 void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
540 mImpl->BeginRenderPass( framebufferId, bufferIndex );
543 void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
545 mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
548 void CommandBuffer::EndRenderPass()
550 mImpl->EndRenderPass();
553 void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
555 mImpl->ExecuteCommands( commandBuffers );
558 } // namespace Vulkan
559 } // namespace Graphics