// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "GPUDeviceVulkan.h" #include "Engine/Core/Types/BaseTypes.h" #include "Engine/Core/Collections/Array.h" #if GRAPHICS_API_VULKAN class GPUDeviceVulkan; class CmdBufferPoolVulkan; class QueueVulkan; class DescriptorPoolSetContainerVulkan; /// /// Implementation of the command buffer for the Vulkan backend. /// class CmdBufferVulkan { friend QueueVulkan; public: enum class State { ReadyForBegin, IsInsideBegin, IsInsideRenderPass, HasEnded, Submitted, }; private: GPUDeviceVulkan* _device; VkCommandBuffer _commandBuffer; State _state; Array _waitFlags; Array _waitSemaphores; Array _submittedWaitSemaphores; FenceVulkan* _fence; #if GPU_ALLOW_PROFILE_EVENTS int32 _eventsBegin = 0; #endif // The latest value when command buffer was submitted. volatile uint64 _submittedFenceCounter; // The latest value passed after the fence was signaled. volatile uint64 _fenceSignaledCounter; CmdBufferPoolVulkan* _commandBufferPool; DescriptorPoolSetContainerVulkan* _descriptorPoolSetContainer = nullptr; public: CmdBufferVulkan(GPUDeviceVulkan* device, CmdBufferPoolVulkan* pool); ~CmdBufferVulkan(); public: CmdBufferPoolVulkan* GetOwner() const { return _commandBufferPool; } State GetState() const { return _state; } FenceVulkan* GetFence() const { return _fence; } inline bool IsInsideRenderPass() const { return _state == State::IsInsideRenderPass; } inline bool IsOutsideRenderPass() const { return _state == State::IsInsideBegin; } inline bool HasBegun() const { return _state == State::IsInsideBegin || _state == State::IsInsideRenderPass; } inline bool HasEnded() const { return _state == State::HasEnded; } inline bool IsSubmitted() const { return _state == State::Submitted; } inline VkCommandBuffer GetHandle() const { return _commandBuffer; } inline volatile uint64 GetFenceSignaledCounter() const { return _fenceSignaledCounter; } inline volatile uint64 GetSubmittedFenceCounter() const { return _submittedFenceCounter; } public: void AddWaitSemaphore(VkPipelineStageFlags waitFlags, SemaphoreVulkan* waitSemaphore); void Begin(); void End(); void BeginRenderPass(RenderPassVulkan* renderPass, FramebufferVulkan* framebuffer, uint32 clearValueCount, VkClearValue* clearValues); void EndRenderPass(); DescriptorPoolSetContainerVulkan* GetDescriptorPoolSet() const { return _descriptorPoolSetContainer; } void AcquirePoolSet(); #if GPU_ALLOW_PROFILE_EVENTS void BeginEvent(const Char* name); void EndEvent(); #endif void RefreshFenceStatus(); }; class CmdBufferPoolVulkan { friend class CmdBufferManagerVulkan; private: GPUDeviceVulkan* _device; VkCommandPool _handle; Array _cmdBuffers; CmdBufferVulkan* Create(); void Create(uint32 queueFamilyIndex); public: CmdBufferPoolVulkan(GPUDeviceVulkan* device); ~CmdBufferPoolVulkan(); public: inline VkCommandPool GetHandle() const { ASSERT(_handle != VK_NULL_HANDLE); return _handle; } void RefreshFenceStatus(CmdBufferVulkan* skipCmdBuffer = nullptr); }; class CmdBufferManagerVulkan { private: GPUDeviceVulkan* _device; CmdBufferPoolVulkan _pool; QueueVulkan* _queue; CmdBufferVulkan* _activeCmdBuffer; Array _queriesInProgress; public: CmdBufferManagerVulkan(GPUDeviceVulkan* device, GPUContextVulkan* context); public: FORCE_INLINE VkCommandPool GetHandle() const { return _pool.GetHandle(); } FORCE_INLINE CmdBufferVulkan* GetActiveCmdBuffer() const { return _activeCmdBuffer; } FORCE_INLINE bool HasPendingActiveCmdBuffer() const { return _activeCmdBuffer != nullptr; } FORCE_INLINE bool HasQueriesInProgress() const { return _queriesInProgress.Count() != 0; } CmdBufferVulkan* GetCmdBuffer() { if (!_activeCmdBuffer) PrepareForNewActiveCommandBuffer(); return _activeCmdBuffer; } public: void SubmitActiveCmdBuffer(SemaphoreVulkan* signalSemaphore = nullptr); void WaitForCmdBuffer(CmdBufferVulkan* cmdBuffer, float timeInSecondsToWait = 1.0f); void RefreshFenceStatus(CmdBufferVulkan* skipCmdBuffer = nullptr) { _pool.RefreshFenceStatus(skipCmdBuffer); } void PrepareForNewActiveCommandBuffer(); void OnQueryBegin(GPUTimerQueryVulkan* query); void OnQueryEnd(GPUTimerQueryVulkan* query); }; #endif