• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.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: %u", 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 
CreateInstance(const VersionInfo & engineInfo,const VersionInfo & appInfo)179 InstanceWrapper CreateFunctionsVk::CreateInstance(const VersionInfo& engineInfo, const VersionInfo& appInfo)
180 {
181     InstanceWrapper wrapper;
182     uint32_t instanceExtensionPropertyCount = 0;
183     vkEnumerateInstanceExtensionProperties(nullptr, // pLayerName
184         &instanceExtensionPropertyCount,            // propertyCount
185         nullptr);                                   // pProperties
186     vector<VkExtensionProperties> instanceExtensions(instanceExtensionPropertyCount);
187     vkEnumerateInstanceExtensionProperties(nullptr, // pLayerName
188         &instanceExtensionPropertyCount,            // propertyCount
189         instanceExtensions.data());                 // pProperties
190 
191     // NOTE: check extensions...
192     PLUGIN_LOG_D("Vulkan: available extensions:");
193 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
194     const char* debugExtension = nullptr;
195 #endif
196 #if (!defined(NDEBUG) || RENDER_VULKAN_VALIDATION_ENABLED == 1)
197     for (const auto& ref : instanceExtensions) {
198         PLUGIN_LOG_D("%s", ref.extensionName);
199 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
200         if (strcmp(ref.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
201             wrapper.debugUtilsSupported = true;
202             debugExtension = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
203         } else if (!debugExtension && strcmp(ref.extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
204             wrapper.debugReportSupported = true;
205             debugExtension = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
206         }
207 #endif
208     }
209 #endif
210 
211     vector<const char*> extensions = { VK_KHR_SURFACE_EXTENSION_NAME, GetPlatformSurfaceName() };
212 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
213     if (debugExtension) {
214         extensions.push_back(debugExtension);
215     }
216 #endif
217     if (!std::all_of(extensions.begin(), extensions.end(), [&instanceExtensions](auto const requiredExtension) {
218             const bool supported = std::any_of(instanceExtensions.begin(), instanceExtensions.end(),
219                 [&requiredExtension](const auto& supportedExtension) {
220                     return (std::strcmp(supportedExtension.extensionName, requiredExtension) == 0);
221                 });
222             if (!supported) {
223                 PLUGIN_LOG_E("some extensions are not supported! Extension name: %s", requiredExtension);
224             }
225             return supported;
226         })) {
227     }
228 
229     uint32_t instanceLayerPropertyCount = 0;
230     vkEnumerateInstanceLayerProperties(&instanceLayerPropertyCount, // pPropertyCount
231         nullptr);                                                   // pProperties
232     vector<VkLayerProperties> instanceLayers(instanceLayerPropertyCount);
233     vkEnumerateInstanceLayerProperties(&instanceLayerPropertyCount, // pPropertyCount
234         instanceLayers.data());                                     // pProperties
235     PLUGIN_LOG_D("Vulkan: available layers:");
236 #if (!defined(NDEBUG) || RENDER_VULKAN_VALIDATION_ENABLED == 1)
237     for (const auto& ref : instanceLayers) {
238         PLUGIN_LOG_D("%s", ref.layerName);
239     }
240 #endif
241 
242     vector<const char*> layers = {
243 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
244         "VK_LAYER_KHRONOS_validation",
245 #endif
246     };
247     if (!std::all_of(layers.begin(), layers.end(), [&instanceLayers](auto const requiredLayer) {
248             const bool supported =
249                 std::any_of(instanceLayers.begin(), instanceLayers.end(), [&requiredLayer](const auto& supportedLayer) {
250                     return (std::strcmp(supportedLayer.layerName, requiredLayer) == 0);
251                 });
252             if (!supported) {
253                 PLUGIN_LOG_E("some layers are not supported! Layer name: %s", requiredLayer);
254             }
255             return supported;
256         })) {
257     }
258 
259     const uint32_t apiVersion = GetInstanceApiVersion();
260     wrapper.apiMajor = VK_VERSION_MAJOR(apiVersion);
261     wrapper.apiMinor = VK_VERSION_MINOR(apiVersion);
262 
263     const uint32_t engineVersion =
264         VK_MAKE_VERSION(engineInfo.versionMajor, engineInfo.versionMinor, engineInfo.versionPatch);
265     const uint32_t appVersion = VK_MAKE_VERSION(appInfo.versionMajor, appInfo.versionMinor, appInfo.versionPatch);
266     const VkApplicationInfo applicationInfo {
267         VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
268         nullptr,                            // pNext
269         appInfo.name.c_str(),               // pApplicationName
270         appVersion,                         // applicationVersion
271         engineInfo.name.c_str(),            // pEngineName
272         engineVersion,                      // engineVersion
273         apiVersion,                         // apiVersion
274     };
275 
276     const VkInstanceCreateInfo instanceCreateInfo {
277         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
278         nullptr,                                // pNext
279         0,                                      // flags
280         &applicationInfo,                       // pApplicationInfo
281         (uint32_t)layers.size(),                // enabledLayerCount
282         layers.data(),                          // ppEnabledLayerNames
283         (uint32_t)extensions.size(),            // enabledExtensionCount
284         extensions.data(),                      // ppEnabledExtensionNames
285     };
286 
287     VALIDATE_VK_RESULT(vkCreateInstance(&instanceCreateInfo, // pCreateInfo
288         nullptr,                                             // pAllocator
289         &wrapper.instance));                                 // pInstance
290     return wrapper;
291 }
292 
DestroyInstance(VkInstance instance)293 void CreateFunctionsVk::DestroyInstance(VkInstance instance)
294 {
295     PLUGIN_ASSERT_MSG(instance, "null instance in DestroyInstance()");
296     vkDestroyInstance(instance, // instance
297         nullptr);               // pAllocator
298 }
299 
CreateDebugCallback(VkInstance instance,PFN_vkDebugReportCallbackEXT callbackFunction)300 VkDebugReportCallbackEXT CreateFunctionsVk::CreateDebugCallback(
301     VkInstance instance, PFN_vkDebugReportCallbackEXT callbackFunction)
302 {
303     VkDebugReportCallbackEXT debugReport { VK_NULL_HANDLE };
304 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
305     PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT =
306         (PFN_vkCreateDebugReportCallbackEXT) reinterpret_cast<void*>(
307             vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
308     if (!vkCreateDebugReportCallbackEXT) {
309         PLUGIN_LOG_W("Missing VK_EXT_debug_report extension");
310         return debugReport;
311     }
312 
313     VkDebugReportCallbackCreateInfoEXT const callbackCreateInfo
314     {
315         VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, // sType
316             nullptr,                                             // pNext
317 #if (RENDER_VULKAN_VALIDATION_ENABLE_INFORMATION == 1)
318             VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
319 #endif
320 #if (RENDER_VULKAN_VALIDATION_ENABLE_WARNINGS == 1)
321                 VK_DEBUG_REPORT_WARNING_BIT_EXT |
322 #endif
323                 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT, // flags
324             callbackFunction,                                                                // pfnCallback
325             nullptr                                                                          // pUserData
326     };
327     VALIDATE_VK_RESULT(vkCreateDebugReportCallbackEXT(instance, // instance
328         &callbackCreateInfo,                                    // pCreateInfo
329         nullptr,                                                // pAllocator
330         &debugReport));                                         // pCallback
331 #endif
332     return debugReport;
333 }
334 
DestroyDebugCallback(VkInstance instance,VkDebugReportCallbackEXT debugReport)335 void CreateFunctionsVk::DestroyDebugCallback(VkInstance instance, VkDebugReportCallbackEXT debugReport)
336 {
337 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
338     if (!debugReport) {
339         return;
340     }
341     PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT =
342         (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
343     if (!vkDestroyDebugReportCallbackEXT) {
344         PLUGIN_LOG_W("Missing VK_EXT_debug_report extension");
345         return;
346     }
347     vkDestroyDebugReportCallbackEXT(instance, debugReport, nullptr);
348 #endif
349 }
350 
CreateDebugMessenger(VkInstance instance,PFN_vkDebugUtilsMessengerCallbackEXT callbackFunction)351 VkDebugUtilsMessengerEXT CreateFunctionsVk::CreateDebugMessenger(
352     VkInstance instance, PFN_vkDebugUtilsMessengerCallbackEXT callbackFunction)
353 {
354     VkDebugUtilsMessengerEXT debugMessenger { VK_NULL_HANDLE };
355 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
356     PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT =
357         (PFN_vkCreateDebugUtilsMessengerEXT) reinterpret_cast<void*>(
358             vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"));
359     if (!vkCreateDebugUtilsMessengerEXT) {
360         PLUGIN_LOG_W("Missing VK_EXT_debug_utils extension");
361         return debugMessenger;
362     }
363 
364     VkDebugUtilsMessengerCreateInfoEXT const messengerCreateInfo {
365         VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, // sType
366         nullptr,                                                 // pNext
367         0,                                                       // flags
368         VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
369             VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, // messageSeverity
370         VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
371             VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, // messageType
372         callbackFunction,                                    // pfnUserCallback
373         nullptr                                              // pUserData
374     };
375     VALIDATE_VK_RESULT(vkCreateDebugUtilsMessengerEXT(instance, // instance
376         &messengerCreateInfo,                                   // pCreateInfo
377         nullptr,                                                // pAllocator
378         &debugMessenger));                                      // pMessenger
379 
380 #endif
381     return debugMessenger;
382 }
383 
DestroyDebugMessenger(VkInstance instance,VkDebugUtilsMessengerEXT debugMessenger)384 void CreateFunctionsVk::DestroyDebugMessenger(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger)
385 {
386 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
387     if (!debugMessenger) {
388         return;
389     }
390 
391     PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT =
392         (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
393     if (!vkDestroyDebugUtilsMessengerEXT) {
394         PLUGIN_LOG_W("Missing VK_EXT_debug_utils extension");
395         return;
396     }
397 
398     vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
399 #endif
400 }
401 
CreatePhysicalDevice(VkInstance instance,QueueProperties const & queueProperties)402 PhysicalDeviceWrapper CreateFunctionsVk::CreatePhysicalDevice(
403     VkInstance instance, QueueProperties const& queueProperties)
404 {
405     uint32_t physicalDeviceCount = 0;
406     VALIDATE_VK_RESULT(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr));
407 
408     VkPhysicalDevice physicalDevice { VK_NULL_HANDLE };
409 
410     uint32_t usedPhysicalDeviceCount { 1 }; // only one device, the first
411     const VkResult result = vkEnumeratePhysicalDevices(instance, &usedPhysicalDeviceCount, &physicalDevice);
412     PLUGIN_UNUSED(result);
413     PLUGIN_ASSERT_MSG((result == VK_SUCCESS || result == VK_INCOMPLETE), "vulkan device enumeration failed");
414 
415     VkPhysicalDeviceProperties physicalDeviceProperties;
416     vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
417 
418     VkPhysicalDeviceFeatures physicalDeviceFeatures;
419     vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
420 
421     VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties;
422     vkGetPhysicalDeviceMemoryProperties(physicalDevice, &physicalDeviceMemoryProperties);
423 
424     uint32_t queueFamilyPropertyCount = 0;
425     vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount, nullptr);
426     vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyPropertyCount);
427     vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount, queueFamilyProperties.data());
428 
429     uint32_t extensionPropertyCount = 0;
430     vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionPropertyCount, nullptr);
431     vector<VkExtensionProperties> extensions(extensionPropertyCount);
432     vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionPropertyCount, extensions.data());
433 
434     if constexpr (CORE_ENABLE_VULKAN_PHYSICAL_DEVICE_PRINT) {
435         PLUGIN_LOG_D("physical device count: %u", physicalDeviceCount);
436         LogPhysicalDeviceProperties(physicalDeviceProperties);
437         LogQueueFamilyProperties(instance, physicalDevice, queueFamilyProperties);
438         for (uint32_t idx = 0; idx < extensions.size(); ++idx) {
439             PLUGIN_LOG_D(
440                 "physical device extension: %s %u", extensions[idx].extensionName, extensions[idx].specVersion);
441         }
442 #ifndef NDEBUG
443         LogPhysicalDeviceMemoryProperties(physicalDeviceMemoryProperties);
444 #endif
445     }
446 
447     const auto suitableQueue = FindSuitableQueue(queueFamilyProperties, queueProperties);
448     if (suitableQueue.queueCount == 0) {
449         PLUGIN_LOG_E("No device maching required queues %x or present capabilities %u", queueProperties.requiredFlags,
450             queueProperties.canPresent);
451         return {};
452     }
453 
454     return { physicalDevice, move(extensions),
455         { move(physicalDeviceProperties), move(physicalDeviceFeatures), move(physicalDeviceMemoryProperties) } };
456 }
457 
CreateDevice(VkInstance instance,VkPhysicalDevice physicalDevice,const vector<VkExtensionProperties> & physicalDeviceExtensions,const VkPhysicalDeviceFeatures & featuresToEnable,const VkPhysicalDeviceFeatures2 * physicalDeviceFeatures2,const vector<LowLevelQueueInfo> & availableQueues,const vector<string_view> & preferredDeviceExtensions)458 DeviceWrapper CreateFunctionsVk::CreateDevice(VkInstance instance, VkPhysicalDevice physicalDevice,
459     const vector<VkExtensionProperties>& physicalDeviceExtensions, const VkPhysicalDeviceFeatures& featuresToEnable,
460     const VkPhysicalDeviceFeatures2* physicalDeviceFeatures2, const vector<LowLevelQueueInfo>& availableQueues,
461     const vector<string_view>& preferredDeviceExtensions)
462 {
463     PLUGIN_ASSERT_MSG(instance, "null instance in CreateDevice()");
464     PLUGIN_ASSERT_MSG(physicalDevice, "null physical device in CreateDevice()");
465 
466     DeviceWrapper deviceWrapper;
467 
468     vector<VkDeviceQueueCreateInfo> queueCreateInfos;
469     queueCreateInfos.reserve(availableQueues.size());
470     constexpr uint32_t maxQueuePriorityCount { 8 };
471     float queuePriorities[maxQueuePriorityCount];
472     uint32_t priorityIndex = 0;
473     PLUGIN_LOG_D("creating device with queue(s):");
474     vector<LowLevelGpuQueueVk> lowLevelQueues;
475     for (const auto& ref : availableQueues) {
476         const uint32_t priorityStartIndex = priorityIndex;
477         for (uint32_t priorityIdx = 0; priorityIdx < ref.queueCount; ++priorityIdx) {
478             PLUGIN_ASSERT(priorityIndex < maxQueuePriorityCount);
479             queuePriorities[priorityIndex] = ref.priority;
480             priorityIndex++;
481         }
482         queueCreateInfos.push_back(VkDeviceQueueCreateInfo {
483             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
484             nullptr,                                    // pNext
485             0,                                          // flags
486             ref.queueFamilyIndex,                       // queueFamilyIndex
487             ref.queueCount,                             // queueCount
488             &queuePriorities[priorityStartIndex],       // pQueuePriorities
489         });
490         PLUGIN_LOG_D(
491             "queue(s), flags: %u, family index: %u, count: %u", ref.queueFlags, ref.queueFamilyIndex, ref.queueCount);
492     }
493 
494     const vector<const char*> layers = {
495 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
496         "VK_LAYER_KHRONOS_validation",
497 #endif
498     };
499     vector<const char*> extensions;
500     for (uint32_t idx = 0; idx < preferredDeviceExtensions.size(); ++idx) {
501         for (uint32_t jdx = 0; jdx < physicalDeviceExtensions.size(); ++jdx) {
502             if (preferredDeviceExtensions[idx].compare(physicalDeviceExtensions[jdx].extensionName) == 0) {
503                 extensions.push_back(physicalDeviceExtensions[jdx].extensionName);
504                 deviceWrapper.extensions.push_back(physicalDeviceExtensions[jdx].extensionName);
505             }
506         }
507     }
508     if constexpr (CORE_ENABLE_VULKAN_PHYSICAL_DEVICE_PRINT) {
509         PLUGIN_LOG_D("enabled extensions:");
510         for (uint32_t idx = 0; idx < extensions.size(); ++idx) {
511             PLUGIN_LOG_D("%s", extensions[idx]);
512         }
513     }
514 
515     VkDeviceCreateInfo const createInfo {
516         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,                  // sType;
517         physicalDeviceFeatures2,                               // pNext;
518         0,                                                     // flags;
519         (uint32_t)queueCreateInfos.size(),                     // queueCreateInfoCount;
520         queueCreateInfos.data(),                               // pQueueCreateInfos;
521         uint32_t(layers.size()),                               // enabledLayerCount;
522         layers.data(),                                         // ppEnabledLayerNames;
523         uint32_t(extensions.size()),                           // enabledExtensionCount;
524         extensions.data(),                                     // ppEnabledExtensionNames;
525         physicalDeviceFeatures2 ? nullptr : &featuresToEnable, // pEnabledFeatures
526     };
527     VALIDATE_VK_RESULT(vkCreateDevice(physicalDevice, // physicalDevice
528         &createInfo,                                  // pCreateInfo
529         nullptr,                                      // pAllocator
530         &deviceWrapper.device));                      // pDevice
531     return deviceWrapper;
532 }
533 
DestroyDevice(VkDevice device)534 void CreateFunctionsVk::DestroyDevice(VkDevice device)
535 {
536     PLUGIN_ASSERT_MSG(device, "null device in DestroyDevice()");
537     vkDestroyDevice(device, // device
538         nullptr);           // pAllocator
539 }
540 
DestroySurface(VkInstance instance,VkSurfaceKHR surface)541 void CreateFunctionsVk::DestroySurface(VkInstance instance, VkSurfaceKHR surface)
542 {
543     PLUGIN_ASSERT_MSG(instance, "null instance in DestroySurface()");
544     PLUGIN_ASSERT_MSG(surface, "null surface in DestroySurface()");
545     PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR =
546         (PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR");
547     if (!vkDestroySurfaceKHR) {
548         PLUGIN_LOG_E("Missing VK_KHR_surface extension");
549         return;
550     }
551 
552     vkDestroySurfaceKHR(instance, // instance
553         surface,                  // surface
554         nullptr);                 // pAllocator
555 }
556 
DestroySwapchain(VkDevice device,VkSwapchainKHR swapchain)557 void CreateFunctionsVk::DestroySwapchain(VkDevice device, VkSwapchainKHR swapchain)
558 {
559     PLUGIN_ASSERT_MSG(device, "null device in DestroySwapchain()");
560     PLUGIN_ASSERT_MSG(swapchain, "null swapchain in DestroySwapchain()");
561 
562     vkDestroySwapchainKHR(device, swapchain, nullptr);
563 }
564 
CreatePipelineCache(VkDevice device,array_view<const uint8_t> initialData)565 VkPipelineCache CreateFunctionsVk::CreatePipelineCache(VkDevice device, array_view<const uint8_t> initialData)
566 {
567     VkPipelineCache pipelineCache = VK_NULL_HANDLE;
568 
569     PLUGIN_ASSERT_MSG(device, "null device in CreatePipelineCache()");
570 
571     const auto info = VkPipelineCacheCreateInfo {
572         VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // sType
573         nullptr,                                      // pNext
574         0,                                            // flags
575         initialData.size(),                           // initialDataSize
576         initialData.data(),                           // pInitialData
577     };
578     VALIDATE_VK_RESULT(vkCreatePipelineCache(device, &info, nullptr, &pipelineCache));
579 
580     return pipelineCache;
581 }
582 
DestroyPipelineCache(VkDevice device,VkPipelineCache pipelineCache)583 void CreateFunctionsVk::DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache)
584 {
585     PLUGIN_ASSERT_MSG(device, "null device in DestroyPipelineCache()");
586     PLUGIN_ASSERT_MSG(pipelineCache, "null pipelineCache in DestroyPipelineCache()");
587 
588     vkDestroyPipelineCache(device, pipelineCache, nullptr);
589 }
590 RENDER_END_NAMESPACE()
591