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