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