diff options
Diffstat (limited to 'drivers/vulkan/vulkan_context.cpp')
-rw-r--r-- | drivers/vulkan/vulkan_context.cpp | 560 |
1 files changed, 370 insertions, 190 deletions
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index c178a68236..a09a757842 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,6 +33,7 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/string/ustring.h" +#include "core/templates/local_vector.h" #include "core/version.h" #include "servers/rendering/rendering_device.h" @@ -41,11 +42,12 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <vector> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define APP_SHORT_NAME "GodotEngine" +VulkanHooks *VulkanContext::vulkan_hooks = nullptr; + VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -212,7 +214,7 @@ VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char *const *c } Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const char *const **names) { - static const std::vector<std::vector<const char *>> instance_validation_layers_alt{ + static const LocalVector<LocalVector<const char *>> instance_validation_layers_alt{ // Preferred set of validation layers { "VK_LAYER_KHRONOS_validation" }, @@ -249,10 +251,10 @@ Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const cha } for (uint32_t i = 0; i < instance_validation_layers_alt.size(); i++) { - if (_check_layers(instance_validation_layers_alt[i].size(), instance_validation_layers_alt[i].data(), instance_layer_count, instance_layers)) { + if (_check_layers(instance_validation_layers_alt[i].size(), instance_validation_layers_alt[i].ptr(), instance_layer_count, instance_layers)) { *count = instance_validation_layers_alt[i].size(); if (names != nullptr) { - *names = instance_validation_layers_alt[i].data(); + *names = instance_validation_layers_alt[i].ptr(); } break; } @@ -273,9 +275,9 @@ Error VulkanContext::_obtain_vulkan_version() { uint32_t api_version; VkResult res = func(&api_version); if (res == VK_SUCCESS) { - vulkan_major = VK_VERSION_MAJOR(api_version); - vulkan_minor = VK_VERSION_MINOR(api_version); - vulkan_patch = VK_VERSION_PATCH(api_version); + vulkan_major = VK_API_VERSION_MAJOR(api_version); + vulkan_minor = VK_API_VERSION_MINOR(api_version); + vulkan_patch = VK_API_VERSION_PATCH(api_version); } else { // according to the documentation this shouldn't fail with anything except a memory allocation error // in which case we're in deep trouble anyway @@ -514,27 +516,62 @@ Error VulkanContext::_check_capabilities() { subgroup_capabilities.supportedStages = 0; subgroup_capabilities.supportedOperations = 0; subgroup_capabilities.quadOperationsInAllStages = false; + shader_capabilities.shader_float16_is_supported = false; + shader_capabilities.shader_int8_is_supported = false; + storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = false; + storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = false; + storage_buffer_capabilities.storage_push_constant_16_is_supported = false; + storage_buffer_capabilities.storage_input_output_16 = false; // check for extended features - PFN_vkGetPhysicalDeviceFeatures2 device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2"); - if (device_features_func == nullptr) { + PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2"); + if (vkGetPhysicalDeviceFeatures2_func == nullptr) { // In Vulkan 1.0 might be accessible under its original extension name - device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR"); + vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR"); } - if (device_features_func != nullptr) { + if (vkGetPhysicalDeviceFeatures2_func != nullptr) { // check our extended features - VkPhysicalDeviceMultiviewFeatures multiview_features; - multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - multiview_features.pNext = nullptr; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, + /*pNext*/ nullptr, + /*shaderFloat16*/ false, + /*shaderInt8*/ false, + }; + + VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, + /*pNext*/ &shader_features, + /*storageBuffer16BitAccess*/ false, + /*uniformAndStorageBuffer16BitAccess*/ false, + /*storagePushConstant16*/ false, + /*storageInputOutput16*/ false, + }; + + VkPhysicalDeviceMultiviewFeatures multiview_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, + /*pNext*/ &storage_feature, + /*multiview*/ false, + /*multiviewGeometryShader*/ false, + /*multiviewTessellationShader*/ false, + }; VkPhysicalDeviceFeatures2 device_features; device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; device_features.pNext = &multiview_features; - device_features_func(gpu, &device_features); + vkGetPhysicalDeviceFeatures2_func(gpu, &device_features); + multiview_capabilities.is_supported = multiview_features.multiview; multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader; multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader; + + shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16; + shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8; + + storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = storage_feature.storageBuffer16BitAccess; + storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = storage_feature.uniformAndStorageBuffer16BitAccess; + storage_buffer_capabilities.storage_push_constant_16_is_supported = storage_feature.storagePushConstant16; + storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16; } // check extended properties @@ -597,7 +634,7 @@ Error VulkanContext::_check_capabilities() { return OK; } -Error VulkanContext::_create_physical_device() { +Error VulkanContext::_create_instance() { /* obtain version */ _obtain_vulkan_version(); @@ -610,15 +647,13 @@ Error VulkanContext::_create_physical_device() { } CharString cs = ProjectSettings::get_singleton()->get("application/config/name").operator String().utf8(); - String name = "GodotEngine " + String(VERSION_FULL_NAME); - CharString namecs = name.utf8(); const VkApplicationInfo app = { /*sType*/ VK_STRUCTURE_TYPE_APPLICATION_INFO, /*pNext*/ nullptr, /*pApplicationName*/ cs.get_data(), /*applicationVersion*/ 0, - /*pEngineName*/ namecs.get_data(), - /*engineVersion*/ 0, + /*pEngineName*/ VERSION_NAME, + /*engineVersion*/ VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH), /*apiVersion*/ VK_MAKE_VERSION(vulkan_major, vulkan_minor, 0) }; VkInstanceCreateInfo inst_info{}; @@ -662,21 +697,27 @@ Error VulkanContext::_create_physical_device() { inst_info.pNext = &dbg_report_callback_create_info; } - uint32_t gpu_count; + VkResult err; - VkResult err = vkCreateInstance(&inst_info, nullptr, &inst); - ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE, - "Cannot find a compatible Vulkan installable client driver (ICD).\n\n" - "vkCreateInstance Failure"); - ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE, - "Cannot find a specified extension library.\n" - "Make sure your layers path is set appropriately.\n" - "vkCreateInstance Failure"); - ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, - "vkCreateInstance failed.\n\n" - "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" - "Please look at the Getting Started guide for additional information.\n" - "vkCreateInstance Failure"); + if (vulkan_hooks) { + if (!vulkan_hooks->create_vulkan_instance(&inst_info, &inst)) { + return ERR_CANT_CREATE; + } + } else { + err = vkCreateInstance(&inst_info, nullptr, &inst); + ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE, + "Cannot find a compatible Vulkan installable client driver (ICD).\n\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE, + "Cannot find a specified extension library.\n" + "Make sure your layers path is set appropriately.\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, + "vkCreateInstance failed.\n\n" + "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" + "Please look at the Getting Started guide for additional information.\n" + "vkCreateInstance Failure"); + } inst_initialized = true; @@ -684,10 +725,85 @@ Error VulkanContext::_create_physical_device() { volkLoadInstance(inst); #endif + if (enabled_debug_utils) { + // Setup VK_EXT_debug_utils function pointers always (we use them for + // debug labels and names). + CreateDebugUtilsMessengerEXT = + (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugUtilsMessengerEXT"); + DestroyDebugUtilsMessengerEXT = + (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugUtilsMessengerEXT"); + SubmitDebugUtilsMessageEXT = + (PFN_vkSubmitDebugUtilsMessageEXT)vkGetInstanceProcAddr(inst, "vkSubmitDebugUtilsMessageEXT"); + CmdBeginDebugUtilsLabelEXT = + (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdBeginDebugUtilsLabelEXT"); + CmdEndDebugUtilsLabelEXT = + (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdEndDebugUtilsLabelEXT"); + CmdInsertDebugUtilsLabelEXT = + (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdInsertDebugUtilsLabelEXT"); + SetDebugUtilsObjectNameEXT = + (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(inst, "vkSetDebugUtilsObjectNameEXT"); + if (nullptr == CreateDebugUtilsMessengerEXT || nullptr == DestroyDebugUtilsMessengerEXT || + nullptr == SubmitDebugUtilsMessageEXT || nullptr == CmdBeginDebugUtilsLabelEXT || + nullptr == CmdEndDebugUtilsLabelEXT || nullptr == CmdInsertDebugUtilsLabelEXT || + nullptr == SetDebugUtilsObjectNameEXT) { + ERR_FAIL_V_MSG(ERR_CANT_CREATE, + "GetProcAddr: Failed to init VK_EXT_debug_utils\n" + "GetProcAddr: Failure"); + } + + err = CreateDebugUtilsMessengerEXT(inst, &dbg_messenger_create_info, nullptr, &dbg_messenger); + switch (err) { + case VK_SUCCESS: + break; + case VK_ERROR_OUT_OF_HOST_MEMORY: + ERR_FAIL_V_MSG(ERR_CANT_CREATE, + "CreateDebugUtilsMessengerEXT: out of host memory\n" + "CreateDebugUtilsMessengerEXT Failure"); + break; + default: + ERR_FAIL_V_MSG(ERR_CANT_CREATE, + "CreateDebugUtilsMessengerEXT: unknown failure\n" + "CreateDebugUtilsMessengerEXT Failure"); + ERR_FAIL_V(ERR_CANT_CREATE); + break; + } + } else if (enabled_debug_report) { + CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugReportCallbackEXT"); + DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(inst, "vkDebugReportMessageEXT"); + DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugReportCallbackEXT"); + + if (nullptr == CreateDebugReportCallbackEXT || nullptr == DebugReportMessageEXT || nullptr == DestroyDebugReportCallbackEXT) { + ERR_FAIL_V_MSG(ERR_CANT_CREATE, + "GetProcAddr: Failed to init VK_EXT_debug_report\n" + "GetProcAddr: Failure"); + } + + err = CreateDebugReportCallbackEXT(inst, &dbg_report_callback_create_info, nullptr, &dbg_debug_report); + switch (err) { + case VK_SUCCESS: + break; + case VK_ERROR_OUT_OF_HOST_MEMORY: + ERR_FAIL_V_MSG(ERR_CANT_CREATE, + "CreateDebugReportCallbackEXT: out of host memory\n" + "CreateDebugReportCallbackEXT Failure"); + break; + default: + ERR_FAIL_V_MSG(ERR_CANT_CREATE, + "CreateDebugReportCallbackEXT: unknown failure\n" + "CreateDebugReportCallbackEXT Failure"); + ERR_FAIL_V(ERR_CANT_CREATE); + break; + } + } + + return OK; +} + +Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { /* Make initial call to query gpu_count, then second call for gpu info*/ - err = vkEnumeratePhysicalDevices(inst, &gpu_count, nullptr); + uint32_t gpu_count = 0; + VkResult err = vkEnumeratePhysicalDevices(inst, &gpu_count, nullptr); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - ERR_FAIL_COND_V_MSG(gpu_count == 0, ERR_CANT_CREATE, "vkEnumeratePhysicalDevices reported zero accessible devices.\n\n" "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" @@ -700,25 +816,136 @@ Error VulkanContext::_create_physical_device() { ERR_FAIL_V(ERR_CANT_CREATE); } - // TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances. - // The device should really be a preference, but for now choosing a discrete GPU over the - // integrated one is better than the default. + static const struct { + uint32_t id; + const char *name; + } vendor_names[] = { + { 0x1002, "AMD" }, + { 0x1010, "ImgTec" }, + { 0x106B, "Apple" }, + { 0x10DE, "NVIDIA" }, + { 0x13B5, "ARM" }, + { 0x5143, "Qualcomm" }, + { 0x8086, "Intel" }, + { 0, nullptr }, + }; - // Default to first device - uint32_t device_index = 0; + int32_t device_index = -1; + if (vulkan_hooks) { + if (!vulkan_hooks->get_physical_device(&gpu)) { + return ERR_CANT_CREATE; + } - for (uint32_t i = 0; i < gpu_count; ++i) { - VkPhysicalDeviceProperties props; - vkGetPhysicalDeviceProperties(physical_devices[i], &props); + // not really needed but nice to print the correct entry + for (uint32_t i = 0; i < gpu_count; ++i) { + if (physical_devices[i] == gpu) { + device_index = i; + break; + } + } + } else { + // TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances. + // The device should really be a preference, but for now choosing a discrete GPU over the + // integrated one is better than the default. + + int type_selected = -1; + print_verbose("Vulkan devices:"); + for (uint32_t i = 0; i < gpu_count; ++i) { + VkPhysicalDeviceProperties props; + vkGetPhysicalDeviceProperties(physical_devices[i], &props); + + bool present_supported = false; + + uint32_t device_queue_family_count = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr); + VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties)); + vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props); + for (uint32_t j = 0; j < device_queue_family_count; j++) { + VkBool32 supports; + vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, p_surface, &supports); + if (supports && ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)) { + present_supported = true; + } else { + continue; + } + } + String name = props.deviceName; + String vendor = "Unknown"; + String dev_type; + switch (props.deviceType) { + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { + dev_type = "Discrete"; + } break; + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { + dev_type = "Integrated"; + } break; + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { + dev_type = "Virtual"; + } break; + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: { + dev_type = "CPU"; + } break; + default: { + dev_type = "Other"; + } break; + } + uint32_t vendor_idx = 0; + while (vendor_names[vendor_idx].name != nullptr) { + if (props.vendorID == vendor_names[vendor_idx].id) { + vendor = vendor_names[vendor_idx].name; + break; + } + vendor_idx++; + } + free(device_queue_props); + print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type); + + if (present_supported) { // Select first supported device of preferred type: Discrete > Integrated > Virtual > CPU > Other. + switch (props.deviceType) { + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { + if (type_selected < 4) { + type_selected = 4; + device_index = i; + } + } break; + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { + if (type_selected < 3) { + type_selected = 3; + device_index = i; + } + } break; + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { + if (type_selected < 2) { + type_selected = 2; + device_index = i; + } + } break; + case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: { + if (type_selected < 1) { + type_selected = 1; + device_index = i; + } + } break; + default: { + if (type_selected < 0) { + type_selected = 0; + device_index = i; + } + } break; + } + } + } - if (props.deviceType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { - // Prefer discrete GPU. - device_index = i; - break; + int32_t user_device_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU. + if (user_device_index >= 0 && user_device_index < (int32_t)gpu_count) { + device_index = user_device_index; } + + ERR_FAIL_COND_V_MSG(device_index == -1, ERR_CANT_CREATE, "None of Vulkan devices supports both graphics and present queues."); + + gpu = physical_devices[device_index]; } - gpu = physical_devices[device_index]; free(physical_devices); /* Look for device extensions */ @@ -730,20 +957,8 @@ Error VulkanContext::_create_physical_device() { /* Get identifier properties */ vkGetPhysicalDeviceProperties(gpu, &gpu_props); - static const struct { - uint32_t id; - const char *name; - } vendor_names[] = { - { 0x1002, "AMD" }, - { 0x1010, "ImgTec" }, - { 0x106B, "Apple" }, - { 0x10DE, "NVIDIA" }, - { 0x13B5, "ARM" }, - { 0x5143, "Qualcomm" }, - { 0x8086, "Intel" }, - { 0, nullptr }, - }; device_name = gpu_props.deviceName; + device_type = gpu_props.deviceType; pipeline_cache_id = String::hex_encode_buffer(gpu_props.pipelineCacheUUID, VK_UUID_SIZE); pipeline_cache_id += "-driver-" + itos(gpu_props.driverVersion); { @@ -834,77 +1049,6 @@ Error VulkanContext::_create_physical_device() { " extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\n" "vkCreateInstance Failure"); - if (enabled_debug_utils) { - // Setup VK_EXT_debug_utils function pointers always (we use them for - // debug labels and names). - CreateDebugUtilsMessengerEXT = - (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugUtilsMessengerEXT"); - DestroyDebugUtilsMessengerEXT = - (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugUtilsMessengerEXT"); - SubmitDebugUtilsMessageEXT = - (PFN_vkSubmitDebugUtilsMessageEXT)vkGetInstanceProcAddr(inst, "vkSubmitDebugUtilsMessageEXT"); - CmdBeginDebugUtilsLabelEXT = - (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdBeginDebugUtilsLabelEXT"); - CmdEndDebugUtilsLabelEXT = - (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdEndDebugUtilsLabelEXT"); - CmdInsertDebugUtilsLabelEXT = - (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdInsertDebugUtilsLabelEXT"); - SetDebugUtilsObjectNameEXT = - (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(inst, "vkSetDebugUtilsObjectNameEXT"); - if (nullptr == CreateDebugUtilsMessengerEXT || nullptr == DestroyDebugUtilsMessengerEXT || - nullptr == SubmitDebugUtilsMessageEXT || nullptr == CmdBeginDebugUtilsLabelEXT || - nullptr == CmdEndDebugUtilsLabelEXT || nullptr == CmdInsertDebugUtilsLabelEXT || - nullptr == SetDebugUtilsObjectNameEXT) { - ERR_FAIL_V_MSG(ERR_CANT_CREATE, - "GetProcAddr: Failed to init VK_EXT_debug_utils\n" - "GetProcAddr: Failure"); - } - - err = CreateDebugUtilsMessengerEXT(inst, &dbg_messenger_create_info, nullptr, &dbg_messenger); - switch (err) { - case VK_SUCCESS: - break; - case VK_ERROR_OUT_OF_HOST_MEMORY: - ERR_FAIL_V_MSG(ERR_CANT_CREATE, - "CreateDebugUtilsMessengerEXT: out of host memory\n" - "CreateDebugUtilsMessengerEXT Failure"); - break; - default: - ERR_FAIL_V_MSG(ERR_CANT_CREATE, - "CreateDebugUtilsMessengerEXT: unknown failure\n" - "CreateDebugUtilsMessengerEXT Failure"); - ERR_FAIL_V(ERR_CANT_CREATE); - break; - } - } else if (enabled_debug_report) { - CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugReportCallbackEXT"); - DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(inst, "vkDebugReportMessageEXT"); - DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugReportCallbackEXT"); - - if (nullptr == CreateDebugReportCallbackEXT || nullptr == DebugReportMessageEXT || nullptr == DestroyDebugReportCallbackEXT) { - ERR_FAIL_V_MSG(ERR_CANT_CREATE, - "GetProcAddr: Failed to init VK_EXT_debug_report\n" - "GetProcAddr: Failure"); - } - - err = CreateDebugReportCallbackEXT(inst, &dbg_report_callback_create_info, nullptr, &dbg_debug_report); - switch (err) { - case VK_SUCCESS: - break; - case VK_ERROR_OUT_OF_HOST_MEMORY: - ERR_FAIL_V_MSG(ERR_CANT_CREATE, - "CreateDebugReportCallbackEXT: out of host memory\n" - "CreateDebugReportCallbackEXT Failure"); - break; - default: - ERR_FAIL_V_MSG(ERR_CANT_CREATE, - "CreateDebugReportCallbackEXT: unknown failure\n" - "CreateDebugReportCallbackEXT Failure"); - ERR_FAIL_V(ERR_CANT_CREATE); - break; - } - } - /* Call with nullptr data to get count */ vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr); ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE); @@ -940,6 +1084,7 @@ Error VulkanContext::_create_physical_device() { } } + device_initialized = true; return OK; } @@ -954,9 +1099,61 @@ Error VulkanContext::_create_device() { queues[0].pQueuePriorities = queue_priorities; queues[0].flags = 0; + // Before we retrieved what is supported, here we tell Vulkan we want to enable these features using the same structs. + void *nextptr = nullptr; + + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, + /*pNext*/ nextptr, + /*shaderFloat16*/ shader_capabilities.shader_float16_is_supported, + /*shaderInt8*/ shader_capabilities.shader_int8_is_supported, + }; + nextptr = &shader_features; + + VkPhysicalDeviceVulkan11Features vulkan11features; + VkPhysicalDevice16BitStorageFeaturesKHR storage_feature; + VkPhysicalDeviceMultiviewFeatures multiview_features; + if (vulkan_major > 1 || vulkan_minor >= 2) { + // In Vulkan 1.2 and newer we use a newer struct to enable various features + + vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; + vulkan11features.pNext = nextptr; + vulkan11features.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported; + vulkan11features.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported; + vulkan11features.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported; + vulkan11features.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16; + vulkan11features.multiview = multiview_capabilities.is_supported; + vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; + vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; + vulkan11features.variablePointersStorageBuffer = 0; + vulkan11features.variablePointers = 0; + vulkan11features.protectedMemory = 0; + vulkan11features.samplerYcbcrConversion = 0; + vulkan11features.shaderDrawParameters = 0; + nextptr = &vulkan11features; + } else { + // On Vulkan 1.0 and 1.1 we use our older structs to initialise these features + storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR; + storage_feature.pNext = nextptr; + storage_feature.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported; + storage_feature.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported; + storage_feature.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported; + storage_feature.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16; + nextptr = &storage_feature; + + if (vulkan_major == 1 && vulkan_minor == 1) { + multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; + multiview_features.pNext = nextptr; + multiview_features.multiview = multiview_capabilities.is_supported; + multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; + multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; + nextptr = &multiview_features; + } + } + VkDeviceCreateInfo sdevice = { /*sType*/ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - /*pNext*/ nullptr, + /*pNext*/ nextptr, /*flags*/ 0, /*queueCreateInfoCount*/ 1, /*pQueueCreateInfos*/ queues, @@ -965,7 +1162,6 @@ Error VulkanContext::_create_device() { /*enabledExtensionCount*/ enabled_extension_count, /*ppEnabledExtensionNames*/ (const char *const *)extension_names, /*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here - }; if (separate_present_queue) { queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; @@ -977,39 +1173,15 @@ Error VulkanContext::_create_device() { sdevice.queueCreateInfoCount = 2; } - VkPhysicalDeviceVulkan11Features vulkan11features; - VkPhysicalDeviceMultiviewFeatures multiview_features; - if (vulkan_major > 1 || vulkan_minor >= 2) { - vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; - vulkan11features.pNext = nullptr; - // !BAS! Need to figure out which ones of these we want enabled... - vulkan11features.storageBuffer16BitAccess = 0; - vulkan11features.uniformAndStorageBuffer16BitAccess = 0; - vulkan11features.storagePushConstant16 = 0; - vulkan11features.storageInputOutput16 = 0; - vulkan11features.multiview = multiview_capabilities.is_supported; - vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; - vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; - vulkan11features.variablePointersStorageBuffer = 0; - vulkan11features.variablePointers = 0; - vulkan11features.protectedMemory = 0; - vulkan11features.samplerYcbcrConversion = 0; - vulkan11features.shaderDrawParameters = 0; - - sdevice.pNext = &vulkan11features; - } else if (vulkan_major == 1 && vulkan_minor == 1) { - multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - multiview_features.pNext = nullptr; - multiview_features.multiview = multiview_capabilities.is_supported; - multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; - multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; - - sdevice.pNext = &multiview_features; + if (vulkan_hooks) { + if (!vulkan_hooks->create_vulkan_device(&sdevice, &device)) { + return ERR_CANT_CREATE; + } + } else { + err = vkCreateDevice(gpu, &sdevice, nullptr, &device); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); } - err = vkCreateDevice(gpu, &sdevice, nullptr, &device); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - return OK; } @@ -1192,25 +1364,17 @@ bool VulkanContext::_use_validation_layers() { Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height) { ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER); + if (!device_initialized) { + Error err = _create_physical_device(p_surface); + ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); + } + if (!queues_initialized) { // We use a single GPU, but we need a surface to initialize the // queues, so this process must be deferred until a surface // is created. Error err = _initialize_queues(p_surface); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); - } else { - // make sure any of the surfaces supports present (validation layer complains if this is not done). - bool any_supports_present = false; - for (uint32_t i = 0; i < queue_family_count; i++) { - VkBool32 supports; - fpGetPhysicalDeviceSurfaceSupportKHR(gpu, i, p_surface, &supports); - if (supports) { - any_supports_present = true; - break; - } - } - - ERR_FAIL_COND_V_MSG(!any_supports_present, ERR_CANT_CREATE, "Surface passed for sub-window creation does not support presenting"); } Window window; @@ -1253,6 +1417,12 @@ int VulkanContext::window_get_height(DisplayServer::WindowID p_window) { return windows[p_window].height; } +bool VulkanContext::window_is_valid_swapchain(DisplayServer::WindowID p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), false); + Window *w = &windows[p_window]; + return w->swapchain_image_resources != VK_NULL_HANDLE; +} + VkRenderPass VulkanContext::window_get_render_pass(DisplayServer::WindowID p_window) { ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE); Window *w = &windows[p_window]; @@ -1265,7 +1435,11 @@ VkFramebuffer VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_wi ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE); Window *w = &windows[p_window]; //vulkan use of currentbuffer - return w->swapchain_image_resources[w->current_buffer].framebuffer; + if (w->swapchain_image_resources != VK_NULL_HANDLE) { + return w->swapchain_image_resources[w->current_buffer].framebuffer; + } else { + return VK_NULL_HANDLE; + } } void VulkanContext::window_destroy(DisplayServer::WindowID p_window_id) { @@ -1677,12 +1851,12 @@ Error VulkanContext::initialize() { return FAILED; } #endif - Error err = _create_physical_device(); - if (err) { + + Error err = _create_instance(); + if (err != OK) { return err; } - device_initialized = true; return OK; } @@ -1835,24 +2009,25 @@ Error VulkanContext::swap_buffers() { } VkSemaphore *semaphores_to_acquire = (VkSemaphore *)alloca(windows.size() * sizeof(VkSemaphore)); + VkPipelineStageFlags *pipe_stage_flags = (VkPipelineStageFlags *)alloca(windows.size() * sizeof(VkPipelineStageFlags)); uint32_t semaphores_to_acquire_count = 0; for (KeyValue<int, Window> &E : windows) { Window *w = &E.value; if (w->semaphore_acquired) { - semaphores_to_acquire[semaphores_to_acquire_count++] = w->image_acquired_semaphores[frame_index]; + semaphores_to_acquire[semaphores_to_acquire_count] = w->image_acquired_semaphores[frame_index]; + pipe_stage_flags[semaphores_to_acquire_count] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + semaphores_to_acquire_count++; } } - VkPipelineStageFlags pipe_stage_flags; VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = nullptr; - submit_info.pWaitDstStageMask = &pipe_stage_flags; - pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; submit_info.waitSemaphoreCount = semaphores_to_acquire_count; submit_info.pWaitSemaphores = semaphores_to_acquire; + submit_info.pWaitDstStageMask = pipe_stage_flags; submit_info.commandBufferCount = commands_to_submit; submit_info.pCommandBuffers = commands_ptr; submit_info.signalSemaphoreCount = 1; @@ -1868,7 +2043,7 @@ Error VulkanContext::swap_buffers() { // present queue before presenting, waiting for the draw complete // semaphore and signalling the ownership released semaphore when finished VkFence nullFence = VK_NULL_HANDLE; - pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index]; submit_info.commandBufferCount = 0; @@ -2192,6 +2367,11 @@ String VulkanContext::get_device_vendor_name() const { String VulkanContext::get_device_name() const { return device_name; } + +RenderingDevice::DeviceType VulkanContext::get_device_type() const { + return RenderingDevice::DeviceType(device_type); +} + String VulkanContext::get_device_pipeline_cache_uuid() const { return pipeline_cache_id; } |