HoviTron Video Pipeline
VulkanContext.cpp
1/* ----------------------
2* Copyright 2023 Université Libre de Bruxelles(ULB), Universidad Politécnica de Madrid(UPM), CREAL, Deutsches Zentrum für Luft - und Raumfahrt(DLR)
3
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at < http://www.apache.org/licenses/LICENSE-2.0>
7
8* Unless required by applicable law or agreed to in writing, software
9* distributed under the License is distributed on an "AS IS" BASIS,
10* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11* See the License for the specific language governing permissionsand
12* limitations under the License.
13---------------------- */
14
15
16
17#include <iostream>
18#include <map>
19#include <set>
20
21#include "VulkanContext.h"
22#include"../WindowAbstract.h"
23#include <iostream>
24#include <sstream>
25
26#ifdef USE_OPENXR
27 #include "../WindowOpenXR.h"
28#endif // DEBUG
29
30// Unique storage for the vulkan dynamic dispatcher
31VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE;
32
33//use code from: https://github.com/KhronosGroup/Vulkan-Hpp/blob/master/samples/01_InitInstance/01_InitInstance.cpp
34//and https://vulkan-tutorial.com/
35
36#ifdef DEBUG
37const bool PRINT_AVAILABLE_EXTENSION = false;
38#else
39const bool PRINT_AVAILABLE_EXTENSION = false;
40#endif // DEBUG
41
42const bool verboseDebug = false;
43
44
45
46
47//validation layer name
48const std::vector<const char*> validationLayers = {
49 "VK_LAYER_KHRONOS_validation"
50};
51
52//pointer to function for debug messenger
53#ifdef __ANDROID__
54static const char* kTAG = "androidContext";
55#define LOGI(...) \
56 ((void)__android_log_print(ANDROID_LOG_INFO, kTAG, __VA_ARGS__))
57PFN_vkCreateDebugUtilsMessengerEXT pfnCreateDebugUtilsMessengerEXT;
58PFN_vkDestroyDebugUtilsMessengerEXT pfnDestroyDebugUtilsMessengerEXT;
59#else
60PFN_vkCreateDebugUtilsMessengerEXT pfnVkCreateDebugUtilsMessengerEXT;
61PFN_vkDestroyDebugUtilsMessengerEXT pfnVkDestroyDebugUtilsMessengerEXT;
62#endif
63
64//Callback for Android
65#ifdef __ANDROID__
66VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
67 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
68 VkDebugUtilsMessageTypeFlagsEXT messageType,
69 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
70 void* pUserData) {
71
72 const char validation[] = "Validation";
73 const char performance[] = "Performance";
74 const char error[] = "ERROR";
75 const char warning[] = "WARNING";
76 const char unknownType[] = "UNKNOWN_TYPE";
77 const char unknownSeverity[] = "UNKNOWN_SEVERITY";
78 const char* typeString = unknownType;
79 const char* severityString = unknownSeverity;
80 const char* messageIdName = pCallbackData->pMessageIdName;
81 int32_t messageIdNumber = pCallbackData->messageIdNumber;
82 const char* message = pCallbackData->pMessage;
83 android_LogPriority priority = ANDROID_LOG_UNKNOWN;
84
85 if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
86 severityString = error;
87 priority = ANDROID_LOG_ERROR;
88 }
89 else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
90 severityString = warning;
91 priority = ANDROID_LOG_WARN;
92 }
93 if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) {
94 typeString = validation;
95 }
96 else if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) {
97 typeString = performance;
98 }
99
100 const int maxSize= 1000;
101 std::string longMessage = message;
102
103 for(int i = 0; i <= longMessage.length() / maxSize; i++) {
104 int start = i * maxSize;
105 int end = (i + 1) * maxSize;
106 end = end > longMessage.length() ? longMessage.length() : end;
107 if(i == 0) {
108 __android_log_print(priority,
109 kTAG,
110 "%s %s: [%s] Code %i : %s",
111 typeString,
112 severityString,
113 messageIdName,
114 messageIdNumber,
115 longMessage.substr(start,end).c_str());
116 }else{
117 LOGI("%s",longMessage.substr(start,end).c_str());
118 }
119 }
120#else
121 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
122 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
123 VkDebugUtilsMessageTypeFlagsEXT messageType,
124 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
125 void* pUserData) {
126 if (VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT != messageSeverity || verboseDebug) {
127 std::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl;
128 }
129#endif
130 return VK_FALSE;
131}
132
133#ifdef __ANDROID__
134
135#else
136VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT( VkInstance instance,
137 const VkDebugUtilsMessengerCreateInfoEXT * pCreateInfo,
138 const VkAllocationCallbacks * pAllocator,
139 VkDebugUtilsMessengerEXT * pMessenger )
140{
141 return pfnVkCreateDebugUtilsMessengerEXT( instance, pCreateInfo, pAllocator, pMessenger );
142}
143
144VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT( VkInstance instance,
145 VkDebugUtilsMessengerEXT messenger,
146 VkAllocationCallbacks const * pAllocator )
147{
148 return pfnVkDestroyDebugUtilsMessengerEXT( instance, messenger, pAllocator );
149}
150#endif
151
153{
154 try
155 {
156
157PRINT("Before instance creation;");
158
159 createInstance();
160
161 PRINT("setupDebug");
162
163
164 //LOGI("I'm a test c");
165 setupDebugMessenger();
166
167
168 window->createSurface();
169
170 PRINT("Physical device");
171
172#ifdef USE_OPENXR
173 if (window->useOpenXR()) {
174 static_cast<WindowOpenXR*>(window)->getVulkanPhysicalDevice(reinterpret_cast<VkInstance&>(instance),
175 reinterpret_cast<VkPhysicalDevice*>(&physicalDevice));
176 }
177 else
178#endif
179 {
180 pickPhysicalDevice();
181 }
182
183 createLogicalDevice();
184 initialized = true;
185 }
186 catch (vk::SystemError& err)
187 {
188 std::cout << "vk::SystemError: " << err.what() << std::endl;
189 exit(-1);
190 }
191 catch (std::exception& err)
192 {
193 std::cout << "std::exception: " << err.what() << std::endl;
194 exit(-1);
195 }
196 catch (std::runtime_error& err)
197 {
198 std::cout << "std::runtime error: " << err.what() << std::endl;
199 exit(-1);
200 }
201 catch (...)
202 {
203 std::cout << "unknown error\n";
204 exit(-1);
205 }
206}
207
208void VulkanContext::createInstance()
209{
210 vk::DynamicLoader dl;
211 auto getProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
212 VULKAN_HPP_DEFAULT_DISPATCHER.init(getProcAddr);
213#ifdef __ANDROID__
214 LOGI("before Test");
215#endif
216 if (window->isValidationLayersEnabled() && !checkValidationLayerSupport()) {
217 throw std::runtime_error("validation layers requested, but not available!");
218 }
219 // initialize the vk::ApplicationInfo structure
220 vk::ApplicationInfo applicationInfo(AppName.c_str(), 1.1, EngineName.c_str(), 1, VK_API_VERSION_1_2);
221
222 // initialize the vk::InstanceCreateInfo
223 vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo);
224 if (window->isValidationLayersEnabled()) {
225 instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
226 instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
227
228#ifdef __ANDROID__
229 //for android we gonna setup this later
230#else
231 vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
232 vk::DebugUtilsMessageSeverityFlagBitsEXT::eError); //| vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose);
233 vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
234 vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
235 vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);
236 vk::DebugUtilsMessengerCreateInfoEXT createInfo({}, severityFlags, messageTypeFlags, &debugCallback);
237 instanceCreateInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &createInfo;
238#endif
239 }
240
241
242 auto extensions = window->getRequiredExtensions();
243 //TODO for android we should test if debugUtils extensions is available
244
245 instanceCreateInfo.setEnabledExtensionCount(static_cast<uint32_t>(extensions.size()));
246 instanceCreateInfo.setPpEnabledExtensionNames(extensions.data());
247
248
249
250 // create an Instance
251 instance = vk::createInstance(instanceCreateInfo);
252
253 VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
254
255
256#ifdef __ANDROID__
257 if (PRINT_AVAILABLE_EXTENSION) {
258 uint32_t inst_ext_count = 0;
259 vkEnumerateInstanceExtensionProperties(nullptr, &inst_ext_count, nullptr);
260
261 // Enumerate the instance extensions.
262 VkExtensionProperties inst_exts[inst_ext_count];
263 vkEnumerateInstanceExtensionProperties(nullptr, &inst_ext_count, inst_exts);
264
265 for (const auto& extension : inst_exts) {
266 LOGI("%s", extension.extensionName );
267 }
268 }
269#else
270 if (PRINT_AVAILABLE_EXTENSION) {
271 //get the extensions
272 auto extensionsProp = vk::enumerateInstanceExtensionProperties();
273 std::cout << "available extensions:\n";
274
275 for (const auto& extension : extensionsProp) {
276 std::cout << '\t' << extension.extensionName << '\n';
277 }
278 }
279#endif
280
281
282}
283
285{
286 return format == vk::Format::eD32SfloatS8Uint || format == vk::Format::eD24UnormS8Uint;
287}
288
290{
291 return window->isIndepFromWindowDimension();
292}
293
294bool VulkanContext::checkValidationLayerSupport()
295{
296#ifdef __ANDROID__
297 // Get the layer count using a null pointer as the last parameter.
298 uint32_t instance_layer_present_count = 0;
299 vkEnumerateInstanceLayerProperties(&instance_layer_present_count, nullptr);
300 // Enumerate layers with a valid pointer in the last parameter.
301 VkLayerProperties availableLayers[instance_layer_present_count];
302 vkEnumerateInstanceLayerProperties(&instance_layer_present_count, availableLayers);
303#else
304 auto availableLayers = vk::enumerateInstanceLayerProperties();
305
306#endif
307 for (const char* layerName : validationLayers) {
308 bool layerFound = false;
309
310 for (const auto& layerProperties : availableLayers) {
311 if (strcmp(layerName, layerProperties.layerName) == 0) {
312 layerFound = true;
313 break;
314 }
315 }
316
317 if (!layerFound) {
318 return false;
319 }
320 }
321 return true;
322}
323
324void VulkanContext::setupDebugMessenger()
325{
326 //check this if needed: https://github.com/KhronosGroup/Vulkan-Hpp/blob/master/samples/CreateDebugUtilsMessenger/CreateDebugUtilsMessenger.cpp
327#if defined(USE_OPENXR) && defined(__ANDROID__)
328
329 if (!window->isValidationLayersEnabled()) createDebugReport();
330#else
331 if (!window->isValidationLayersEnabled()) return;
332#endif
333
334#ifdef __ANDROID__
335 //need to cast
336 VkInstance vkInstance = static_cast<VkInstance>(instance);
337 pfnCreateDebugUtilsMessengerEXT =
338 (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
339 vkInstance, "vkCreateDebugUtilsMessengerEXT");
340 pfnDestroyDebugUtilsMessengerEXT =
341 (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
342 vkInstance, "vkDestroyDebugUtilsMessengerEXT");
343
344 // Create the debug messenger callback with your the settings you want.
345
346 if (pfnCreateDebugUtilsMessengerEXT) {
347 VkDebugUtilsMessengerCreateInfoEXT messengerInfo;
348 constexpr VkDebugUtilsMessageSeverityFlagsEXT kSeveritiesToLog =
349 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
350 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
351
352 constexpr VkDebugUtilsMessageTypeFlagsEXT kMessagesToLog =
353 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
354 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
355 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
356
357 messengerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
358 messengerInfo.pNext = nullptr;
359 messengerInfo.flags = 0;
360 messengerInfo.messageSeverity = kSeveritiesToLog;
361 messengerInfo.messageType = kMessagesToLog;
362
363 messengerInfo.pfnUserCallback = &debugCallback;
364 messengerInfo.pUserData = nullptr; // Custom user data passed to callback
365
366 VkDebugUtilsMessengerEXT messenger;
367 pfnCreateDebugUtilsMessengerEXT(vkInstance, &messengerInfo, nullptr,
368 &messenger);
369 debugMessenger = static_cast<vk::DebugUtilsMessengerEXT>(messenger);
370 }
371#else
372 pfnVkCreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(instance.getProcAddr("vkCreateDebugUtilsMessengerEXT"));
373 if (!pfnVkCreateDebugUtilsMessengerEXT)
374 {
375 throw std::runtime_error("GetInstanceProcAddr: Unable to find pfnVkCreateDebugUtilsMessengerEXT function.");
376
377 }
378
379 pfnVkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(instance.getProcAddr("vkDestroyDebugUtilsMessengerEXT"));
380 if (!pfnVkDestroyDebugUtilsMessengerEXT)
381 {
382 throw std::runtime_error("GetInstanceProcAddr: Unable to find pfnVkDestroyDebugUtilsMessengerEXT function.");
383 }
384
385 vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
386 vk::DebugUtilsMessageSeverityFlagBitsEXT::eError| vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose | vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo);
387 vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
388 vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
389 vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);
390 vk::DebugUtilsMessengerCreateInfoEXT createInfo({}, severityFlags, messageTypeFlags, &debugCallback);
391
392 debugMessenger = instance.createDebugUtilsMessengerEXT(createInfo);
393#endif
394
395}
396
397void VulkanContext::pickPhysicalDevice()
398{
399 auto devices = instance.enumeratePhysicalDevices();
400 if (devices.size() == 0) {
401 throw std::runtime_error("failed to find GPUs with Vulkan support!");
402 }
403
404 // Use an ordered map to automatically sort candidates by increasing score
405 physicalDevice = devices[0];
406
407 std::multimap<int, vk::PhysicalDevice> candidates;
408 for (const auto& device : devices) {
409 int score = rateDeviceSuitability(device);
410 candidates.insert(std::make_pair(score, device));
411 }
412 // Check if the best candidate is suitable at all
413 if (candidates.rbegin()->first > 0) {
414 physicalDevice = candidates.rbegin()->second;
415 }
416 else {
417 throw std::runtime_error("failed to find a suitable GPU!");
418 }
419
420 std::cout << "Physical Device Name " << physicalDevice.getProperties().deviceName << std::endl;
421}
422
423int VulkanContext::rateDeviceSuitability(vk::PhysicalDevice device)
424{
425
426 auto deviceProperties = device.getProperties();
427 auto deviceFeatures = device.getFeatures();
428 //vk::PhysicalDeviceVulkan11Features vulkan11Features; //we need at least vulkan 1.2 so using features from 1.1 should be fine
429 //vk::PhysicalDeviceFeatures2 deviceFeatures2;
430 //deviceFeatures2.setPNext(&vulkan11Features);
431 //device.getFeatures2(deviceFeatures2);
432 auto features2 = device.getFeatures2 <vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceSamplerYcbcrConversionFeatures>();
433 int score = 0;
434
435 // Discrete GPUs have a significant performance advantage
436 if (deviceProperties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
437 score += 1000;
438 }
439
440 // Maximum possible size of textures affects graphics quality
441 score += deviceProperties.limits.maxImageDimension2D;
442
443 // Application can't function without geometry shaders
444 if (!deviceFeatures.geometryShader) {
445 return -1;
446 }
447 if (!deviceFeatures.samplerAnisotropy) {
448 return -1;
449 }
450 vk::PhysicalDeviceSamplerYcbcrConversionFeatures const& samplerYcbcrConversionFeatures = features2.get<vk::PhysicalDeviceSamplerYcbcrConversionFeatures>();
451 if (!samplerYcbcrConversionFeatures.samplerYcbcrConversion) {
452 return -1;
453 }
454 //if no queue not suitable device
456 return -1;
457 }
458 bool extensionsSupported = checkDeviceExtensionSupport(device);
459 bool swapChainAdequate = false;
460 if (extensionsSupported) {
461 if (window->isSwapChainNeeded()) {
462 SwapChainSupportDetails swapChainSupport = window->querySwapChainSupport(device);
463 swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
464 }
465 else {
466 swapChainAdequate = true;
467 }
468 }
469 else {
470 return -1;
471 }
472 if (!swapChainAdequate) {
473 return -1;
474 }
475
476 return score;
477}
478
479bool VulkanContext::checkDeviceExtensionSupport(vk::PhysicalDevice device)
480{
481 auto availableExtensions = device.enumerateDeviceExtensionProperties();
482
483 auto deviceExt = window->getRequiredDeviceExtensions();
484 std::set<std::string> requiredExtensions(deviceExt.begin(),deviceExt.end());
485
486 for (const auto& extension : availableExtensions) {
487 std::string name = extension.extensionName;
488 requiredExtensions.erase(name);
489 }
490 return requiredExtensions.empty();
491}
492
494{
495 QueueFamilyIndices indices;
496 auto queueFamilies = device.getQueueFamilyProperties();
497
498 int i = 0;
499 for (const auto& queueFamily : queueFamilies) {
500 if (queueFamily.queueFlags & vk::QueueFlagBits::eGraphics) {
501 indices.graphicsFamily = i;
502 } else if(queueFamily.queueFlags & vk::QueueFlagBits::eCompute) {
503 //Compute only
504 } else if(queueFamily.queueFlags & vk::QueueFlagBits::eTransfer) {
505 // Transfer only queue
506 indices.transferFamily = i;
507 }
508 if (window->isDeviceSupportingSufaceKHR(static_cast<VkPhysicalDevice>(device),i)) {
509 indices.presentFamily = i;
510 }
511 if (indices.isComplete()) {
512 break;
513 }
514
515 i++;
516 }
517
518 if (!indices.presentFamily.has_value() && window->useOpenXR() ) {
519 //In some case there is no surface to test for present support for the queue
520 //In this corner case --> default to graphism queue for present queue
521 indices.presentFamily = indices.graphicsFamily.value();
522 }
523
524 return indices;
525}
526
527vk::Format VulkanContext::findSupportedFormat(const std::vector<vk::Format>& candidates, vk::ImageTiling tiling, vk::FormatFeatureFlags features)
528{
529 for (vk::Format format : candidates) {
530 vk::FormatProperties props = physicalDevice.getFormatProperties(format);
531 if (tiling == vk::ImageTiling::eLinear && (props.linearTilingFeatures & features) == features) {
532 return format;
533 }
534 else if (tiling == vk::ImageTiling::eOptimal && (props.optimalTilingFeatures & features) == features) {
535 return format;
536 }
537 }
538 throw std::runtime_error("failed to find supported format!");
539}
540
542{
543 return findSupportedFormat(
544 { vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint },
545 vk::ImageTiling::eOptimal,
546 vk::FormatFeatureFlagBits::eDepthStencilAttachment
547 );
548}
549
550
551void VulkanContext::createLogicalDevice()
552{
553 vk::PhysicalDeviceFeatures deviceFeatures{};
554 deviceFeatures.samplerAnisotropy = VK_TRUE;
555 deviceFeatures.geometryShader = VK_TRUE;
556 deviceFeatures.shaderInt64 = VK_TRUE;
557 vk::PhysicalDeviceFeatures2 deviceFeature2{};
558 vk::PhysicalDeviceVulkan11Features devices11features{};
559 devices11features.samplerYcbcrConversion = VK_TRUE;
560 vk::PhysicalDeviceShaderAtomicInt64Features atomics64feature(VK_TRUE);
561 devices11features.setPNext(&atomics64feature);
562 vk::PhysicalDeviceShaderImageAtomicInt64FeaturesEXT atomic64image(VK_TRUE);
563 atomics64feature.setPNext(&atomic64image);
564 deviceFeature2.setPNext(&devices11features);
565 deviceFeature2.features = deviceFeatures;
566
567
568
570
571 // create a Device
572 float queuePriority = 1.0f;
573 std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
574 if (!indices.isComplete()) {
575 throw std::runtime_error("Some queues families requested by the application are not found");
576 }
577 std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value(), indices.transferFamily.value() };
578 for (uint32_t queueFamily : uniqueQueueFamilies) {
579 queueCreateInfos.push_back(vk::DeviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), queueFamily, 1, &queuePriority));
580 }
581 auto deviceExt = window->getRequiredDeviceExtensions();
582 deviceExt.push_back(VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME);
583#ifdef WIN32
584 deviceExt.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
585 deviceExt.push_back(VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME);
586#else
587//#error TODO do this for posix, linux
588 deviceExt.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
589 deviceExt.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
590 deviceExt.push_back(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME);
591 deviceExt.push_back(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);
592#endif
593 vk::DeviceCreateInfo deviceCreateInfo(vk::DeviceCreateFlags(), //flags
594 static_cast<uint32_t>(queueCreateInfos.size()), //queueCreateInfoCount
595 queueCreateInfos.data(), //queueCreateInfo
596 0, // enabledLayerCount
597 nullptr, // enabledLayer
598 static_cast<uint32_t>(deviceExt.size()), //enabledExtensionCount
599 deviceExt.data(), //enabledExtension
600 nullptr); //EnabledFeatures
601 deviceCreateInfo.setPNext(&deviceFeature2);
602
603
604 device = physicalDevice.createDevice(deviceCreateInfo);
605 graphicsQueue = device.getQueue(indices.graphicsFamily.value(),0);
606 presentQueue = device.getQueue(indices.presentFamily.value(), 0);
607 transferQueue = device.getQueue(indices.transferFamily.value(), 0);
608 queueFamilyIndex = indices.graphicsFamily.value();
610
611
612 VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
613}
614
616{
617 this->window = window;
618}
619
620
621
623{
624 // destroy
625
626 window->cleanUpSurface();
627 device.destroy();
628#ifdef __ANDROID__
629 if (window->isValidationLayersEnabled()) {
630 VkInstance vkInstance = static_cast<VkInstance>(instance);
631 auto messenger = static_cast<VkDebugUtilsMessengerEXT>(debugMessenger);
632 pfnDestroyDebugUtilsMessengerEXT(vkInstance,messenger,nullptr);
633 }
634#else
635 if (window->isValidationLayersEnabled()) {
636 instance.destroyDebugUtilsMessengerEXT(debugMessenger);
637 }
638#endif
639 instance.destroy();
640}
641
643 return initialized;
644}
645
646#ifdef ANDROID
647
648#ifdef USE_OPENXR
649
650static VKAPI_ATTR VkBool32 VKAPI_CALL debugReportThunk(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType,
651 uint64_t object, size_t location, int32_t messageCode,
652 const char* pLayerPrefix, const char* pMessage, void* pUserData) {
653 return static_cast<VulkanContext*>(pUserData)->debugReportFunction(flags, objectType, object, location, messageCode,
654 pLayerPrefix, pMessage);
655}
656
657VkBool32 VulkanContext::debugReportFunction(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t /*location*/,
658 int32_t /*messageCode*/, const char* pLayerPrefix, const char* pMessage) {
659 std::string flagNames;
660 std::string objName;
661 //Log::Level level = Log::Level::Error;
662 android_LogPriority level = ANDROID_LOG_DEBUG;
663
664 if ((flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0u) {
665 flagNames += "DEBUG:";
666 //level = Log::Level::Verbose;
667 level = ANDROID_LOG_DEBUG;
668 }
669 if ((flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0u) {
670 flagNames += "INFO:";
671 //level = Log::Level::Info;
672 level = ANDROID_LOG_INFO;
673 }
674 if ((flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0u) {
675 flagNames += "PERF:";
676 //level = Log::Level::Warning;
677 level = ANDROID_LOG_WARN;
678 }
679 if ((flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0u) {
680 flagNames += "WARN:";
681 //level = Log::Level::Warning;
682 level = ANDROID_LOG_WARN;
683 }
684 if ((flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0u) {
685 flagNames += "ERROR:";
686 //level = Log::Level::Error;
687 level = ANDROID_LOG_ERROR;
688 }
689
690#define LIST_OBJECT_TYPES(_) \
691 _(UNKNOWN) \
692 _(INSTANCE) \
693 _(PHYSICAL_DEVICE) \
694 _(DEVICE) \
695 _(QUEUE) \
696 _(SEMAPHORE) \
697 _(COMMAND_BUFFER) \
698 _(FENCE) \
699 _(DEVICE_MEMORY) \
700 _(BUFFER) \
701 _(IMAGE) \
702 _(EVENT) \
703 _(QUERY_POOL) \
704 _(BUFFER_VIEW) \
705 _(IMAGE_VIEW) \
706 _(SHADER_MODULE) \
707 _(PIPELINE_CACHE) \
708 _(PIPELINE_LAYOUT) \
709 _(RENDER_PASS) \
710 _(PIPELINE) \
711 _(DESCRIPTOR_SET_LAYOUT) \
712 _(SAMPLER) \
713 _(DESCRIPTOR_POOL) \
714 _(DESCRIPTOR_SET) \
715 _(FRAMEBUFFER) \
716 _(COMMAND_POOL) \
717 _(SURFACE_KHR) \
718 _(SWAPCHAIN_KHR) \
719 _(DISPLAY_KHR) \
720 _(DISPLAY_MODE_KHR)
721
722 switch (objectType) {
723 default:
724#define MK_OBJECT_TYPE_CASE(name) \
725 case VK_DEBUG_REPORT_OBJECT_TYPE_##name##_EXT: \
726 objName = #name; \
727 break;
728 LIST_OBJECT_TYPES(MK_OBJECT_TYPE_CASE)
729
730#if VK_HEADER_VERSION >= 46
731 MK_OBJECT_TYPE_CASE(DESCRIPTOR_UPDATE_TEMPLATE_KHR)
732#endif
733#if VK_HEADER_VERSION >= 70
734 MK_OBJECT_TYPE_CASE(DEBUG_REPORT_CALLBACK_EXT)
735#endif
736 }
737
738 if ((objectType == VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT) && (strcmp(pLayerPrefix, "Loader Message") == 0) &&
739 (strncmp(pMessage, "Device Extension:", 17) == 0)) {
740 return VK_FALSE;
741 }
742
743 //Log::Write(level, Fmt("%s (%s 0x%llx) [%s] %s", flagNames.c_str(), objName.c_str(), object, pLayerPrefix, pMessage));
744 __android_log_print(level,flagNames.c_str() ,"%s (%s 0x%llx) [%s] %s", flagNames.c_str(), objName.c_str(), object, pLayerPrefix, pMessage);
745 if ((flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0u) {
746 return VK_FALSE;
747 }
748 if ((flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0u) {
749 return VK_FALSE;
750 }
751 return VK_FALSE;
752}
753
754void VulkanContext::createDebugReport() {
755 //need to cast
756 VkInstance vkInstance = static_cast<VkInstance>(instance);
757 vkCreateDebugReportCallbackEXT =
758 (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(vkInstance, "vkCreateDebugReportCallbackEXT");
759 vkDestroyDebugReportCallbackEXT =
760 (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(vkInstance, "vkDestroyDebugReportCallbackEXT");
761 VkDebugReportCallbackCreateInfoEXT debugInfo{VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT};
762 debugInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
763 if(window->isValidationLayersEnabled()){
764 debugInfo.flags |=
765 VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
766 }
767 debugInfo.pfnCallback = debugReportThunk;
768 debugInfo.pUserData = this;
769 VkResult res = vkCreateDebugReportCallbackEXT(vkInstance, &debugInfo, nullptr, &debugReport);
770 if(res != VK_SUCCESS){
771 throw std::runtime_error("failed to create debug report");
772 }
773 LOGI("debug report created");
774}
775#endif
776#endif
777
778
779
File that contain the VulkanContext class to manage Vulkan Instance, Physical device,...
class that manages tasks related to Vulkan context (Vulkan Instance, Vulkan Physical device,...
Definition: VulkanContext.h:59
VulkanContext(WindowAbstract *window)
vk::Format findDepthFormat()
bool hasStencilComponent(vk::Format format)
vk::PhysicalDevice physicalDevice
Definition: VulkanContext.h:85
vk::Instance instance
Definition: VulkanContext.h:83
uint32_t queueFamilyIndex
Definition: VulkanContext.h:95
vk::Queue transferQueue
Definition: VulkanContext.h:93
vk::Format findSupportedFormat(const std::vector< vk::Format > &candidates, vk::ImageTiling tiling, vk::FormatFeatureFlags features)
vk::Device device
Definition: VulkanContext.h:87
uint32_t transferQueueFamilyIndex
Definition: VulkanContext.h:98
vk::Queue presentQueue
Definition: VulkanContext.h:91
vk::Queue graphicsQueue
Definition: VulkanContext.h:89
bool isIndepFromWindowDimension()
QueueFamilyIndices findQueueFamilies(vk::PhysicalDevice device)
Abstraction of the way of the result is displayed (screen or HMD).
virtual const bool useOpenXR()
virtual SwapChainSupportDetails querySwapChainSupport(vk::PhysicalDevice device)=0
virtual void cleanUpSurface()=0
virtual VkBool32 isDeviceSupportingSufaceKHR(VkPhysicalDevice device, int i)=0
const bool isValidationLayersEnabled()
virtual std::vector< const char * > getRequiredExtensions()=0
bool isIndepFromWindowDimension()
bool isSwapChainNeeded()
virtual void createSurface()=0
virtual std::vector< const char * > getRequiredDeviceExtensions()=0
Class that take care of the tasks linked to OpenXR (input and display), is used when HMD support is r...
Definition: WindowOpenXR.h:52
Struct to encapsulate the indice of the queues families.
Definition: VulkanContext.h:38
std::optional< uint32_t > transferFamily
Definition: VulkanContext.h:44
std::optional< uint32_t > graphicsFamily
Definition: VulkanContext.h:40
std::optional< uint32_t > presentFamily
Definition: VulkanContext.h:42
Struct that contains the capability for the sapchain, the formats and the present mode supported.
Definition: commonVulkan.h:87
std::vector< vk::SurfaceFormatKHR > formats
Definition: commonVulkan.h:91
std::vector< vk::PresentModeKHR > presentModes
Definition: commonVulkan.h:93