1 /*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 // @lint-ignore-every CLANGTIDY clang-diagnostic-missing-field-initializers
10
11 #include <executorch/backends/vulkan/runtime/vk_api/Device.h>
12
13 #include <executorch/backends/vulkan/runtime/vk_api/Exception.h>
14
15 #include <bitset>
16 #include <cstring>
17
18 namespace vkcompute {
19 namespace vkapi {
20
PhysicalDevice(VkPhysicalDevice physical_device_handle)21 PhysicalDevice::PhysicalDevice(VkPhysicalDevice physical_device_handle)
22 : handle(physical_device_handle),
23 properties{},
24 memory_properties{},
25 #ifdef VK_KHR_16bit_storage
26 shader_16bit_storage{
27 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES},
28 #endif /* VK_KHR_16bit_storage */
29 #ifdef VK_KHR_8bit_storage
30 shader_8bit_storage{
31 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES},
32 #endif /* VK_KHR_8bit_storage */
33 #ifdef VK_KHR_shader_float16_int8
34 shader_float16_int8_types{
35 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR},
36 #endif /* VK_KHR_shader_float16_int8 */
37 extension_features{nullptr},
38 queue_families{},
39 num_compute_queues(0),
40 supports_int16_shader_types(false),
41 has_unified_memory(false),
42 has_timestamps(properties.limits.timestampComputeAndGraphics),
43 timestamp_period(properties.limits.timestampPeriod) {
44 // Extract physical device properties
45 vkGetPhysicalDeviceProperties(handle, &properties);
46 vkGetPhysicalDeviceMemoryProperties(handle, &memory_properties);
47
48 VkPhysicalDeviceFeatures2 features2{
49 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
50
51 // Create linked list to query availability of extensions
52
53 #ifdef VK_KHR_16bit_storage
54 extension_features = &shader_16bit_storage;
55 features2.pNext = &shader_16bit_storage;
56 #elif defined(VK_KHR_8bit_storage)
57 extension_features = &shader_8bit_storage;
58 features2.pNext = &shader_8bit_storage;
59 #elif defined(VK_KHR_shader_float16_int8)
60 extension_features = &shader_float16_int8_types;
61 features2.pNext = &shader_float16_int8_types;
62 #endif /* VK_KHR_16bit_storage */
63
64 #if defined(VK_KHR_16bit_storage) && defined(VK_KHR_8bit_storage)
65 shader_16bit_storage.pNext = &shader_8bit_storage;
66 #elif defined(VK_KHR_16bit_storage) && defined(VK_KHR_shader_float16_int8)
67 shader_16bit_storage.pNext = &shader_float16_int8_types;
68 #elif defined(VK_KHR_16bit_storage)
69 shader_16bit_storage.pNext = nullptr;
70 #endif
71
72 #if defined(VK_KHR_8bit_storage) && defined(VK_KHR_shader_float16_int8)
73 shader_8bit_storage.pNext = &shader_float16_int8_types;
74 #elif defined(VK_KHR_8bit_storage)
75 shader_8bit_storage.pNext = nullptr;
76 #endif
77
78 #ifdef VK_KHR_shader_float16_int8
79 shader_float16_int8_types.pNext = nullptr;
80 #endif
81
82 vkGetPhysicalDeviceFeatures2(handle, &features2);
83
84 if (features2.features.shaderInt16 == VK_TRUE) {
85 supports_int16_shader_types = true;
86 }
87
88 // Check if there are any memory types have both the HOST_VISIBLE and the
89 // DEVICE_LOCAL property flags
90 const VkMemoryPropertyFlags unified_memory_flags =
91 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
92 for (size_t i = 0; i < memory_properties.memoryTypeCount; ++i) {
93 if (memory_properties.memoryTypes[i].propertyFlags | unified_memory_flags) {
94 has_unified_memory = true;
95 break;
96 }
97 }
98
99 uint32_t queue_family_count = 0;
100 vkGetPhysicalDeviceQueueFamilyProperties(
101 handle, &queue_family_count, nullptr);
102
103 queue_families.resize(queue_family_count);
104 vkGetPhysicalDeviceQueueFamilyProperties(
105 handle, &queue_family_count, queue_families.data());
106
107 // Find the total number of compute queues
108 for (const VkQueueFamilyProperties& p : queue_families) {
109 // Check if this family has compute capability
110 if (p.queueFlags & VK_QUEUE_COMPUTE_BIT) {
111 num_compute_queues += p.queueCount;
112 }
113 }
114 }
115
116 //
117 // DeviceHandle
118 //
119
DeviceHandle(VkDevice device)120 DeviceHandle::DeviceHandle(VkDevice device) : handle(device) {}
121
~DeviceHandle()122 DeviceHandle::~DeviceHandle() {
123 if (handle == VK_NULL_HANDLE) {
124 return;
125 }
126 vkDestroyDevice(handle, nullptr);
127 }
128
129 //
130 // Utils
131 //
132
find_requested_device_extensions(VkPhysicalDevice physical_device,std::vector<const char * > & enabled_extensions,const std::vector<const char * > & requested_extensions)133 void find_requested_device_extensions(
134 VkPhysicalDevice physical_device,
135 std::vector<const char*>& enabled_extensions,
136 const std::vector<const char*>& requested_extensions) {
137 uint32_t device_extension_properties_count = 0;
138 VK_CHECK(vkEnumerateDeviceExtensionProperties(
139 physical_device, nullptr, &device_extension_properties_count, nullptr));
140 std::vector<VkExtensionProperties> device_extension_properties(
141 device_extension_properties_count);
142 VK_CHECK(vkEnumerateDeviceExtensionProperties(
143 physical_device,
144 nullptr,
145 &device_extension_properties_count,
146 device_extension_properties.data()));
147
148 std::vector<const char*> enabled_device_extensions;
149
150 for (const auto& requested_extension : requested_extensions) {
151 for (const auto& extension : device_extension_properties) {
152 if (strcmp(requested_extension, extension.extensionName) == 0) {
153 enabled_extensions.push_back(requested_extension);
154 break;
155 }
156 }
157 }
158 }
159
get_device_type_str(const VkPhysicalDeviceType type)160 std::string get_device_type_str(const VkPhysicalDeviceType type) {
161 switch (type) {
162 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
163 return "INTEGRATED_GPU";
164 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
165 return "DISCRETE_GPU";
166 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
167 return "VIRTUAL_GPU";
168 case VK_PHYSICAL_DEVICE_TYPE_CPU:
169 return "CPU";
170 default:
171 return "UNKNOWN";
172 }
173 }
174
get_memory_properties_str(const VkMemoryPropertyFlags flags)175 std::string get_memory_properties_str(const VkMemoryPropertyFlags flags) {
176 std::bitset<10> values(flags);
177 std::stringstream ss("|");
178 if (values[0]) {
179 ss << " DEVICE_LOCAL |";
180 }
181 if (values[1]) {
182 ss << " HOST_VISIBLE |";
183 }
184 if (values[2]) {
185 ss << " HOST_COHERENT |";
186 }
187 if (values[3]) {
188 ss << " HOST_CACHED |";
189 }
190 if (values[4]) {
191 ss << " LAZILY_ALLOCATED |";
192 }
193
194 return ss.str();
195 }
196
get_queue_family_properties_str(const VkQueueFlags flags)197 std::string get_queue_family_properties_str(const VkQueueFlags flags) {
198 std::bitset<10> values(flags);
199 std::stringstream ss("|");
200 if (values[0]) {
201 ss << " GRAPHICS |";
202 }
203 if (values[1]) {
204 ss << " COMPUTE |";
205 }
206 if (values[2]) {
207 ss << " TRANSFER |";
208 }
209
210 return ss.str();
211 }
212
213 } // namespace vkapi
214 } // namespace vkcompute
215