/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #pragma once // @lint-ignore-every CLANGTIDY facebook-hte-BadMemberName #include #include #include #include #include #include #include namespace vkcompute { namespace vkapi { class CommandBuffer final { public: explicit CommandBuffer(VkCommandBuffer, const VkCommandBufferUsageFlags); CommandBuffer(const CommandBuffer&) = delete; CommandBuffer& operator=(const CommandBuffer&) = delete; CommandBuffer(CommandBuffer&&) noexcept; CommandBuffer& operator=(CommandBuffer&&) noexcept; ~CommandBuffer() = default; // The lifecycle of a command buffer is as follows: enum State { INVALID, // Used to indicate the command buffer is moved from NEW, // Set during constructor RECORDING, // Set during call to begin() and dispatch() PIPELINE_BOUND, // Set during call to bind_pipeline() DESCRIPTORS_BOUND, // Set during call to bind_descriptors() BARRIERS_INSERTED, // Set during call to insert_barrier() READY, // Set during call to end() SUBMITTED, // Set during call to get_submit_handle() }; struct Bound { VkPipeline pipeline; VkPipelineLayout pipeline_layout; utils::uvec3 local_workgroup_size; VkDescriptorSet descriptors; explicit Bound() : pipeline{VK_NULL_HANDLE}, pipeline_layout{VK_NULL_HANDLE}, local_workgroup_size{0u, 0u, 0u}, descriptors{VK_NULL_HANDLE} {} inline void reset() { pipeline = VK_NULL_HANDLE; pipeline_layout = VK_NULL_HANDLE; local_workgroup_size = {0u, 0u, 0u}; descriptors = VK_NULL_HANDLE; } }; private: VkCommandBuffer handle_; VkCommandBufferUsageFlags flags_; State state_; Bound bound_; public: inline bool is_reusable() { return !(flags_ & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); } inline void invalidate() { handle_ = VK_NULL_HANDLE; bound_.reset(); } void begin(); void end(); void bind_pipeline(VkPipeline, VkPipelineLayout, const utils::uvec3); void bind_descriptors(VkDescriptorSet); void insert_barrier(PipelineBarrier& pipeline_barrier); void dispatch(const utils::uvec3&); void blit(vkapi::VulkanImage& src, vkapi::VulkanImage& dst); void write_timestamp(VkQueryPool, const uint32_t) const; void reset_querypool(VkQueryPool, const uint32_t, const uint32_t) const; VkCommandBuffer get_submit_handle(const bool final_use = false); inline operator bool() const { return handle_ != VK_NULL_HANDLE; } }; struct CommandPoolConfig final { uint32_t cmd_pool_initial_size; uint32_t cmd_pool_batch_size; }; class CommandPool final { public: explicit CommandPool(VkDevice, const uint32_t, const CommandPoolConfig&); CommandPool(const CommandPool&) = delete; CommandPool& operator=(const CommandPool&) = delete; CommandPool(CommandPool&&) = delete; CommandPool& operator=(CommandPool&&) = delete; ~CommandPool(); private: VkDevice device_; uint32_t queue_family_idx_; VkCommandPool pool_; CommandPoolConfig config_; // New Buffers std::mutex mutex_; std::vector buffers_; size_t in_use_; public: CommandBuffer get_new_cmd(bool reusable = false); void flush(); private: void allocate_new_batch(const uint32_t); }; } // namespace vkapi } // namespace vkcompute