/* * 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 namespace vkcompute { namespace vkapi { // // A Vulkan Adapter represents a logical device and all its properties. It // manages all relevant properties of the underlying physical device, a // handle to the logical device, and a number of compute queues available to // the device. It is primarily responsible for managing the VkDevice handle // which points to the logical device object on the GPU. // // This class is primarily used by the Runtime class, which holds one Adapter // instance for each physical device visible to the VkInstance. Upon // construction, this class will populate the physical device properties, but // will not create the logical device until specifically requested via the // init_device() function. // // init_device() will create the logical device and obtain the VkDevice handle // for it. It will also create a number of compute queues up to the amount // requested when the Adapter instance was constructed. // // Contexts (which represent one thread of execution) will request a compute // queue from an Adapter. The Adapter will then select a compute queue to // assign to the Context, attempting to balance load between all available // queues. This will allow different Contexts (which typically execute on // separate threads) to run concurrently. // #define NUM_QUEUE_MUTEXES 4 class Adapter final { public: explicit Adapter( VkInstance instance, PhysicalDevice physical_device, const uint32_t num_queues, const std::string& cache_data_path); Adapter(const Adapter&) = delete; Adapter& operator=(const Adapter&) = delete; Adapter(Adapter&&) = delete; Adapter& operator=(Adapter&&) = delete; ~Adapter() = default; struct Queue { uint32_t family_index; uint32_t queue_index; VkQueueFlags capabilities; VkQueue handle; }; private: // Use a mutex to manage queue usage info since // it can be accessed from multiple threads std::mutex queue_usage_mutex_; // Physical Device Info PhysicalDevice physical_device_; // Queue Management std::vector queues_; std::vector queue_usage_; std::array queue_mutexes_; // Handles VkInstance instance_; DeviceHandle device_; // Device-level resource caches ShaderLayoutCache shader_layout_cache_; ShaderCache shader_cache_; PipelineLayoutCache pipeline_layout_cache_; ComputePipelineCache compute_pipeline_cache_; // Memory Management SamplerCache sampler_cache_; Allocator vma_; // Miscellaneous bool linear_tiling_3d_enabled_; public: // Physical Device metadata inline VkPhysicalDevice physical_handle() const { return physical_device_.handle; } inline VkDevice device_handle() const { return device_.handle; } inline bool has_unified_memory() const { return physical_device_.has_unified_memory; } inline uint32_t num_compute_queues() const { return physical_device_.num_compute_queues; } inline bool timestamp_compute_and_graphics() const { return physical_device_.has_timestamps; } inline float timestamp_period() const { return physical_device_.timestamp_period; } // Queue Management Queue request_queue(); void return_queue(Queue&); // Caches inline ShaderLayoutCache& shader_layout_cache() { return shader_layout_cache_; } inline ShaderCache& shader_cache() { return shader_cache_; } inline PipelineLayoutCache& pipeline_layout_cache() { return pipeline_layout_cache_; } inline ComputePipelineCache& compute_pipeline_cache() { return compute_pipeline_cache_; } // Memory Allocation inline SamplerCache& sampler_cache() { return sampler_cache_; } inline Allocator& vma() { return vma_; } inline bool linear_tiling_3d_enabled() const { return linear_tiling_3d_enabled_; } // Physical Device Features inline bool supports_16bit_storage_buffers() { #ifdef VK_KHR_16bit_storage return physical_device_.shader_16bit_storage.storageBuffer16BitAccess == VK_TRUE; #else return false; #endif /* VK_KHR_16bit_storage */ } inline bool supports_8bit_storage_buffers() { #ifdef VK_KHR_8bit_storage return physical_device_.shader_8bit_storage.storageBuffer8BitAccess == VK_TRUE; #else return false; #endif /* VK_KHR_8bit_storage */ } inline bool supports_float16_shader_types() { #ifdef VK_KHR_shader_float16_int8 return physical_device_.shader_float16_int8_types.shaderFloat16 == VK_TRUE; #else return false; #endif /* VK_KHR_shader_float16_int8 */ } inline bool supports_int8_shader_types() { #ifdef VK_KHR_shader_float16_int8 return physical_device_.shader_float16_int8_types.shaderInt8 == VK_TRUE; #else return false; #endif /* VK_KHR_shader_float16_int8 */ } inline bool supports_int16_shader_types() { return physical_device_.supports_int16_shader_types; } inline bool has_full_float16_buffers_support() { return supports_16bit_storage_buffers() && supports_float16_shader_types(); } inline bool has_full_int8_buffers_support() { return supports_8bit_storage_buffers() && supports_int8_shader_types(); } // Command Buffer Submission void submit_cmd(const Queue&, VkCommandBuffer, VkFence fence = VK_NULL_HANDLE); std::string stringize() const; friend std::ostream& operator<<(std::ostream&, const Adapter&); }; } // namespace vkapi } // namespace vkcompute