1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "create_functions_vk.h"
17
18 #include <algorithm>
19 #include <cinttypes>
20 #include <cstring>
21 #include <vulkan/vulkan_core.h>
22
23 #include <base/containers/vector.h>
24 #include <render/intf_render_context.h>
25 #include <render/namespace.h>
26
27 #include "platform_vk.h"
28 #include "util/log.h"
29 #include "vulkan/device_vk.h"
30 #include "vulkan/validate_vk.h"
31
32 using namespace BASE_NS;
33
34 RENDER_BEGIN_NAMESPACE()
35 namespace {
36 constexpr const bool CORE_ENABLE_VULKAN_PHYSICAL_DEVICE_PRINT = true;
37
38 #define SPLIT_VK_VERSION(version) VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version)
39
GetInstanceApiVersion()40 uint32_t GetInstanceApiVersion()
41 {
42 uint32_t apiVersion = VK_VERSION_1_0;
43 auto vkEnumerateInstanceVersionFunc = (PFN_vkEnumerateInstanceVersion) reinterpret_cast<void*>(
44 vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceVersion"));
45 if (vkEnumerateInstanceVersionFunc) {
46 const VkResult result = vkEnumerateInstanceVersionFunc(&apiVersion);
47 if (result != VK_SUCCESS) {
48 apiVersion = VK_VERSION_1_0;
49 PLUGIN_LOG_D("vkEnumerateInstanceVersion error: %i", result);
50 }
51 }
52 apiVersion = VK_MAKE_VERSION(VK_VERSION_MAJOR(apiVersion), VK_VERSION_MINOR(apiVersion), 0);
53 PLUGIN_LOG_D("enumerated api version for instance creation %u.%u", VK_VERSION_MAJOR(apiVersion),
54 VK_VERSION_MINOR(apiVersion));
55 return apiVersion;
56 }
57
LogPhysicalDeviceProperties(const VkPhysicalDeviceProperties & physicalDeviceProperties)58 inline void LogPhysicalDeviceProperties(const VkPhysicalDeviceProperties& physicalDeviceProperties)
59 {
60 PLUGIN_LOG_D("api version: %u.%u.%u", SPLIT_VK_VERSION(physicalDeviceProperties.apiVersion));
61 PLUGIN_LOG_D("driver version: %u.%u.%u", SPLIT_VK_VERSION(physicalDeviceProperties.driverVersion));
62 PLUGIN_LOG_D("vendor id: %x", physicalDeviceProperties.vendorID);
63 PLUGIN_LOG_D("device id: %x", physicalDeviceProperties.deviceID);
64 PLUGIN_LOG_D("device name: %s", physicalDeviceProperties.deviceName);
65 PLUGIN_LOG_D("device type: %d", physicalDeviceProperties.deviceType);
66 PLUGIN_LOG_D("timestampPeriod: %f", physicalDeviceProperties.limits.timestampPeriod);
67 }
68
LogQueueFamilyProperties(VkInstance instance,VkPhysicalDevice physicalDevice,const vector<VkQueueFamilyProperties> & queueFamilyProperties)69 inline void LogQueueFamilyProperties(
70 VkInstance instance, VkPhysicalDevice physicalDevice, const vector<VkQueueFamilyProperties>& queueFamilyProperties)
71 {
72 PLUGIN_LOG_D("queue count: %zu", queueFamilyProperties.size());
73 for (uint32_t idx = 0; idx < queueFamilyProperties.size(); ++idx) {
74 const bool canPresent = CanDevicePresent(instance, physicalDevice, idx);
75 PLUGIN_UNUSED(canPresent);
76 PLUGIN_LOG_D("queue flags: %x", queueFamilyProperties[idx].queueFlags);
77 PLUGIN_LOG_D("queue timestampValitBits: %x", queueFamilyProperties[idx].timestampValidBits);
78 PLUGIN_LOG_D("queue can present: %d", canPresent);
79 }
80 }
81
82 #ifndef NDEBUG
GetMemoryPropertyFlagsStr(const VkMemoryType memoryType)83 string GetMemoryPropertyFlagsStr(const VkMemoryType memoryType)
84 {
85 const uint32_t flags = memoryType.propertyFlags;
86 string flagsStr;
87 if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
88 flagsStr += "VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ";
89 }
90 if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
91 flagsStr += "VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ";
92 }
93 if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
94 flagsStr += "VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ";
95 }
96 if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
97 flagsStr += "VK_MEMORY_PROPERTY_HOST_CACHED_BIT ";
98 }
99 if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
100 flagsStr += "VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ";
101 }
102 if (flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) {
103 flagsStr += "VK_MEMORY_PROPERTY_PROTECTED_BIT ";
104 }
105 return flagsStr;
106 }
107
LogPhysicalDeviceMemoryProperties(const VkPhysicalDeviceMemoryProperties & physicalDeviceMemoryProperties)108 void LogPhysicalDeviceMemoryProperties(const VkPhysicalDeviceMemoryProperties& physicalDeviceMemoryProperties)
109 {
110 PLUGIN_LOG_D("physical device memory properties (for memory property type count %u ): ",
111 physicalDeviceMemoryProperties.memoryTypeCount);
112 for (uint32_t idx = 0; idx < physicalDeviceMemoryProperties.memoryTypeCount; ++idx) {
113 const string flagsString = GetMemoryPropertyFlagsStr(physicalDeviceMemoryProperties.memoryTypes[idx]);
114 PLUGIN_LOG_D("%u: memory property flags: %s, (from heap of size: %" PRIu64 ")", idx, flagsString.c_str(),
115 physicalDeviceMemoryProperties.memoryHeaps[physicalDeviceMemoryProperties.memoryTypes[idx].heapIndex].size);
116 }
117 }
118 #endif
119
GetQueueFamilieProperties(VkPhysicalDevice physicalDevice)120 vector<VkQueueFamilyProperties> GetQueueFamilieProperties(VkPhysicalDevice physicalDevice)
121 {
122 if (!physicalDevice) {
123 PLUGIN_LOG_E("Invalid Vulkan physical device");
124 return {};
125 }
126
127 uint32_t queueFamilyPropertyCount = 0u;
128 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, // physicalDevice
129 &queueFamilyPropertyCount, // pQueueFamilyPropertyCount
130 nullptr); // pQueueFamilyProperties
131
132 vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyPropertyCount);
133 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, // physicalDevice
134 &queueFamilyPropertyCount, // pQueueFamilyPropertyCount
135 queueFamilyProperties.data()); // pQueueFamilyProperties
136
137 return queueFamilyProperties;
138 }
139
140 struct SuitableQueueVk {
141 uint32_t queueFamilyIndex { ~0u };
142 uint32_t queueCount { 0u };
143 };
144
FindSuitableQueue(const vector<VkQueueFamilyProperties> & queueFamilyProperties,const QueueProperties & queueProperties)145 SuitableQueueVk FindSuitableQueue(
146 const vector<VkQueueFamilyProperties>& queueFamilyProperties, const QueueProperties& queueProperties)
147 {
148 for (uint32_t idx = 0; idx < queueFamilyProperties.size(); ++idx) {
149 if (queueProperties.explicitFlags) {
150 if (queueFamilyProperties[idx].queueFlags != queueProperties.requiredFlags) {
151 continue;
152 }
153 } else {
154 if ((queueFamilyProperties[idx].queueFlags & queueProperties.requiredFlags) !=
155 queueProperties.requiredFlags) {
156 continue;
157 }
158 }
159
160 return { idx, queueFamilyProperties[idx].queueCount };
161 }
162 return {};
163 }
164 } // namespace
165
GetAvailableQueues(VkPhysicalDevice physicalDevice,const vector<QueueProperties> & queueProperties)166 vector<LowLevelQueueInfo> CreateFunctionsVk::GetAvailableQueues(
167 VkPhysicalDevice physicalDevice, const vector<QueueProperties>& queueProperties)
168 {
169 vector<LowLevelQueueInfo> availableQueues;
170 availableQueues.reserve(queueProperties.size());
171
172 const vector<VkQueueFamilyProperties> queueFamilyProperties = GetQueueFamilieProperties(physicalDevice);
173
174 for (const auto& ref : queueProperties) {
175 const SuitableQueueVk suitableQueue = FindSuitableQueue(queueFamilyProperties, ref);
176 if (suitableQueue.queueCount > 0) {
177 const uint32_t maxQueueCount = std::min(suitableQueue.queueCount, ref.count);
178 availableQueues.push_back(
179 LowLevelQueueInfo { ref.requiredFlags, suitableQueue.queueFamilyIndex, maxQueueCount, ref.priority });
180 }
181 }
182 return availableQueues;
183 }
184
GetInstanceExtensions()185 vector<VkExtensionProperties> GetInstanceExtensions()
186 {
187 uint32_t instanceExtensionPropertyCount = 0;
188 vkEnumerateInstanceExtensionProperties(nullptr, // pLayerName
189 &instanceExtensionPropertyCount, // propertyCount
190 nullptr); // pProperties
191 vector<VkExtensionProperties> instanceExtensions(instanceExtensionPropertyCount);
192 vkEnumerateInstanceExtensionProperties(nullptr, // pLayerName
193 &instanceExtensionPropertyCount, // propertyCount
194 instanceExtensions.data()); // pProperties
195 return instanceExtensions;
196 }
197
GetInstancLayers()198 vector<VkLayerProperties> GetInstancLayers()
199 {
200 uint32_t instanceLayerPropertyCount = 0;
201 vkEnumerateInstanceLayerProperties(&instanceLayerPropertyCount, // pPropertyCount
202 nullptr); // pProperties
203 vector<VkLayerProperties> instanceLayers(instanceLayerPropertyCount);
204 vkEnumerateInstanceLayerProperties(&instanceLayerPropertyCount, // pPropertyCount
205 instanceLayers.data()); // pProperties
206 return instanceLayers;
207 }
208
GetWrapper(VkInstance instance)209 InstanceWrapper CreateFunctionsVk::GetWrapper(VkInstance instance)
210 {
211 InstanceWrapper wrapper;
212 wrapper.instance = instance;
213
214 #if (!defined(NDEBUG) || RENDER_VULKAN_VALIDATION_ENABLED == 1)
215 vector<VkExtensionProperties> instanceExtensions = GetInstanceExtensions();
216
217 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
218 const char* debugExtension = nullptr;
219 #endif
220 for (const auto& ref : instanceExtensions) {
221 PLUGIN_LOG_V("%s", ref.extensionName);
222 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
223 if (strcmp(ref.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
224 wrapper.debugUtilsSupported = true;
225 debugExtension = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
226 } else if (!debugExtension && strcmp(ref.extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
227 wrapper.debugReportSupported = true;
228 debugExtension = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
229 }
230 #endif
231 }
232 #endif
233 const uint32_t apiVersion = GetInstanceApiVersion();
234 wrapper.apiMajor = VK_VERSION_MAJOR(apiVersion);
235 wrapper.apiMinor = VK_VERSION_MINOR(apiVersion);
236 return wrapper;
237 }
238
CreateInstance(const VersionInfo & engineInfo,const VersionInfo & appInfo)239 InstanceWrapper CreateFunctionsVk::CreateInstance(const VersionInfo& engineInfo, const VersionInfo& appInfo)
240 {
241 InstanceWrapper wrapper;
242
243 vector<VkExtensionProperties> instanceExtensions = GetInstanceExtensions();
244
245 // NOTE: check extensions...
246 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
247 const char* debugExtension = nullptr;
248 #endif
249 #if (!defined(NDEBUG) || RENDER_VULKAN_VALIDATION_ENABLED == 1)
250 PLUGIN_LOG_V("Vulkan: available extensions:");
251 for (const auto& ref : instanceExtensions) {
252 PLUGIN_LOG_V("%s", ref.extensionName);
253 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
254 if (strcmp(ref.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
255 wrapper.debugUtilsSupported = true;
256 debugExtension = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
257 } else if (!debugExtension && strcmp(ref.extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
258 wrapper.debugReportSupported = true;
259 debugExtension = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
260 }
261 #endif
262 }
263 #endif
264
265 vector<const char*> extensions = { VK_KHR_SURFACE_EXTENSION_NAME, GetPlatformSurfaceName() };
266 #ifdef __APPLE__
267 extensions.push_back("VK_KHR_portability_enumeration");
268 #endif
269 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
270 if (debugExtension) {
271 extensions.push_back(debugExtension);
272 }
273 #endif
274 if (!std::all_of(extensions.begin(), extensions.end(), [&instanceExtensions](auto const requiredExtension) {
275 const bool supported = std::any_of(instanceExtensions.begin(), instanceExtensions.end(),
276 [&requiredExtension](const auto& supportedExtension) {
277 return (std::strcmp(supportedExtension.extensionName, requiredExtension) == 0);
278 });
279 if (!supported) {
280 PLUGIN_LOG_E("some extensions are not supported! Extension name: %s", requiredExtension);
281 }
282 return supported;
283 })) {
284 }
285
286 vector<VkLayerProperties> instanceLayers = GetInstancLayers();
287 #if (!defined(NDEBUG) || RENDER_VULKAN_VALIDATION_ENABLED == 1)
288 PLUGIN_LOG_D("Vulkan: available layers:");
289 for (const auto& ref : instanceLayers) {
290 PLUGIN_LOG_D("%s", ref.layerName);
291 }
292 #endif
293
294 vector<const char*> layers = {
295 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
296 "VK_LAYER_KHRONOS_validation",
297 #endif
298 };
299 layers.erase(std::remove_if(layers.begin(), layers.end(),
300 [&instanceLayers](const char* requiredLayer) {
301 const bool supported = std::any_of(instanceLayers.begin(), instanceLayers.end(),
302 [&requiredLayer](const VkLayerProperties& supportedLayer) {
303 return (std::strcmp(supportedLayer.layerName, requiredLayer) == 0);
304 });
305 if (!supported) {
306 PLUGIN_LOG_E("some layers are not supported! Layer name: %s", requiredLayer);
307 }
308 return !supported;
309 }),
310 layers.cend());
311
312 const uint32_t apiVersion = GetInstanceApiVersion();
313 wrapper.apiMajor = VK_VERSION_MAJOR(apiVersion);
314 wrapper.apiMinor = VK_VERSION_MINOR(apiVersion);
315
316 const uint32_t engineVersion =
317 VK_MAKE_VERSION(engineInfo.versionMajor, engineInfo.versionMinor, engineInfo.versionPatch);
318 const uint32_t appVersion = VK_MAKE_VERSION(appInfo.versionMajor, appInfo.versionMinor, appInfo.versionPatch);
319 const VkApplicationInfo applicationInfo {
320 VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
321 nullptr, // pNext
322 appInfo.name.c_str(), // pApplicationName
323 appVersion, // applicationVersion
324 engineInfo.name.c_str(), // pEngineName
325 engineVersion, // engineVersion
326 apiVersion, // apiVersion
327 };
328
329 const VkInstanceCreateInfo instanceCreateInfo {
330 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
331 nullptr, // pNext
332 #ifdef __APPLE__
333 VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, // flags
334 #else
335 0, // flags
336 #endif
337 &applicationInfo, // pApplicationInfo
338 (uint32_t)layers.size(), // enabledLayerCount
339 layers.data(), // ppEnabledLayerNames
340 (uint32_t)extensions.size(), // enabledExtensionCount
341 extensions.data(), // ppEnabledExtensionNames
342 };
343
344 VALIDATE_VK_RESULT(vkCreateInstance(&instanceCreateInfo, // pCreateInfo
345 nullptr, // pAllocator
346 &wrapper.instance)); // pInstance
347 return wrapper;
348 }
349
DestroyInstance(VkInstance instance)350 void CreateFunctionsVk::DestroyInstance(VkInstance instance)
351 {
352 PLUGIN_ASSERT_MSG(instance, "null instance in DestroyInstance()");
353 vkDestroyInstance(instance, // instance
354 nullptr); // pAllocator
355 }
356
CreateDebugCallback(VkInstance instance,PFN_vkDebugReportCallbackEXT callbackFunction)357 VkDebugReportCallbackEXT CreateFunctionsVk::CreateDebugCallback(
358 VkInstance instance, PFN_vkDebugReportCallbackEXT callbackFunction)
359 {
360 VkDebugReportCallbackEXT debugReport { VK_NULL_HANDLE };
361 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
362 auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT) reinterpret_cast<void*>(
363 vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
364 if (!vkCreateDebugReportCallbackEXT) {
365 PLUGIN_LOG_W("Missing VK_EXT_debug_report extension");
366 return debugReport;
367 }
368
369 VkDebugReportCallbackCreateInfoEXT const callbackCreateInfo
370 {
371 VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, // sType
372 nullptr, // pNext
373 #if (RENDER_VULKAN_VALIDATION_ENABLE_INFORMATION == 1)
374 VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
375 #endif
376 #if (RENDER_VULKAN_VALIDATION_ENABLE_WARNINGS == 1)
377 VK_DEBUG_REPORT_WARNING_BIT_EXT |
378 #endif
379 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT, // flags
380 callbackFunction, // pfnCallback
381 nullptr // pUserData
382 };
383 VALIDATE_VK_RESULT(vkCreateDebugReportCallbackEXT(instance, // instance
384 &callbackCreateInfo, // pCreateInfo
385 nullptr, // pAllocator
386 &debugReport)); // pCallback
387 #endif
388 return debugReport;
389 }
390
DestroyDebugCallback(VkInstance instance,VkDebugReportCallbackEXT debugReport)391 void CreateFunctionsVk::DestroyDebugCallback(VkInstance instance, VkDebugReportCallbackEXT debugReport)
392 {
393 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
394 if (!debugReport) {
395 return;
396 }
397 auto vkDestroyDebugReportCallbackEXT =
398 (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
399 if (!vkDestroyDebugReportCallbackEXT) {
400 PLUGIN_LOG_W("Missing VK_EXT_debug_report extension");
401 return;
402 }
403 vkDestroyDebugReportCallbackEXT(instance, debugReport, nullptr);
404 #endif
405 }
406
CreateDebugMessenger(VkInstance instance,PFN_vkDebugUtilsMessengerCallbackEXT callbackFunction,RenderContext * renderContext)407 VkDebugUtilsMessengerEXT CreateFunctionsVk::CreateDebugMessenger(
408 VkInstance instance, PFN_vkDebugUtilsMessengerCallbackEXT callbackFunction, RenderContext* renderContext)
409 {
410 VkDebugUtilsMessengerEXT debugMessenger { VK_NULL_HANDLE };
411 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
412 auto vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT) reinterpret_cast<void*>(
413 vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"));
414 if (!vkCreateDebugUtilsMessengerEXT) {
415 PLUGIN_LOG_W("Missing VK_EXT_debug_utils extension");
416 return debugMessenger;
417 }
418
419 VkDebugUtilsMessengerCreateInfoEXT const messengerCreateInfo {
420 VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, // sType
421 nullptr, // pNext
422 0, // flags
423 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
424 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, // messageSeverity
425 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
426 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, // messageType
427 callbackFunction, // pfnUserCallback
428 renderContext, // pUserData
429 };
430 VALIDATE_VK_RESULT(vkCreateDebugUtilsMessengerEXT(instance, // instance
431 &messengerCreateInfo, // pCreateInfo
432 nullptr, // pAllocator
433 &debugMessenger)); // pMessenger
434
435 #endif
436 return debugMessenger;
437 }
438
DestroyDebugMessenger(VkInstance instance,VkDebugUtilsMessengerEXT debugMessenger)439 void CreateFunctionsVk::DestroyDebugMessenger(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger)
440 {
441 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
442 if (!debugMessenger) {
443 return;
444 }
445
446 auto vkDestroyDebugUtilsMessengerEXT =
447 (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
448 if (!vkDestroyDebugUtilsMessengerEXT) {
449 PLUGIN_LOG_W("Missing VK_EXT_debug_utils extension");
450 return;
451 }
452
453 vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
454 #endif
455 }
456
GetWrapper(VkPhysicalDevice physicalDevice)457 PhysicalDeviceWrapper CreateFunctionsVk::GetWrapper(VkPhysicalDevice physicalDevice)
458 {
459 VkPhysicalDeviceProperties physicalDeviceProperties;
460 vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
461
462 VkPhysicalDeviceFeatures physicalDeviceFeatures;
463 vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
464
465 uint32_t extensionPropertyCount = 0;
466 vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionPropertyCount, nullptr);
467 vector<VkExtensionProperties> extensions(extensionPropertyCount);
468 vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionPropertyCount, extensions.data());
469 std::sort(extensions.begin(), extensions.end(), [](const VkExtensionProperties& lhs, VkExtensionProperties& rhs) {
470 return std::strcmp(lhs.extensionName, rhs.extensionName) < 0;
471 });
472 VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties;
473 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &physicalDeviceMemoryProperties);
474 if constexpr (CORE_ENABLE_VULKAN_PHYSICAL_DEVICE_PRINT) {
475 LogPhysicalDeviceProperties(physicalDeviceProperties);
476 for (auto& extension : extensions) {
477 PLUGIN_LOG_V("physical device extension: %s %u", extension.extensionName, extension.specVersion);
478 }
479 #ifndef NDEBUG
480 LogPhysicalDeviceMemoryProperties(physicalDeviceMemoryProperties);
481 #endif
482 }
483
484 return { physicalDevice, move(extensions),
485 { move(physicalDeviceProperties), move(physicalDeviceFeatures), move(physicalDeviceMemoryProperties) } };
486 }
487
CreatePhysicalDevice(VkInstance instance,QueueProperties const & queueProperties)488 PhysicalDeviceWrapper CreateFunctionsVk::CreatePhysicalDevice(
489 VkInstance instance, QueueProperties const& queueProperties)
490 {
491 if (!instance) {
492 PLUGIN_LOG_E("Invalid Vulkan instance.");
493 return {};
494 }
495
496 uint32_t physicalDeviceCount = 0;
497 VALIDATE_VK_RESULT(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr));
498
499 uint32_t usedPhysicalDeviceCount { 1 }; // only one device, the first
500 // some drivers write out physicalDeviceCount instead of usedPhysicalDeviceCount VkPhysicalDevices so we need enough
501 // space
502 vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount, VK_NULL_HANDLE);
503 const VkResult result = vkEnumeratePhysicalDevices(instance, &usedPhysicalDeviceCount, physicalDevices.data());
504 PLUGIN_UNUSED(result);
505 PLUGIN_ASSERT_MSG((result == VK_SUCCESS || result == VK_INCOMPLETE), "vulkan device enumeration failed");
506
507 if (physicalDevices.empty()) {
508 return {};
509 }
510 const VkPhysicalDevice physicalDevice = physicalDevices[0];
511
512 uint32_t queueFamilyPropertyCount = 0;
513 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount, nullptr);
514 vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyPropertyCount);
515 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount, queueFamilyProperties.data());
516
517 if constexpr (CORE_ENABLE_VULKAN_PHYSICAL_DEVICE_PRINT) {
518 PLUGIN_LOG_D("physical device count: %u", physicalDeviceCount);
519 LogQueueFamilyProperties(instance, physicalDevice, queueFamilyProperties);
520 }
521
522 const auto suitableQueue = FindSuitableQueue(queueFamilyProperties, queueProperties);
523 if (suitableQueue.queueCount == 0) {
524 PLUGIN_LOG_E("No device maching required queues %x or present capabilities %u", queueProperties.requiredFlags,
525 queueProperties.canPresent);
526 return {};
527 }
528 return GetWrapper(physicalDevice);
529 }
530
HasExtension(array_view<const VkExtensionProperties> physicalDeviceExtensions,string_view extension)531 bool CreateFunctionsVk::HasExtension(
532 array_view<const VkExtensionProperties> physicalDeviceExtensions, string_view extension)
533 {
534 VkExtensionProperties value;
535 value.extensionName[extension.copy(
536 value.extensionName, Math::min(countof(value.extensionName), extension.size()), 0U)] = '\0';
537 value.specVersion = 1;
538 return std::binary_search(physicalDeviceExtensions.cbegin(), physicalDeviceExtensions.cend(), value,
539 [](const VkExtensionProperties& element, const VkExtensionProperties& value) {
540 return std::strcmp(element.extensionName, value.extensionName) < 0;
541 });
542 }
543
CreateDevice(VkInstance instance,VkPhysicalDevice physicalDevice,const vector<VkExtensionProperties> & physicalDeviceExtensions,const VkPhysicalDeviceFeatures & featuresToEnable,const VkPhysicalDeviceFeatures2 * physicalDeviceFeatures2,const vector<LowLevelQueueInfo> & availableQueues,const vector<string_view> & preferredDeviceExtensions)544 DeviceWrapper CreateFunctionsVk::CreateDevice(VkInstance instance, VkPhysicalDevice physicalDevice,
545 const vector<VkExtensionProperties>& physicalDeviceExtensions, const VkPhysicalDeviceFeatures& featuresToEnable,
546 const VkPhysicalDeviceFeatures2* physicalDeviceFeatures2, const vector<LowLevelQueueInfo>& availableQueues,
547 const vector<string_view>& preferredDeviceExtensions)
548 {
549 if ((!instance) || (!physicalDevice)) {
550 PLUGIN_LOG_E("Invalid instance and/or physical device.");
551 return {};
552 }
553
554 DeviceWrapper deviceWrapper;
555
556 vector<VkDeviceQueueCreateInfo> queueCreateInfos;
557 queueCreateInfos.reserve(availableQueues.size());
558 constexpr uint32_t maxQueuePriorityCount { 8 };
559 float queuePriorities[maxQueuePriorityCount];
560 uint32_t priorityIndex = 0;
561 PLUGIN_LOG_D("creating device with queue(s):");
562 vector<LowLevelGpuQueueVk> lowLevelQueues;
563 for (const auto& ref : availableQueues) {
564 const uint32_t priorityStartIndex = priorityIndex;
565 for (uint32_t priorityIdx = 0; priorityIdx < ref.queueCount; ++priorityIdx) {
566 PLUGIN_ASSERT(priorityIndex < maxQueuePriorityCount);
567 queuePriorities[priorityIndex] = ref.priority;
568 priorityIndex++;
569 }
570 queueCreateInfos.push_back(VkDeviceQueueCreateInfo {
571 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
572 nullptr, // pNext
573 0, // flags
574 ref.queueFamilyIndex, // queueFamilyIndex
575 ref.queueCount, // queueCount
576 &queuePriorities[priorityStartIndex], // pQueuePriorities
577 });
578 PLUGIN_LOG_D(
579 "queue(s), flags: %u, family index: %u, count: %u", ref.queueFlags, ref.queueFamilyIndex, ref.queueCount);
580 }
581
582 const vector<const char*> layers = {
583 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
584 "VK_LAYER_KHRONOS_validation",
585 #endif
586 };
587 vector<const char*> extensions;
588 for (const string_view& preferredDeviceExtension : preferredDeviceExtensions) {
589 if (HasExtension(physicalDeviceExtensions, preferredDeviceExtension)) {
590 extensions.push_back(preferredDeviceExtension.data());
591 deviceWrapper.extensions.push_back(preferredDeviceExtension.data());
592 }
593 }
594 if constexpr (CORE_ENABLE_VULKAN_PHYSICAL_DEVICE_PRINT) {
595 PLUGIN_LOG_D("enabled extensions:");
596 for (auto& extension : extensions) {
597 PLUGIN_LOG_D("%s", extension);
598 }
599 }
600
601 VkDeviceCreateInfo const createInfo {
602 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType;
603 physicalDeviceFeatures2, // pNext;
604 0, // flags;
605 (uint32_t)queueCreateInfos.size(), // queueCreateInfoCount;
606 queueCreateInfos.data(), // pQueueCreateInfos;
607 uint32_t(layers.size()), // enabledLayerCount;
608 layers.data(), // ppEnabledLayerNames;
609 uint32_t(extensions.size()), // enabledExtensionCount;
610 extensions.data(), // ppEnabledExtensionNames;
611 physicalDeviceFeatures2 ? nullptr : &featuresToEnable, // pEnabledFeatures
612 };
613 VALIDATE_VK_RESULT(vkCreateDevice(physicalDevice, // physicalDevice
614 &createInfo, // pCreateInfo
615 nullptr, // pAllocator
616 &deviceWrapper.device)); // pDevice
617 return deviceWrapper;
618 }
619
DestroyDevice(VkDevice device)620 void CreateFunctionsVk::DestroyDevice(VkDevice device)
621 {
622 PLUGIN_ASSERT_MSG(device, "null device in DestroyDevice()");
623 vkDestroyDevice(device, // device
624 nullptr); // pAllocator
625 }
626
DestroySurface(VkInstance instance,VkSurfaceKHR surface)627 void CreateFunctionsVk::DestroySurface(VkInstance instance, VkSurfaceKHR surface)
628 {
629 PLUGIN_ASSERT_MSG(instance, "null instance in DestroySurface()");
630 PLUGIN_ASSERT_MSG(surface, "null surface in DestroySurface()");
631 auto vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR");
632 if (!vkDestroySurfaceKHR) {
633 PLUGIN_LOG_E("Missing VK_KHR_surface extension");
634 return;
635 }
636
637 vkDestroySurfaceKHR(instance, // instance
638 surface, // surface
639 nullptr); // pAllocator
640 }
641
DestroySwapchain(VkDevice device,VkSwapchainKHR swapchain)642 void CreateFunctionsVk::DestroySwapchain(VkDevice device, VkSwapchainKHR swapchain)
643 {
644 if (device && swapchain) {
645 vkDestroySwapchainKHR(device, swapchain, nullptr);
646 }
647 }
648
CreatePipelineCache(VkDevice device,array_view<const uint8_t> initialData)649 VkPipelineCache CreateFunctionsVk::CreatePipelineCache(VkDevice device, array_view<const uint8_t> initialData)
650 {
651 VkPipelineCache pipelineCache = VK_NULL_HANDLE;
652
653 PLUGIN_ASSERT_MSG(device, "null device in CreatePipelineCache()");
654
655 const auto info = VkPipelineCacheCreateInfo {
656 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // sType
657 nullptr, // pNext
658 0, // flags
659 initialData.size(), // initialDataSize
660 initialData.data(), // pInitialData
661 };
662 VALIDATE_VK_RESULT(vkCreatePipelineCache(device, &info, nullptr, &pipelineCache));
663
664 return pipelineCache;
665 }
666
DestroyPipelineCache(VkDevice device,VkPipelineCache pipelineCache)667 void CreateFunctionsVk::DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache)
668 {
669 PLUGIN_ASSERT_MSG(device, "null device in DestroyPipelineCache()");
670 PLUGIN_ASSERT_MSG(pipelineCache, "null pipelineCache in DestroyPipelineCache()");
671
672 vkDestroyPipelineCache(device, pipelineCache, nullptr);
673 }
674 RENDER_END_NAMESPACE()
675