• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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