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-types.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-graphics.h>
23 #include <dali/graphics/vulkan/vulkan-buffer.h>
24 #include <dali/graphics/vulkan/vulkan-image.h>
25 #include <dali/graphics/vulkan/vulkan-pipeline.h>
26 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
27 #include <dali/graphics/vulkan/vulkan-surface.h>
36 struct CommandBuffer::Impl
38 Impl( CommandPool& commandPool, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer commandBuffer )
39 : mGraphics( commandPool.GetGraphics() ),
40 mOwnerCommandPool( commandPool ),
41 mAllocateInfo( allocateInfo ),
42 mCommandBuffer( commandBuffer )
57 bool IsResourceAdded( Handle<T> resourceHandle )
59 for( auto&& res : mResources )
61 if( res == resourceHandle )
70 bool PushResource( Handle<T> resourceHandle )
72 if(!IsResourceAdded( resourceHandle ))
74 mResources.push_back(VkTypeCast<VkManaged>( resourceHandle ));
83 void Begin(vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo)
85 assert(!mRecording && "CommandBuffer already is in the recording state");
86 auto info = vk::CommandBufferBeginInfo{};
87 info.setPInheritanceInfo(inheritanceInfo);
88 info.setFlags(usageFlags);
90 // set the inheritance option
91 auto inheritance = vk::CommandBufferInheritanceInfo{}.setSubpass( 0 );
93 if( mAllocateInfo.level == vk::CommandBufferLevel::eSecondary )
95 // todo: sets render pass from 'default' surface, should be supplied from primary command buffer
96 // which has render pass associated within execution context
97 inheritance.setRenderPass( mGraphics.GetSurface(0).GetRenderPass() );
98 info.setPInheritanceInfo( &inheritance );
101 VkAssert(mCommandBuffer.begin(info));
107 assert(mRecording && "CommandBuffer is not in the recording state!");
108 VkAssert(mCommandBuffer.end());
114 assert(!mRecording && "Can't reset command buffer during recording!");
115 assert(mCommandBuffer && "Invalid command buffer!");
116 mCommandBuffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources);
121 assert(mCommandBuffer && "Invalid command buffer!");
122 mGraphics.GetDevice().freeCommandBuffers(mOwnerCommandPool.GetPool(), mCommandBuffer);
125 void ImageLayoutTransition(vk::Image image,
126 vk::ImageLayout oldLayout,
127 vk::ImageLayout newLayout,
128 vk::ImageAspectFlags aspectMask)
130 // just push new image barrier until any command is being called or buffer recording ends.
131 // it will make sure we batch barriers together rather than calling cmdPipelineBarrier
132 // for each separately
133 vk::AccessFlags srcAccessMask, dstAccessMask;
134 vk::PipelineStageFlags srcStageMask, dstStageMask;
136 // TODO: add other transitions
139 case vk::ImageLayout::eUndefined:
141 srcStageMask = vk::PipelineStageFlagBits::eTopOfPipe;
144 case vk::ImageLayout::ePresentSrcKHR:
146 srcStageMask = vk::PipelineStageFlagBits::eBottomOfPipe;
147 srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
150 case vk::ImageLayout::eColorAttachmentOptimal:
152 srcStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eColorAttachmentOutput;
153 srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
156 case vk::ImageLayout::eGeneral:
157 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
158 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
159 case vk::ImageLayout::eShaderReadOnlyOptimal:
160 case vk::ImageLayout::eTransferSrcOptimal:
161 case vk::ImageLayout::eTransferDstOptimal:
162 case vk::ImageLayout::ePreinitialized:
163 case vk::ImageLayout::eSharedPresentKHR:
170 case vk::ImageLayout::eColorAttachmentOptimal:
172 dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eFragmentShader;
173 dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eHostWrite;
176 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
178 dstStageMask = vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eEarlyFragmentTests;
179 dstAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
182 case vk::ImageLayout::ePresentSrcKHR:
184 dstStageMask = vk::PipelineStageFlagBits::eBottomOfPipe;
185 dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eMemoryRead;
187 case vk::ImageLayout::eGeneral:
188 case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
189 case vk::ImageLayout::eShaderReadOnlyOptimal:
190 case vk::ImageLayout::eTransferSrcOptimal:
191 case vk::ImageLayout::eTransferDstOptimal:
192 case vk::ImageLayout::ePreinitialized:
193 case vk::ImageLayout::eUndefined:
194 case vk::ImageLayout::eSharedPresentKHR:
201 RecordImageLayoutTransition(image, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask,
202 oldLayout, newLayout, aspectMask);
205 #pragma GCC diagnostic push
206 #pragma GCC diagnostic ignored "-Wframe-larger-than="
207 void RecordImageLayoutTransition(vk::Image image, vk::AccessFlags srcAccessMask,
208 vk::AccessFlags dstAccessMask, vk::PipelineStageFlags srcStageMask,
209 vk::PipelineStageFlags dstStageMask, vk::ImageLayout oldLayout,
210 vk::ImageLayout newLayout, vk::ImageAspectFlags aspectMask)
212 vk::ImageSubresourceRange subres;
213 subres.setLayerCount(1).setBaseMipLevel(0).setBaseArrayLayer(0).setLevelCount(1).setAspectMask(aspectMask);
216 auto barrier = vk::ImageMemoryBarrier{};
219 .setSubresourceRange(subres)
220 .setSrcAccessMask(srcAccessMask)
221 .setDstAccessMask(dstAccessMask)
222 .setOldLayout(oldLayout)
223 .setNewLayout(newLayout);
225 // todo: implement barriers batching
226 mCommandBuffer.pipelineBarrier(srcStageMask, dstStageMask, vk::DependencyFlags{}, nullptr, nullptr, barrier);
228 #pragma GCC diagnostic pop
230 /** Push wait semaphores */
231 void PushWaitSemaphores(const std::vector< vk::Semaphore >& semaphores,
232 const std::vector< vk::PipelineStageFlags >& stages)
234 mWaitSemaphores = semaphores;
235 mWaitStages = stages;
238 /** Push signal semaphores */
239 void PushSignalSemaphores(const std::vector< vk::Semaphore >& semaphores)
241 mSignalSemaphores = semaphores;
244 // TODO: handles should be synchronized
245 void BindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, std::vector<Handle<Buffer>> buffers,
246 const vk::DeviceSize *pOffsets)
248 // update list of used resources and create an array of VkBuffers
249 std::vector<vk::Buffer> vkBuffers;
250 vkBuffers.reserve( buffers.size() );
251 for( auto&& buffer : buffers )
253 vkBuffers.emplace_back( buffer->GetVkBuffer() );
254 PushResource(buffer);
257 mCommandBuffer.bindVertexBuffers( firstBinding, bindingCount, vkBuffers.data(), pOffsets);
260 void BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType)
263 assert ( (buffer->GetUsage() & vk::BufferUsageFlagBits::eIndexBuffer) && "The buffer used as index buffer has wrong usage flags!" );
265 PushResource( buffer );
266 mCommandBuffer.bindIndexBuffer( buffer->GetVkBuffer(), offset, indexType );
269 void BindGraphicsPipeline( Handle<Pipeline> pipeline )
271 PushResource( pipeline );
272 mCurrentPipeline = pipeline;
273 mCommandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipeline() );
276 void BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
277 Handle<Pipeline> pipeline, uint32_t firstSet, uint32_t descriptorSetCount )
280 PushResource( pipeline );
281 std::vector<vk::DescriptorSet> vkSets;
282 vkSets.reserve( descriptorSets.size() );
283 for( auto&& set : descriptorSets )
285 vkSets.emplace_back( set->GetVkDescriptorSet() );
289 // TODO: support dynamic offsets
290 mCommandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, pipeline->GetVkPipelineLayout(),
291 firstSet, descriptorSetCount, vkSets.data(), 0, nullptr );
294 void Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
296 mCommandBuffer.draw( vertexCount, instanceCount, firstVertex, firstInstance );
299 void DrawIndexed( uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
301 mCommandBuffer.drawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
304 const std::vector< Handle<VkManaged>> GetResources() const
310 void BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
312 auto& surface = mGraphics.GetSurface( framebufferId );
313 auto renderPass = surface.GetRenderPass();
314 auto frameBuffer = surface.GetFramebuffer( bufferIndex );
315 auto clearValues = surface.GetClearValues();
317 auto info = vk::RenderPassBeginInfo{};
318 info.setFramebuffer( frameBuffer );
319 info.setRenderPass( renderPass );
320 info.setClearValueCount( U32(clearValues.size()) );
321 info.setPClearValues( clearValues.data() );
322 info.setRenderArea( vk::Rect2D( { 0,0 }, surface.GetSize() ) );
324 mCurrentRenderPass = renderPass;
325 mCommandBuffer.beginRenderPass( info, vk::SubpassContents::eInline );
328 void BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
330 mCurrentRenderPass = renderPassBeginInfo.renderPass;
331 mCommandBuffer.beginRenderPass( renderPassBeginInfo, subpassContents );
336 mCurrentRenderPass = nullptr;
337 mCommandBuffer.endRenderPass();
340 void ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
342 auto vkBuffers = std::vector<vk::CommandBuffer>{};
343 vkBuffers.reserve( commandBuffers.size() );
344 for( auto&& buf : commandBuffers )
346 vkBuffers.emplace_back( buf->GetVkCommandBuffer() );
350 mCommandBuffer.executeCommands( vkBuffers );
354 CommandPool& mOwnerCommandPool;
355 vk::CommandBufferAllocateInfo mAllocateInfo {};
357 vk::CommandBuffer mCommandBuffer {};
359 // semaphores per command buffer
360 std::vector< vk::Semaphore > mSignalSemaphores {};
361 std::vector< vk::Semaphore > mWaitSemaphores {};
362 std::vector< vk::PipelineStageFlags > mWaitStages {};
364 std::vector< Handle<VkManaged>> mResources; // used resources
366 PipelineRef mCurrentPipeline;
368 vk::RenderPass mCurrentRenderPass;
370 bool mRecording { false };
375 * Class: CommandBuffer
379 CommandBuffer::CommandBuffer( CommandPool& commandPool, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer vkCommandBuffer )
381 mImpl = MakeUnique<Impl>( commandPool, allocateInfo, vkCommandBuffer );
384 CommandBuffer::~CommandBuffer()
388 /** Begin recording */
389 void CommandBuffer::Begin(vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo)
391 mImpl->Begin( usageFlags, inheritanceInfo );
394 /** Finish recording */
395 void CommandBuffer::End()
400 /** Reset command buffer */
401 void CommandBuffer::Reset()
406 /** Free command buffer */
407 void CommandBuffer::Free()
412 /** Records image layout transition barrier for one image */
413 void CommandBuffer::ImageLayoutTransition(vk::Image image,
414 vk::ImageLayout oldLayout,
415 vk::ImageLayout newLayout,
416 vk::ImageAspectFlags aspectMask)
418 mImpl->ImageLayoutTransition( image, oldLayout, newLayout, aspectMask );
421 void CommandBuffer::RecordImageLayoutTransition(vk::Image image, vk::AccessFlags srcAccessMask,
422 vk::AccessFlags dstAccessMask, vk::PipelineStageFlags srcStageMask,
423 vk::PipelineStageFlags dstStageMask, vk::ImageLayout oldLayout,
424 vk::ImageLayout newLayout, vk::ImageAspectFlags aspectMask)
426 mImpl->RecordImageLayoutTransition( image, srcAccessMask, dstAccessMask,srcStageMask, dstStageMask, oldLayout, newLayout, aspectMask );
429 /** Push wait semaphores */
430 void CommandBuffer::PushWaitSemaphores(const std::vector< vk::Semaphore >& semaphores,
431 const std::vector< vk::PipelineStageFlags >& stages)
433 mImpl->PushWaitSemaphores( semaphores, stages );
436 /** Push signal semaphores */
437 void CommandBuffer::PushSignalSemaphores(const std::vector< vk::Semaphore >& semaphores)
439 mImpl->PushSignalSemaphores( semaphores );
442 const std::vector< vk::Semaphore >& CommandBuffer::GetSignalSemaphores() const
444 return mImpl->mSignalSemaphores;
447 const std::vector< vk::Semaphore >& CommandBuffer::GetSWaitSemaphores() const
449 return mImpl->mWaitSemaphores;
452 const std::vector< vk::PipelineStageFlags >& CommandBuffer::GetWaitSemaphoreStages() const
454 return mImpl->mWaitStages;
457 vk::CommandBuffer CommandBuffer::GetVkCommandBuffer() const
459 return mImpl->mCommandBuffer;
462 bool CommandBuffer::IsPrimary() const
464 return mImpl->mAllocateInfo.level == vk::CommandBufferLevel::ePrimary;
467 void CommandBuffer::BindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, std::vector<Handle<Buffer>> buffers,
468 const vk::DeviceSize *pOffsets)
470 mImpl->BindVertexBuffers( firstBinding, bindingCount, buffers, pOffsets );
473 void CommandBuffer::BindIndexBuffer( BufferRef buffer, uint32_t offset, vk::IndexType indexType)
475 mImpl->BindIndexBuffer( buffer, offset, indexType );
478 void CommandBuffer::BindVertexBuffer(uint32_t binding, Dali::Graphics::Vulkan::Handle<Buffer> buffer, vk::DeviceSize offset )
480 mImpl->BindVertexBuffers( binding, 1, std::vector<Handle<Buffer>>({ buffer }), &offset );
483 void CommandBuffer::BindGraphicsPipeline( Handle<Pipeline> pipeline )
485 mImpl->BindGraphicsPipeline( pipeline );
488 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets,
489 Handle<Pipeline> pipeline, uint32_t firstSet, uint32_t descriptorSetCount )
491 mImpl->BindDescriptorSets( descriptorSets, pipeline, firstSet, descriptorSetCount );
494 void CommandBuffer::BindDescriptorSets( std::vector<Dali::Graphics::Vulkan::Handle<DescriptorSet>> descriptorSets, uint32_t firstSet )
496 mImpl->BindDescriptorSets( descriptorSets, mImpl->mCurrentPipeline, 0, static_cast<uint32_t>(descriptorSets.size()) );
499 void CommandBuffer::Draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance )
501 mImpl->Draw( vertexCount, instanceCount, firstVertex, firstInstance );
504 void CommandBuffer::DrawIndexed( uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance )
506 mImpl->DrawIndexed( indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );
509 void CommandBuffer::BeginRenderPass( FBID framebufferId, uint32_t bufferIndex )
511 mImpl->BeginRenderPass( framebufferId, bufferIndex );
514 void CommandBuffer::BeginRenderPass( vk::RenderPassBeginInfo renderPassBeginInfo, vk::SubpassContents subpassContents )
516 mImpl->BeginRenderPass( renderPassBeginInfo, subpassContents );
519 void CommandBuffer::EndRenderPass()
521 mImpl->EndRenderPass();
524 void CommandBuffer::ExecuteCommands( std::vector<Dali::Graphics::Vulkan::Handle<CommandBuffer>> commandBuffers )
526 mImpl->ExecuteCommands( commandBuffers );
529 } // namespace Vulkan
530 } // namespace Graphics