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