feat: godot-engine-source-4.3-stable
This commit is contained in:
parent
c59a7dcade
commit
7125d019b5
11149 changed files with 5070401 additions and 0 deletions
64
engine/drivers/vulkan/SCsub
Normal file
64
engine/drivers/vulkan/SCsub
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
|
||||
thirdparty_obj = []
|
||||
thirdparty_dir = "#thirdparty/vulkan"
|
||||
thirdparty_volk_dir = "#thirdparty/volk"
|
||||
|
||||
# Use bundled Vulkan headers
|
||||
env.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "/include"])
|
||||
|
||||
if env["use_volk"]:
|
||||
env.AppendUnique(CPPDEFINES=["USE_VOLK"])
|
||||
env.Prepend(CPPPATH=[thirdparty_volk_dir])
|
||||
|
||||
if env["platform"] == "android":
|
||||
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_ANDROID_KHR"])
|
||||
elif env["platform"] == "ios":
|
||||
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_IOS_MVK", "VK_USE_PLATFORM_METAL_EXT"])
|
||||
elif env["platform"] == "linuxbsd":
|
||||
if env["x11"]:
|
||||
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_XLIB_KHR"])
|
||||
if env["wayland"]:
|
||||
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_WAYLAND_KHR"])
|
||||
elif env["platform"] == "macos":
|
||||
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_MACOS_MVK", "VK_USE_PLATFORM_METAL_EXT"])
|
||||
elif env["platform"] == "windows":
|
||||
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_WIN32_KHR"])
|
||||
|
||||
# Build Vulkan memory allocator and volk
|
||||
env_thirdparty_vma = env.Clone()
|
||||
env_thirdparty_vma.disable_warnings()
|
||||
thirdparty_sources_vma = [thirdparty_dir + "/vk_mem_alloc.cpp"]
|
||||
|
||||
if env["use_volk"]:
|
||||
env_thirdparty_vma.AppendUnique(CPPDEFINES=["VMA_STATIC_VULKAN_FUNCTIONS=1"])
|
||||
env_thirdparty_volk = env.Clone()
|
||||
env_thirdparty_volk.disable_warnings()
|
||||
|
||||
thirdparty_sources_volk = [thirdparty_volk_dir + "/volk.c"]
|
||||
env_thirdparty_volk.add_source_files(thirdparty_obj, thirdparty_sources_volk)
|
||||
elif env["platform"] == "android":
|
||||
# Our current NDK version only provides old Vulkan headers,
|
||||
# so we have to limit VMA.
|
||||
env_thirdparty_vma.AppendUnique(CPPDEFINES=["VMA_VULKAN_VERSION=1000000"])
|
||||
elif env["platform"] == "macos" or env["platform"] == "ios":
|
||||
# MoltenVK supports only Vulkan 1.1 API, limit VMA to the same version.
|
||||
env_thirdparty_vma.AppendUnique(CPPDEFINES=["VMA_VULKAN_VERSION=1001000"])
|
||||
|
||||
env_thirdparty_vma.add_source_files(thirdparty_obj, thirdparty_sources_vma)
|
||||
|
||||
|
||||
env.drivers_sources += thirdparty_obj
|
||||
|
||||
|
||||
# Godot source files
|
||||
|
||||
driver_obj = []
|
||||
|
||||
env.add_source_files(driver_obj, "*.cpp")
|
||||
env.drivers_sources += driver_obj
|
||||
|
||||
# Needed to force rebuilding the driver files when the thirdparty code is updated.
|
||||
env.Depends(driver_obj, thirdparty_obj)
|
||||
723
engine/drivers/vulkan/rendering_context_driver_vulkan.cpp
Normal file
723
engine/drivers/vulkan/rendering_context_driver_vulkan.cpp
Normal file
|
|
@ -0,0 +1,723 @@
|
|||
/**************************************************************************/
|
||||
/* rendering_context_driver_vulkan.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifdef VULKAN_ENABLED
|
||||
|
||||
#include "rendering_context_driver_vulkan.h"
|
||||
|
||||
#include "vk_enum_string_helper.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/version.h"
|
||||
|
||||
#include "rendering_device_driver_vulkan.h"
|
||||
#include "vulkan_hooks.h"
|
||||
|
||||
RenderingContextDriverVulkan::RenderingContextDriverVulkan() {
|
||||
// Empty constructor.
|
||||
}
|
||||
|
||||
RenderingContextDriverVulkan::~RenderingContextDriverVulkan() {
|
||||
if (debug_messenger != VK_NULL_HANDLE && functions.DestroyDebugUtilsMessengerEXT != nullptr) {
|
||||
functions.DestroyDebugUtilsMessengerEXT(instance, debug_messenger, nullptr);
|
||||
}
|
||||
|
||||
if (debug_report != VK_NULL_HANDLE && functions.DestroyDebugReportCallbackEXT != nullptr) {
|
||||
functions.DestroyDebugReportCallbackEXT(instance, debug_report, nullptr);
|
||||
}
|
||||
|
||||
if (instance != VK_NULL_HANDLE) {
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Error RenderingContextDriverVulkan::_initialize_vulkan_version() {
|
||||
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html#_description
|
||||
// For Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android.
|
||||
typedef VkResult(VKAPI_PTR * _vkEnumerateInstanceVersion)(uint32_t *);
|
||||
_vkEnumerateInstanceVersion func = (_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion");
|
||||
if (func != nullptr) {
|
||||
uint32_t api_version;
|
||||
VkResult res = func(&api_version);
|
||||
if (res == VK_SUCCESS) {
|
||||
instance_api_version = 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.
|
||||
ERR_FAIL_V(ERR_CANT_CREATE);
|
||||
}
|
||||
} else {
|
||||
print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0.");
|
||||
instance_api_version = VK_API_VERSION_1_0;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void RenderingContextDriverVulkan::_register_requested_instance_extension(const CharString &p_extension_name, bool p_required) {
|
||||
ERR_FAIL_COND(requested_instance_extensions.has(p_extension_name));
|
||||
requested_instance_extensions[p_extension_name] = p_required;
|
||||
}
|
||||
|
||||
Error RenderingContextDriverVulkan::_initialize_instance_extensions() {
|
||||
enabled_instance_extension_names.clear();
|
||||
|
||||
// The surface extension and the platform-specific surface extension are core requirements.
|
||||
_register_requested_instance_extension(VK_KHR_SURFACE_EXTENSION_NAME, true);
|
||||
if (_get_platform_surface_extension()) {
|
||||
_register_requested_instance_extension(_get_platform_surface_extension(), true);
|
||||
}
|
||||
|
||||
if (_use_validation_layers()) {
|
||||
_register_requested_instance_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false);
|
||||
}
|
||||
|
||||
// This extension allows us to use the properties2 features to query additional device capabilities.
|
||||
_register_requested_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false);
|
||||
|
||||
#if defined(USE_VOLK) && (defined(MACOS_ENABLED) || defined(IOS_ENABLED))
|
||||
_register_requested_instance_extension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, true);
|
||||
#endif
|
||||
|
||||
// Only enable debug utils in verbose mode or DEV_ENABLED.
|
||||
// End users would get spammed with messages of varying verbosity due to the
|
||||
// mess that thirdparty layers/extensions and drivers seem to leave in their
|
||||
// wake, making the Windows registry a bottomless pit of broken layer JSON.
|
||||
#ifdef DEV_ENABLED
|
||||
bool want_debug_utils = true;
|
||||
#else
|
||||
bool want_debug_utils = OS::get_singleton()->is_stdout_verbose();
|
||||
#endif
|
||||
if (want_debug_utils) {
|
||||
_register_requested_instance_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false);
|
||||
}
|
||||
|
||||
// Load instance extensions that are available.
|
||||
uint32_t instance_extension_count = 0;
|
||||
VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr);
|
||||
ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, ERR_CANT_CREATE);
|
||||
ERR_FAIL_COND_V_MSG(instance_extension_count == 0, ERR_CANT_CREATE, "No instance extensions were found.");
|
||||
|
||||
TightLocalVector<VkExtensionProperties> instance_extensions;
|
||||
instance_extensions.resize(instance_extension_count);
|
||||
err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions.ptr());
|
||||
if (err != VK_SUCCESS && err != VK_INCOMPLETE) {
|
||||
ERR_FAIL_V(ERR_CANT_CREATE);
|
||||
}
|
||||
|
||||
#ifdef DEV_ENABLED
|
||||
for (uint32_t i = 0; i < instance_extension_count; i++) {
|
||||
print_verbose(String("VULKAN: Found instance extension ") + String::utf8(instance_extensions[i].extensionName) + String("."));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Enable all extensions that are supported and requested.
|
||||
for (uint32_t i = 0; i < instance_extension_count; i++) {
|
||||
CharString extension_name(instance_extensions[i].extensionName);
|
||||
if (requested_instance_extensions.has(extension_name)) {
|
||||
enabled_instance_extension_names.insert(extension_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Now check our requested extensions.
|
||||
for (KeyValue<CharString, bool> &requested_extension : requested_instance_extensions) {
|
||||
if (!enabled_instance_extension_names.has(requested_extension.key)) {
|
||||
if (requested_extension.value) {
|
||||
ERR_FAIL_V_MSG(ERR_BUG, String("Required extension ") + String::utf8(requested_extension.key) + String(" not found."));
|
||||
} else {
|
||||
print_verbose(String("Optional extension ") + String::utf8(requested_extension.key) + String(" not found."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error RenderingContextDriverVulkan::_find_validation_layers(TightLocalVector<const char *> &r_layer_names) const {
|
||||
r_layer_names.clear();
|
||||
|
||||
uint32_t instance_layer_count = 0;
|
||||
VkResult err = vkEnumerateInstanceLayerProperties(&instance_layer_count, nullptr);
|
||||
ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
|
||||
if (instance_layer_count > 0) {
|
||||
TightLocalVector<VkLayerProperties> layer_properties;
|
||||
layer_properties.resize(instance_layer_count);
|
||||
err = vkEnumerateInstanceLayerProperties(&instance_layer_count, layer_properties.ptr());
|
||||
ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
|
||||
|
||||
// Preferred set of validation layers.
|
||||
const std::initializer_list<const char *> preferred = { "VK_LAYER_KHRONOS_validation" };
|
||||
|
||||
// Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers.
|
||||
const std::initializer_list<const char *> lunarg = { "VK_LAYER_LUNARG_standard_validation" };
|
||||
|
||||
// Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers.
|
||||
const std::initializer_list<const char *> google = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" };
|
||||
|
||||
// Verify all the layers of the list are present.
|
||||
for (const std::initializer_list<const char *> &list : { preferred, lunarg, google }) {
|
||||
bool layers_found = false;
|
||||
for (const char *layer_name : list) {
|
||||
layers_found = false;
|
||||
|
||||
for (const VkLayerProperties &properties : layer_properties) {
|
||||
if (!strcmp(properties.layerName, layer_name)) {
|
||||
layers_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!layers_found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (layers_found) {
|
||||
r_layer_names.reserve(list.size());
|
||||
for (const char *layer_name : list) {
|
||||
r_layer_names.push_back(layer_name);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL RenderingContextDriverVulkan::_debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, VkDebugUtilsMessageTypeFlagsEXT p_message_type, const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data) {
|
||||
// This error needs to be ignored because the AMD allocator will mix up memory types on IGP processors.
|
||||
if (strstr(p_callback_data->pMessage, "Mapping an image with layout") != nullptr && strstr(p_callback_data->pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
// This needs to be ignored because Validator is wrong here.
|
||||
if (strstr(p_callback_data->pMessage, "Invalid SPIR-V binary version 1.3") != nullptr) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
// This needs to be ignored because Validator is wrong here.
|
||||
if (strstr(p_callback_data->pMessage, "Shader requires flag") != nullptr) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
// This needs to be ignored because Validator is wrong here.
|
||||
if (strstr(p_callback_data->pMessage, "SPIR-V module not valid: Pointer operand") != nullptr && strstr(p_callback_data->pMessage, "must be a memory object") != nullptr) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
if (p_callback_data->pMessageIdName && strstr(p_callback_data->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != nullptr) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
String type_string;
|
||||
switch (p_message_type) {
|
||||
case (VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT):
|
||||
type_string = "GENERAL";
|
||||
break;
|
||||
case (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT):
|
||||
type_string = "VALIDATION";
|
||||
break;
|
||||
case (VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT):
|
||||
type_string = "PERFORMANCE";
|
||||
break;
|
||||
case (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT):
|
||||
type_string = "VALIDATION|PERFORMANCE";
|
||||
break;
|
||||
}
|
||||
|
||||
String objects_string;
|
||||
if (p_callback_data->objectCount > 0) {
|
||||
objects_string = "\n\tObjects - " + String::num_int64(p_callback_data->objectCount);
|
||||
for (uint32_t object = 0; object < p_callback_data->objectCount; ++object) {
|
||||
objects_string +=
|
||||
"\n\t\tObject[" + String::num_int64(object) + "]" +
|
||||
" - " + string_VkObjectType(p_callback_data->pObjects[object].objectType) +
|
||||
", Handle " + String::num_int64(p_callback_data->pObjects[object].objectHandle);
|
||||
|
||||
if (p_callback_data->pObjects[object].pObjectName != nullptr && strlen(p_callback_data->pObjects[object].pObjectName) > 0) {
|
||||
objects_string += ", Name \"" + String(p_callback_data->pObjects[object].pObjectName) + "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String labels_string;
|
||||
if (p_callback_data->cmdBufLabelCount > 0) {
|
||||
labels_string = "\n\tCommand Buffer Labels - " + String::num_int64(p_callback_data->cmdBufLabelCount);
|
||||
for (uint32_t cmd_buf_label = 0; cmd_buf_label < p_callback_data->cmdBufLabelCount; ++cmd_buf_label) {
|
||||
labels_string +=
|
||||
"\n\t\tLabel[" + String::num_int64(cmd_buf_label) + "]" +
|
||||
" - " + p_callback_data->pCmdBufLabels[cmd_buf_label].pLabelName +
|
||||
"{ ";
|
||||
|
||||
for (int color_idx = 0; color_idx < 4; ++color_idx) {
|
||||
labels_string += String::num(p_callback_data->pCmdBufLabels[cmd_buf_label].color[color_idx]);
|
||||
if (color_idx < 3) {
|
||||
labels_string += ", ";
|
||||
}
|
||||
}
|
||||
|
||||
labels_string += " }";
|
||||
}
|
||||
}
|
||||
|
||||
String error_message(type_string +
|
||||
" - Message Id Number: " + String::num_int64(p_callback_data->messageIdNumber) +
|
||||
" | Message Id Name: " + p_callback_data->pMessageIdName +
|
||||
"\n\t" + p_callback_data->pMessage +
|
||||
objects_string + labels_string);
|
||||
|
||||
// Convert VK severity to our own log macros.
|
||||
switch (p_message_severity) {
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
|
||||
print_verbose(error_message);
|
||||
break;
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
|
||||
print_line(error_message);
|
||||
break;
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
|
||||
WARN_PRINT(error_message);
|
||||
break;
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
||||
ERR_PRINT(error_message);
|
||||
CRASH_COND_MSG(Engine::get_singleton()->is_abort_on_gpu_errors_enabled(), "Crashing, because abort on GPU errors is enabled.");
|
||||
break;
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT:
|
||||
break; // Shouldn't happen, only handling to make compilers happy.
|
||||
}
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL RenderingContextDriverVulkan::_debug_report_callback(VkDebugReportFlagsEXT p_flags, VkDebugReportObjectTypeEXT p_object_type, uint64_t p_object, size_t p_location, int32_t p_message_code, const char *p_layer_prefix, const char *p_message, void *p_user_data) {
|
||||
String debug_message = String("Vulkan Debug Report: object - ") + String::num_int64(p_object) + "\n" + p_message;
|
||||
|
||||
switch (p_flags) {
|
||||
case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
|
||||
case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
|
||||
print_line(debug_message);
|
||||
break;
|
||||
case VK_DEBUG_REPORT_WARNING_BIT_EXT:
|
||||
case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
|
||||
WARN_PRINT(debug_message);
|
||||
break;
|
||||
case VK_DEBUG_REPORT_ERROR_BIT_EXT:
|
||||
ERR_PRINT(debug_message);
|
||||
break;
|
||||
}
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
Error RenderingContextDriverVulkan::_initialize_instance() {
|
||||
Error err;
|
||||
TightLocalVector<const char *> enabled_extension_names;
|
||||
enabled_extension_names.reserve(enabled_instance_extension_names.size());
|
||||
for (const CharString &extension_name : enabled_instance_extension_names) {
|
||||
enabled_extension_names.push_back(extension_name.ptr());
|
||||
}
|
||||
|
||||
// We'll set application version to the Vulkan version we're developing against, even if our instance is based on an older Vulkan
|
||||
// version, devices can still support newer versions of Vulkan. The exception is when we're on Vulkan 1.0, we should not set this
|
||||
// to anything but 1.0. Note that this value is only used by validation layers to warn us about version issues.
|
||||
uint32_t application_api_version = instance_api_version == VK_API_VERSION_1_0 ? VK_API_VERSION_1_0 : VK_API_VERSION_1_2;
|
||||
|
||||
CharString cs = GLOBAL_GET("application/config/name").operator String().utf8();
|
||||
VkApplicationInfo app_info = {};
|
||||
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
app_info.pApplicationName = cs.get_data();
|
||||
app_info.pEngineName = VERSION_NAME;
|
||||
app_info.engineVersion = VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
||||
app_info.apiVersion = application_api_version;
|
||||
|
||||
TightLocalVector<const char *> enabled_layer_names;
|
||||
if (_use_validation_layers()) {
|
||||
err = _find_validation_layers(enabled_layer_names);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
}
|
||||
|
||||
VkInstanceCreateInfo instance_info = {};
|
||||
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
|
||||
#if defined(USE_VOLK) && (defined(MACOS_ENABLED) || defined(IOS_ENABLED))
|
||||
instance_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
||||
#endif
|
||||
|
||||
instance_info.pApplicationInfo = &app_info;
|
||||
instance_info.enabledExtensionCount = enabled_extension_names.size();
|
||||
instance_info.ppEnabledExtensionNames = enabled_extension_names.ptr();
|
||||
instance_info.enabledLayerCount = enabled_layer_names.size();
|
||||
instance_info.ppEnabledLayerNames = enabled_layer_names.ptr();
|
||||
|
||||
// This is info for a temp callback to use during CreateInstance. After the instance is created, we use the instance-based function to register the final callback.
|
||||
VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info = {};
|
||||
VkDebugReportCallbackCreateInfoEXT debug_report_callback_create_info = {};
|
||||
const bool has_debug_utils_extension = enabled_instance_extension_names.has(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
const bool has_debug_report_extension = enabled_instance_extension_names.has(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
||||
if (has_debug_utils_extension) {
|
||||
debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||
debug_messenger_create_info.pNext = nullptr;
|
||||
debug_messenger_create_info.flags = 0;
|
||||
debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
debug_messenger_create_info.pfnUserCallback = _debug_messenger_callback;
|
||||
debug_messenger_create_info.pUserData = this;
|
||||
instance_info.pNext = &debug_messenger_create_info;
|
||||
} else if (has_debug_report_extension) {
|
||||
debug_report_callback_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
|
||||
debug_report_callback_create_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
|
||||
debug_report_callback_create_info.pfnCallback = _debug_report_callback;
|
||||
debug_report_callback_create_info.pUserData = this;
|
||||
instance_info.pNext = &debug_report_callback_create_info;
|
||||
}
|
||||
|
||||
err = _create_vulkan_instance(&instance_info, &instance);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
|
||||
#ifdef USE_VOLK
|
||||
volkLoadInstance(instance);
|
||||
#endif
|
||||
|
||||
// Physical device.
|
||||
if (enabled_instance_extension_names.has(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
|
||||
functions.GetPhysicalDeviceFeatures2 = PFN_vkGetPhysicalDeviceFeatures2(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
|
||||
functions.GetPhysicalDeviceProperties2 = PFN_vkGetPhysicalDeviceProperties2(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
|
||||
|
||||
// In Vulkan 1.0, the functions might be accessible under their original extension names.
|
||||
if (functions.GetPhysicalDeviceFeatures2 == nullptr) {
|
||||
functions.GetPhysicalDeviceFeatures2 = PFN_vkGetPhysicalDeviceFeatures2(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
|
||||
}
|
||||
|
||||
if (functions.GetPhysicalDeviceProperties2 == nullptr) {
|
||||
functions.GetPhysicalDeviceProperties2 = PFN_vkGetPhysicalDeviceProperties2(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
|
||||
}
|
||||
}
|
||||
|
||||
// Device.
|
||||
functions.GetDeviceProcAddr = PFN_vkGetDeviceProcAddr(vkGetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
|
||||
|
||||
// Surfaces.
|
||||
functions.GetPhysicalDeviceSurfaceSupportKHR = PFN_vkGetPhysicalDeviceSurfaceSupportKHR(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR"));
|
||||
functions.GetPhysicalDeviceSurfaceFormatsKHR = PFN_vkGetPhysicalDeviceSurfaceFormatsKHR(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"));
|
||||
functions.GetPhysicalDeviceSurfaceCapabilitiesKHR = PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
|
||||
functions.GetPhysicalDeviceSurfacePresentModesKHR = PFN_vkGetPhysicalDeviceSurfacePresentModesKHR(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"));
|
||||
|
||||
// Debug utils and report.
|
||||
if (has_debug_utils_extension) {
|
||||
// Setup VK_EXT_debug_utils function pointers always (we use them for debug labels and names).
|
||||
functions.CreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
||||
functions.DestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||
functions.CmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT");
|
||||
functions.CmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT");
|
||||
functions.SetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT");
|
||||
|
||||
if (!functions.debug_util_functions_available()) {
|
||||
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "GetProcAddr: Failed to init VK_EXT_debug_utils\nGetProcAddr: Failure");
|
||||
}
|
||||
|
||||
VkResult res = functions.CreateDebugUtilsMessengerEXT(instance, &debug_messenger_create_info, nullptr, &debug_messenger);
|
||||
switch (res) {
|
||||
case VK_SUCCESS:
|
||||
break;
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CreateDebugUtilsMessengerEXT: out of host memory\nCreateDebugUtilsMessengerEXT Failure");
|
||||
break;
|
||||
default:
|
||||
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CreateDebugUtilsMessengerEXT: unknown failure\nCreateDebugUtilsMessengerEXT Failure");
|
||||
break;
|
||||
}
|
||||
} else if (has_debug_report_extension) {
|
||||
functions.CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
|
||||
functions.DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(instance, "vkDebugReportMessageEXT");
|
||||
functions.DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
|
||||
|
||||
if (!functions.debug_report_functions_available()) {
|
||||
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "GetProcAddr: Failed to init VK_EXT_debug_report\nGetProcAddr: Failure");
|
||||
}
|
||||
|
||||
VkResult res = functions.CreateDebugReportCallbackEXT(instance, &debug_report_callback_create_info, nullptr, &debug_report);
|
||||
switch (res) {
|
||||
case VK_SUCCESS:
|
||||
break;
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CreateDebugReportCallbackEXT: out of host memory\nCreateDebugReportCallbackEXT Failure");
|
||||
break;
|
||||
default:
|
||||
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CreateDebugReportCallbackEXT: unknown failure\nCreateDebugReportCallbackEXT Failure");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error RenderingContextDriverVulkan::_initialize_devices() {
|
||||
if (VulkanHooks::get_singleton() != nullptr) {
|
||||
VkPhysicalDevice physical_device;
|
||||
bool device_retrieved = VulkanHooks::get_singleton()->get_physical_device(&physical_device);
|
||||
ERR_FAIL_COND_V(!device_retrieved, ERR_CANT_CREATE);
|
||||
|
||||
// When a hook is active, pretend the device returned by the hook is the only device available.
|
||||
driver_devices.resize(1);
|
||||
physical_devices.resize(1);
|
||||
device_queue_families.resize(1);
|
||||
physical_devices[0] = physical_device;
|
||||
|
||||
} else {
|
||||
uint32_t physical_device_count = 0;
|
||||
VkResult err = vkEnumeratePhysicalDevices(instance, &physical_device_count, nullptr);
|
||||
ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
|
||||
ERR_FAIL_COND_V_MSG(physical_device_count == 0, ERR_CANT_CREATE, "vkEnumeratePhysicalDevices reported zero accessible devices.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\nvkEnumeratePhysicalDevices Failure.");
|
||||
|
||||
driver_devices.resize(physical_device_count);
|
||||
physical_devices.resize(physical_device_count);
|
||||
device_queue_families.resize(physical_device_count);
|
||||
err = vkEnumeratePhysicalDevices(instance, &physical_device_count, physical_devices.ptr());
|
||||
ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
|
||||
}
|
||||
|
||||
// Fill the list of driver devices with the properties from the physical devices.
|
||||
for (uint32_t i = 0; i < physical_devices.size(); i++) {
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(physical_devices[i], &props);
|
||||
|
||||
Device &driver_device = driver_devices[i];
|
||||
driver_device.name = String::utf8(props.deviceName);
|
||||
driver_device.vendor = Vendor(props.vendorID);
|
||||
driver_device.type = DeviceType(props.deviceType);
|
||||
driver_device.workarounds = Workarounds();
|
||||
|
||||
_check_driver_workarounds(props, driver_device);
|
||||
|
||||
uint32_t queue_family_properties_count = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &queue_family_properties_count, nullptr);
|
||||
|
||||
if (queue_family_properties_count > 0) {
|
||||
device_queue_families[i].properties.resize(queue_family_properties_count);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &queue_family_properties_count, device_queue_families[i].properties.ptr());
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void RenderingContextDriverVulkan::_check_driver_workarounds(const VkPhysicalDeviceProperties &p_device_properties, Device &r_device) {
|
||||
// Workaround for the Adreno 6XX family of devices.
|
||||
//
|
||||
// There's a known issue with the Vulkan driver in this family of devices where it'll crash if a dynamic state for drawing is
|
||||
// used in a command buffer before a dispatch call is issued. As both dynamic scissor and viewport are basic requirements for
|
||||
// the engine to not bake this state into the PSO, the only known way to fix this issue is to reset the command buffer entirely.
|
||||
//
|
||||
// As the render graph has no built in limitations of whether it'll issue compute work before anything needs to draw on the
|
||||
// frame, and there's no guarantee that compute work will never be dependent on rasterization in the future, this workaround
|
||||
// will end recording on the current command buffer any time a compute list is encountered after a draw list was executed.
|
||||
// A new command buffer will be created afterwards and the appropriate synchronization primitives will be inserted.
|
||||
//
|
||||
// Executing this workaround has the added cost of synchronization between all the command buffers that are created as well as
|
||||
// all the individual submissions. This performance hit is accepted for the sake of being able to support these devices without
|
||||
// limiting the design of the renderer.
|
||||
//
|
||||
// This bug was fixed in driver version 512.503.0, so we only enabled it on devices older than this.
|
||||
//
|
||||
r_device.workarounds.avoid_compute_after_draw =
|
||||
r_device.vendor == VENDOR_QUALCOMM &&
|
||||
p_device_properties.deviceID >= 0x6000000 && // Adreno 6xx
|
||||
p_device_properties.driverVersion < VK_MAKE_VERSION(512, 503, 0) &&
|
||||
r_device.name.find("Turnip") < 0;
|
||||
}
|
||||
|
||||
bool RenderingContextDriverVulkan::_use_validation_layers() const {
|
||||
return Engine::get_singleton()->is_validation_layers_enabled();
|
||||
}
|
||||
|
||||
Error RenderingContextDriverVulkan::_create_vulkan_instance(const VkInstanceCreateInfo *p_create_info, VkInstance *r_instance) {
|
||||
if (VulkanHooks::get_singleton() != nullptr) {
|
||||
return VulkanHooks::get_singleton()->create_vulkan_instance(p_create_info, r_instance) ? OK : ERR_CANT_CREATE;
|
||||
} else {
|
||||
VkResult err = vkCreateInstance(p_create_info, nullptr, r_instance);
|
||||
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");
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error RenderingContextDriverVulkan::initialize() {
|
||||
Error err;
|
||||
|
||||
#ifdef USE_VOLK
|
||||
if (volkInitialize() != VK_SUCCESS) {
|
||||
return FAILED;
|
||||
}
|
||||
#endif
|
||||
|
||||
err = _initialize_vulkan_version();
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
|
||||
err = _initialize_instance_extensions();
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
|
||||
err = _initialize_instance();
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
|
||||
err = _initialize_devices();
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
const RenderingContextDriver::Device &RenderingContextDriverVulkan::device_get(uint32_t p_device_index) const {
|
||||
DEV_ASSERT(p_device_index < driver_devices.size());
|
||||
return driver_devices[p_device_index];
|
||||
}
|
||||
|
||||
uint32_t RenderingContextDriverVulkan::device_get_count() const {
|
||||
return driver_devices.size();
|
||||
}
|
||||
|
||||
bool RenderingContextDriverVulkan::device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const {
|
||||
DEV_ASSERT(p_device_index < physical_devices.size());
|
||||
|
||||
// Check if any of the queues supported by the device supports presenting to the window's surface.
|
||||
const VkPhysicalDevice physical_device = physical_devices[p_device_index];
|
||||
const DeviceQueueFamilies &queue_families = device_queue_families[p_device_index];
|
||||
for (uint32_t i = 0; i < queue_families.properties.size(); i++) {
|
||||
if ((queue_families.properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && queue_family_supports_present(physical_device, i, p_surface)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderingDeviceDriver *RenderingContextDriverVulkan::driver_create() {
|
||||
return memnew(RenderingDeviceDriverVulkan(this));
|
||||
}
|
||||
|
||||
void RenderingContextDriverVulkan::driver_free(RenderingDeviceDriver *p_driver) {
|
||||
memdelete(p_driver);
|
||||
}
|
||||
|
||||
RenderingContextDriver::SurfaceID RenderingContextDriverVulkan::surface_create(const void *p_platform_data) {
|
||||
DEV_ASSERT(false && "Surface creation should not be called on the platform-agnostic version of the driver.");
|
||||
return SurfaceID();
|
||||
}
|
||||
|
||||
void RenderingContextDriverVulkan::surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) {
|
||||
Surface *surface = (Surface *)(p_surface);
|
||||
surface->width = p_width;
|
||||
surface->height = p_height;
|
||||
surface->needs_resize = true;
|
||||
}
|
||||
|
||||
void RenderingContextDriverVulkan::surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) {
|
||||
Surface *surface = (Surface *)(p_surface);
|
||||
surface->vsync_mode = p_vsync_mode;
|
||||
surface->needs_resize = true;
|
||||
}
|
||||
|
||||
DisplayServer::VSyncMode RenderingContextDriverVulkan::surface_get_vsync_mode(SurfaceID p_surface) const {
|
||||
Surface *surface = (Surface *)(p_surface);
|
||||
return surface->vsync_mode;
|
||||
}
|
||||
|
||||
uint32_t RenderingContextDriverVulkan::surface_get_width(SurfaceID p_surface) const {
|
||||
Surface *surface = (Surface *)(p_surface);
|
||||
return surface->width;
|
||||
}
|
||||
|
||||
uint32_t RenderingContextDriverVulkan::surface_get_height(SurfaceID p_surface) const {
|
||||
Surface *surface = (Surface *)(p_surface);
|
||||
return surface->height;
|
||||
}
|
||||
|
||||
void RenderingContextDriverVulkan::surface_set_needs_resize(SurfaceID p_surface, bool p_needs_resize) {
|
||||
Surface *surface = (Surface *)(p_surface);
|
||||
surface->needs_resize = p_needs_resize;
|
||||
}
|
||||
|
||||
bool RenderingContextDriverVulkan::surface_get_needs_resize(SurfaceID p_surface) const {
|
||||
Surface *surface = (Surface *)(p_surface);
|
||||
return surface->needs_resize;
|
||||
}
|
||||
|
||||
void RenderingContextDriverVulkan::surface_destroy(SurfaceID p_surface) {
|
||||
Surface *surface = (Surface *)(p_surface);
|
||||
vkDestroySurfaceKHR(instance, surface->vk_surface, nullptr);
|
||||
memdelete(surface);
|
||||
}
|
||||
|
||||
bool RenderingContextDriverVulkan::is_debug_utils_enabled() const {
|
||||
return enabled_instance_extension_names.has(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
VkInstance RenderingContextDriverVulkan::instance_get() const {
|
||||
return instance;
|
||||
}
|
||||
|
||||
VkPhysicalDevice RenderingContextDriverVulkan::physical_device_get(uint32_t p_device_index) const {
|
||||
DEV_ASSERT(p_device_index < physical_devices.size());
|
||||
return physical_devices[p_device_index];
|
||||
}
|
||||
|
||||
uint32_t RenderingContextDriverVulkan::queue_family_get_count(uint32_t p_device_index) const {
|
||||
DEV_ASSERT(p_device_index < physical_devices.size());
|
||||
return device_queue_families[p_device_index].properties.size();
|
||||
}
|
||||
|
||||
VkQueueFamilyProperties RenderingContextDriverVulkan::queue_family_get(uint32_t p_device_index, uint32_t p_queue_family_index) const {
|
||||
DEV_ASSERT(p_device_index < physical_devices.size());
|
||||
DEV_ASSERT(p_queue_family_index < queue_family_get_count(p_device_index));
|
||||
return device_queue_families[p_device_index].properties[p_queue_family_index];
|
||||
}
|
||||
|
||||
bool RenderingContextDriverVulkan::queue_family_supports_present(VkPhysicalDevice p_physical_device, uint32_t p_queue_family_index, SurfaceID p_surface) const {
|
||||
DEV_ASSERT(p_physical_device != VK_NULL_HANDLE);
|
||||
DEV_ASSERT(p_surface != 0);
|
||||
Surface *surface = (Surface *)(p_surface);
|
||||
VkBool32 present_supported = false;
|
||||
VkResult err = vkGetPhysicalDeviceSurfaceSupportKHR(p_physical_device, p_queue_family_index, surface->vk_surface, &present_supported);
|
||||
return err == VK_SUCCESS && present_supported;
|
||||
}
|
||||
|
||||
const RenderingContextDriverVulkan::Functions &RenderingContextDriverVulkan::functions_get() const {
|
||||
return functions;
|
||||
}
|
||||
|
||||
#endif // VULKAN_ENABLED
|
||||
162
engine/drivers/vulkan/rendering_context_driver_vulkan.h
Normal file
162
engine/drivers/vulkan/rendering_context_driver_vulkan.h
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/**************************************************************************/
|
||||
/* rendering_context_driver_vulkan.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_H
|
||||
#define RENDERING_CONTEXT_DRIVER_VULKAN_H
|
||||
|
||||
#ifdef VULKAN_ENABLED
|
||||
|
||||
#include "servers/rendering/rendering_context_driver.h"
|
||||
|
||||
#ifdef USE_VOLK
|
||||
#include <volk.h>
|
||||
#else
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
||||
class RenderingContextDriverVulkan : public RenderingContextDriver {
|
||||
public:
|
||||
struct Functions {
|
||||
// Physical device.
|
||||
PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2 = nullptr;
|
||||
PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2 = nullptr;
|
||||
|
||||
// Device.
|
||||
PFN_vkGetDeviceProcAddr GetDeviceProcAddr = nullptr;
|
||||
|
||||
// Surfaces.
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR = nullptr;
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR = nullptr;
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
|
||||
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR = nullptr;
|
||||
|
||||
// Debug utils.
|
||||
PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr;
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr;
|
||||
PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT = nullptr;
|
||||
PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT = nullptr;
|
||||
PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT = nullptr;
|
||||
|
||||
bool debug_util_functions_available() const {
|
||||
return CreateDebugUtilsMessengerEXT != nullptr &&
|
||||
DestroyDebugUtilsMessengerEXT != nullptr &&
|
||||
CmdBeginDebugUtilsLabelEXT != nullptr &&
|
||||
CmdEndDebugUtilsLabelEXT != nullptr &&
|
||||
SetDebugUtilsObjectNameEXT != nullptr;
|
||||
}
|
||||
|
||||
// Debug report.
|
||||
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT = nullptr;
|
||||
PFN_vkDebugReportMessageEXT DebugReportMessageEXT = nullptr;
|
||||
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT = nullptr;
|
||||
|
||||
bool debug_report_functions_available() const {
|
||||
return CreateDebugReportCallbackEXT != nullptr &&
|
||||
DebugReportMessageEXT != nullptr &&
|
||||
DestroyDebugReportCallbackEXT != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
struct DeviceQueueFamilies {
|
||||
TightLocalVector<VkQueueFamilyProperties> properties;
|
||||
};
|
||||
|
||||
VkInstance instance = VK_NULL_HANDLE;
|
||||
uint32_t instance_api_version = VK_API_VERSION_1_0;
|
||||
HashMap<CharString, bool> requested_instance_extensions;
|
||||
HashSet<CharString> enabled_instance_extension_names;
|
||||
TightLocalVector<Device> driver_devices;
|
||||
TightLocalVector<VkPhysicalDevice> physical_devices;
|
||||
TightLocalVector<DeviceQueueFamilies> device_queue_families;
|
||||
VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
|
||||
VkDebugReportCallbackEXT debug_report = VK_NULL_HANDLE;
|
||||
Functions functions;
|
||||
|
||||
Error _initialize_vulkan_version();
|
||||
void _register_requested_instance_extension(const CharString &p_extension_name, bool p_required);
|
||||
Error _initialize_instance_extensions();
|
||||
Error _initialize_instance();
|
||||
Error _initialize_devices();
|
||||
void _check_driver_workarounds(const VkPhysicalDeviceProperties &p_device_properties, Device &r_device);
|
||||
|
||||
// Static callbacks.
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, VkDebugUtilsMessageTypeFlagsEXT p_message_type, const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data);
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_report_callback(VkDebugReportFlagsEXT p_flags, VkDebugReportObjectTypeEXT p_object_type, uint64_t p_object, size_t p_location, int32_t p_message_code, const char *p_layer_prefix, const char *p_message, void *p_user_data);
|
||||
|
||||
protected:
|
||||
Error _find_validation_layers(TightLocalVector<const char *> &r_layer_names) const;
|
||||
|
||||
// Can be overridden by platform-specific drivers.
|
||||
virtual const char *_get_platform_surface_extension() const { return nullptr; }
|
||||
virtual bool _use_validation_layers() const;
|
||||
virtual Error _create_vulkan_instance(const VkInstanceCreateInfo *p_create_info, VkInstance *r_instance);
|
||||
|
||||
public:
|
||||
virtual Error initialize() override;
|
||||
virtual const Device &device_get(uint32_t p_device_index) const override;
|
||||
virtual uint32_t device_get_count() const override;
|
||||
virtual bool device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const override;
|
||||
virtual RenderingDeviceDriver *driver_create() override;
|
||||
virtual void driver_free(RenderingDeviceDriver *p_driver) override;
|
||||
virtual SurfaceID surface_create(const void *p_platform_data) override;
|
||||
virtual void surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) override;
|
||||
virtual void surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) override;
|
||||
virtual DisplayServer::VSyncMode surface_get_vsync_mode(SurfaceID p_surface) const override;
|
||||
virtual uint32_t surface_get_width(SurfaceID p_surface) const override;
|
||||
virtual uint32_t surface_get_height(SurfaceID p_surface) const override;
|
||||
virtual void surface_set_needs_resize(SurfaceID p_surface, bool p_needs_resize) override;
|
||||
virtual bool surface_get_needs_resize(SurfaceID p_surface) const override;
|
||||
virtual void surface_destroy(SurfaceID p_surface) override;
|
||||
virtual bool is_debug_utils_enabled() const override;
|
||||
|
||||
// Vulkan-only methods.
|
||||
struct Surface {
|
||||
VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
|
||||
bool needs_resize = false;
|
||||
};
|
||||
|
||||
VkInstance instance_get() const;
|
||||
VkPhysicalDevice physical_device_get(uint32_t p_device_index) const;
|
||||
uint32_t queue_family_get_count(uint32_t p_device_index) const;
|
||||
VkQueueFamilyProperties queue_family_get(uint32_t p_device_index, uint32_t p_queue_family_index) const;
|
||||
bool queue_family_supports_present(VkPhysicalDevice p_physical_device, uint32_t p_queue_family_index, SurfaceID p_surface) const;
|
||||
const Functions &functions_get() const;
|
||||
|
||||
RenderingContextDriverVulkan();
|
||||
virtual ~RenderingContextDriverVulkan() override;
|
||||
};
|
||||
|
||||
#endif // VULKAN_ENABLED
|
||||
|
||||
#endif // RENDERING_CONTEXT_DRIVER_VULKAN_H
|
||||
5026
engine/drivers/vulkan/rendering_device_driver_vulkan.cpp
Normal file
5026
engine/drivers/vulkan/rendering_device_driver_vulkan.cpp
Normal file
File diff suppressed because it is too large
Load diff
654
engine/drivers/vulkan/rendering_device_driver_vulkan.h
Normal file
654
engine/drivers/vulkan/rendering_device_driver_vulkan.h
Normal file
|
|
@ -0,0 +1,654 @@
|
|||
/**************************************************************************/
|
||||
/* rendering_device_driver_vulkan.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef RENDERING_DEVICE_DRIVER_VULKAN_H
|
||||
#define RENDERING_DEVICE_DRIVER_VULKAN_H
|
||||
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/paged_allocator.h"
|
||||
#include "drivers/vulkan/rendering_context_driver_vulkan.h"
|
||||
#include "servers/rendering/rendering_device_driver.h"
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#ifndef _MSC_VER
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#endif
|
||||
#include "thirdparty/vulkan/vk_mem_alloc.h"
|
||||
|
||||
#ifdef USE_VOLK
|
||||
#include <volk.h>
|
||||
#else
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
||||
// Design principles:
|
||||
// - Vulkan structs are zero-initialized and fields not requiring a non-zero value are omitted (except in cases where expresivity reasons apply).
|
||||
class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
|
||||
/*****************/
|
||||
/**** GENERIC ****/
|
||||
/*****************/
|
||||
|
||||
struct CommandQueue;
|
||||
struct SwapChain;
|
||||
|
||||
struct Queue {
|
||||
VkQueue queue = VK_NULL_HANDLE;
|
||||
uint32_t virtual_count = 0;
|
||||
BinaryMutex submit_mutex;
|
||||
};
|
||||
|
||||
struct SubgroupCapabilities {
|
||||
uint32_t size = 0;
|
||||
uint32_t min_size = 0;
|
||||
uint32_t max_size = 0;
|
||||
VkShaderStageFlags supported_stages = 0;
|
||||
VkSubgroupFeatureFlags supported_operations = 0;
|
||||
VkBool32 quad_operations_in_all_stages = false;
|
||||
bool size_control_is_supported = false;
|
||||
|
||||
uint32_t supported_stages_flags_rd() const;
|
||||
String supported_stages_desc() const;
|
||||
uint32_t supported_operations_flags_rd() const;
|
||||
String supported_operations_desc() const;
|
||||
};
|
||||
|
||||
struct VRSCapabilities {
|
||||
bool pipeline_vrs_supported = false; // We can specify our fragment rate on a pipeline level.
|
||||
bool primitive_vrs_supported = false; // We can specify our fragment rate on each drawcall.
|
||||
bool attachment_vrs_supported = false; // We can provide a density map attachment on our framebuffer.
|
||||
|
||||
Size2i min_texel_size;
|
||||
Size2i max_texel_size;
|
||||
Size2i max_fragment_size;
|
||||
|
||||
Size2i texel_size; // The texel size we'll use
|
||||
};
|
||||
|
||||
struct ShaderCapabilities {
|
||||
bool shader_float16_is_supported = false;
|
||||
bool shader_int8_is_supported = false;
|
||||
};
|
||||
|
||||
struct StorageBufferCapabilities {
|
||||
bool storage_buffer_16_bit_access_is_supported = false;
|
||||
bool uniform_and_storage_buffer_16_bit_access_is_supported = false;
|
||||
bool storage_push_constant_16_is_supported = false;
|
||||
bool storage_input_output_16 = false;
|
||||
};
|
||||
|
||||
struct DeviceFunctions {
|
||||
PFN_vkCreateSwapchainKHR CreateSwapchainKHR = nullptr;
|
||||
PFN_vkDestroySwapchainKHR DestroySwapchainKHR = nullptr;
|
||||
PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR = nullptr;
|
||||
PFN_vkAcquireNextImageKHR AcquireNextImageKHR = nullptr;
|
||||
PFN_vkQueuePresentKHR QueuePresentKHR = nullptr;
|
||||
PFN_vkCreateRenderPass2KHR CreateRenderPass2KHR = nullptr;
|
||||
};
|
||||
|
||||
VkDevice vk_device = VK_NULL_HANDLE;
|
||||
RenderingContextDriverVulkan *context_driver = nullptr;
|
||||
RenderingContextDriver::Device context_device = {};
|
||||
uint32_t frame_count = 1;
|
||||
VkPhysicalDevice physical_device = VK_NULL_HANDLE;
|
||||
VkPhysicalDeviceProperties physical_device_properties = {};
|
||||
VkPhysicalDeviceFeatures physical_device_features = {};
|
||||
VkPhysicalDeviceFeatures requested_device_features = {};
|
||||
HashMap<CharString, bool> requested_device_extensions;
|
||||
HashSet<CharString> enabled_device_extension_names;
|
||||
TightLocalVector<TightLocalVector<Queue>> queue_families;
|
||||
TightLocalVector<VkQueueFamilyProperties> queue_family_properties;
|
||||
RDD::Capabilities device_capabilities;
|
||||
SubgroupCapabilities subgroup_capabilities;
|
||||
MultiviewCapabilities multiview_capabilities;
|
||||
VRSCapabilities vrs_capabilities;
|
||||
ShaderCapabilities shader_capabilities;
|
||||
StorageBufferCapabilities storage_buffer_capabilities;
|
||||
bool pipeline_cache_control_support = false;
|
||||
DeviceFunctions device_functions;
|
||||
|
||||
void _register_requested_device_extension(const CharString &p_extension_name, bool p_required);
|
||||
Error _initialize_device_extensions();
|
||||
Error _check_device_features();
|
||||
Error _check_device_capabilities();
|
||||
Error _add_queue_create_info(LocalVector<VkDeviceQueueCreateInfo> &r_queue_create_info);
|
||||
Error _initialize_device(const LocalVector<VkDeviceQueueCreateInfo> &p_queue_create_info);
|
||||
Error _initialize_allocator();
|
||||
Error _initialize_pipeline_cache();
|
||||
VkResult _create_render_pass(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass);
|
||||
bool _release_image_semaphore(CommandQueue *p_command_queue, uint32_t p_semaphore_index, bool p_release_on_swap_chain);
|
||||
bool _recreate_image_semaphore(CommandQueue *p_command_queue, uint32_t p_semaphore_index, bool p_release_on_swap_chain);
|
||||
void _set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name);
|
||||
|
||||
public:
|
||||
Error initialize(uint32_t p_device_index, uint32_t p_frame_count) override final;
|
||||
|
||||
private:
|
||||
/****************/
|
||||
/**** MEMORY ****/
|
||||
/****************/
|
||||
|
||||
VmaAllocator allocator = nullptr;
|
||||
HashMap<uint32_t, VmaPool> small_allocs_pools;
|
||||
|
||||
VmaPool _find_or_create_small_allocs_pool(uint32_t p_mem_type_index);
|
||||
|
||||
/*****************/
|
||||
/**** BUFFERS ****/
|
||||
/*****************/
|
||||
private:
|
||||
struct BufferInfo {
|
||||
VkBuffer vk_buffer = VK_NULL_HANDLE;
|
||||
struct {
|
||||
VmaAllocation handle = nullptr;
|
||||
uint64_t size = UINT64_MAX;
|
||||
} allocation;
|
||||
uint64_t size = 0;
|
||||
VkBufferView vk_view = VK_NULL_HANDLE; // For texel buffers.
|
||||
};
|
||||
|
||||
public:
|
||||
virtual BufferID buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type) override final;
|
||||
virtual bool buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) override final;
|
||||
virtual void buffer_free(BufferID p_buffer) override final;
|
||||
virtual uint64_t buffer_get_allocation_size(BufferID p_buffer) override final;
|
||||
virtual uint8_t *buffer_map(BufferID p_buffer) override final;
|
||||
virtual void buffer_unmap(BufferID p_buffer) override final;
|
||||
|
||||
/*****************/
|
||||
/**** TEXTURE ****/
|
||||
/*****************/
|
||||
|
||||
struct TextureInfo {
|
||||
VkImageView vk_view = VK_NULL_HANDLE;
|
||||
DataFormat rd_format = DATA_FORMAT_MAX;
|
||||
VkImageCreateInfo vk_create_info = {};
|
||||
VkImageViewCreateInfo vk_view_create_info = {};
|
||||
struct {
|
||||
VmaAllocation handle = nullptr;
|
||||
VmaAllocationInfo info = {};
|
||||
} allocation; // All 0/null if just a view.
|
||||
};
|
||||
|
||||
VkSampleCountFlagBits _ensure_supported_sample_count(TextureSamples p_requested_sample_count);
|
||||
|
||||
public:
|
||||
virtual TextureID texture_create(const TextureFormat &p_format, const TextureView &p_view) override final;
|
||||
virtual TextureID texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) override final;
|
||||
virtual TextureID texture_create_shared(TextureID p_original_texture, const TextureView &p_view) override final;
|
||||
virtual TextureID texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) override final;
|
||||
virtual void texture_free(TextureID p_texture) override final;
|
||||
virtual uint64_t texture_get_allocation_size(TextureID p_texture) override final;
|
||||
virtual void texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) override final;
|
||||
virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) override final;
|
||||
virtual void texture_unmap(TextureID p_texture) override final;
|
||||
virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) override final;
|
||||
virtual bool texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) override final;
|
||||
|
||||
/*****************/
|
||||
/**** SAMPLER ****/
|
||||
/*****************/
|
||||
public:
|
||||
virtual SamplerID sampler_create(const SamplerState &p_state) final override;
|
||||
virtual void sampler_free(SamplerID p_sampler) final override;
|
||||
virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_filter) override final;
|
||||
|
||||
/**********************/
|
||||
/**** VERTEX ARRAY ****/
|
||||
/**********************/
|
||||
private:
|
||||
struct VertexFormatInfo {
|
||||
TightLocalVector<VkVertexInputBindingDescription> vk_bindings;
|
||||
TightLocalVector<VkVertexInputAttributeDescription> vk_attributes;
|
||||
VkPipelineVertexInputStateCreateInfo vk_create_info = {};
|
||||
};
|
||||
|
||||
public:
|
||||
virtual VertexFormatID vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) override final;
|
||||
virtual void vertex_format_free(VertexFormatID p_vertex_format) override final;
|
||||
|
||||
/******************/
|
||||
/**** BARRIERS ****/
|
||||
/******************/
|
||||
|
||||
virtual void command_pipeline_barrier(
|
||||
CommandBufferID p_cmd_buffer,
|
||||
BitField<PipelineStageBits> p_src_stages,
|
||||
BitField<PipelineStageBits> p_dst_stages,
|
||||
VectorView<MemoryBarrier> p_memory_barriers,
|
||||
VectorView<BufferBarrier> p_buffer_barriers,
|
||||
VectorView<TextureBarrier> p_texture_barriers) override final;
|
||||
|
||||
/****************/
|
||||
/**** FENCES ****/
|
||||
/****************/
|
||||
|
||||
private:
|
||||
struct Fence {
|
||||
VkFence vk_fence = VK_NULL_HANDLE;
|
||||
CommandQueue *queue_signaled_from = nullptr;
|
||||
};
|
||||
|
||||
public:
|
||||
virtual FenceID fence_create() override final;
|
||||
virtual Error fence_wait(FenceID p_fence) override final;
|
||||
virtual void fence_free(FenceID p_fence) override final;
|
||||
|
||||
/********************/
|
||||
/**** SEMAPHORES ****/
|
||||
/********************/
|
||||
|
||||
virtual SemaphoreID semaphore_create() override final;
|
||||
virtual void semaphore_free(SemaphoreID p_semaphore) override final;
|
||||
|
||||
/******************/
|
||||
/**** COMMANDS ****/
|
||||
/******************/
|
||||
|
||||
// ----- QUEUE FAMILY -----
|
||||
|
||||
virtual CommandQueueFamilyID command_queue_family_get(BitField<CommandQueueFamilyBits> p_cmd_queue_family_bits, RenderingContextDriver::SurfaceID p_surface = 0) override final;
|
||||
|
||||
// ----- QUEUE -----
|
||||
private:
|
||||
struct CommandQueue {
|
||||
LocalVector<VkSemaphore> present_semaphores;
|
||||
LocalVector<VkSemaphore> image_semaphores;
|
||||
LocalVector<SwapChain *> image_semaphores_swap_chains;
|
||||
LocalVector<uint32_t> pending_semaphores_for_execute;
|
||||
LocalVector<uint32_t> pending_semaphores_for_fence;
|
||||
LocalVector<uint32_t> free_image_semaphores;
|
||||
LocalVector<Pair<Fence *, uint32_t>> image_semaphores_for_fences;
|
||||
uint32_t queue_family = 0;
|
||||
uint32_t queue_index = 0;
|
||||
uint32_t present_semaphore_index = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
virtual CommandQueueID command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue = false) override final;
|
||||
virtual Error command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) override final;
|
||||
virtual void command_queue_free(CommandQueueID p_cmd_queue) override final;
|
||||
|
||||
private:
|
||||
// ----- POOL -----
|
||||
|
||||
struct CommandPool {
|
||||
VkCommandPool vk_command_pool = VK_NULL_HANDLE;
|
||||
CommandBufferType buffer_type = COMMAND_BUFFER_TYPE_PRIMARY;
|
||||
};
|
||||
|
||||
public:
|
||||
virtual CommandPoolID command_pool_create(CommandQueueFamilyID p_cmd_queue_family, CommandBufferType p_cmd_buffer_type) override final;
|
||||
virtual void command_pool_free(CommandPoolID p_cmd_pool) override final;
|
||||
|
||||
// ----- BUFFER -----
|
||||
|
||||
virtual CommandBufferID command_buffer_create(CommandPoolID p_cmd_pool) override final;
|
||||
virtual bool command_buffer_begin(CommandBufferID p_cmd_buffer) override final;
|
||||
virtual bool command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) override final;
|
||||
virtual void command_buffer_end(CommandBufferID p_cmd_buffer) override final;
|
||||
virtual void command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) override final;
|
||||
|
||||
/********************/
|
||||
/**** SWAP CHAIN ****/
|
||||
/********************/
|
||||
|
||||
private:
|
||||
struct SwapChain {
|
||||
VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE;
|
||||
RenderingContextDriver::SurfaceID surface = RenderingContextDriver::SurfaceID();
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
TightLocalVector<VkImage> images;
|
||||
TightLocalVector<VkImageView> image_views;
|
||||
TightLocalVector<FramebufferID> framebuffers;
|
||||
LocalVector<CommandQueue *> command_queues_acquired;
|
||||
LocalVector<uint32_t> command_queues_acquired_semaphores;
|
||||
RenderPassID render_pass;
|
||||
uint32_t image_index = 0;
|
||||
};
|
||||
|
||||
void _swap_chain_release(SwapChain *p_swap_chain);
|
||||
|
||||
public:
|
||||
virtual SwapChainID swap_chain_create(RenderingContextDriver::SurfaceID p_surface) override final;
|
||||
virtual Error swap_chain_resize(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, uint32_t p_desired_framebuffer_count) override final;
|
||||
virtual FramebufferID swap_chain_acquire_framebuffer(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, bool &r_resize_required) override final;
|
||||
virtual RenderPassID swap_chain_get_render_pass(SwapChainID p_swap_chain) override final;
|
||||
virtual DataFormat swap_chain_get_format(SwapChainID p_swap_chain) override final;
|
||||
virtual void swap_chain_free(SwapChainID p_swap_chain) override final;
|
||||
|
||||
/*********************/
|
||||
/**** FRAMEBUFFER ****/
|
||||
/*********************/
|
||||
|
||||
virtual FramebufferID framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) override final;
|
||||
virtual void framebuffer_free(FramebufferID p_framebuffer) override final;
|
||||
|
||||
/****************/
|
||||
/**** SHADER ****/
|
||||
/****************/
|
||||
private:
|
||||
struct ShaderBinary {
|
||||
// Version 1: initial.
|
||||
// Version 2: Added shader name.
|
||||
// Version 3: Added writable.
|
||||
// Version 4: 64-bit vertex input mask.
|
||||
static const uint32_t VERSION = 4;
|
||||
|
||||
struct DataBinding {
|
||||
uint32_t type = 0;
|
||||
uint32_t binding = 0;
|
||||
uint32_t stages = 0;
|
||||
uint32_t length = 0; // Size of arrays (in total elements), or UBOs (in bytes * total elements).
|
||||
uint32_t writable = 0;
|
||||
};
|
||||
|
||||
struct SpecializationConstant {
|
||||
uint32_t type = 0;
|
||||
uint32_t constant_id = 0;
|
||||
uint32_t int_value = 0;
|
||||
uint32_t stage_flags = 0;
|
||||
};
|
||||
|
||||
struct Data {
|
||||
uint64_t vertex_input_mask = 0;
|
||||
uint32_t fragment_output_mask = 0;
|
||||
uint32_t specialization_constants_count = 0;
|
||||
uint32_t is_compute = 0;
|
||||
uint32_t compute_local_size[3] = {};
|
||||
uint32_t set_count = 0;
|
||||
uint32_t push_constant_size = 0;
|
||||
uint32_t vk_push_constant_stages_mask = 0;
|
||||
uint32_t stage_count = 0;
|
||||
uint32_t shader_name_len = 0;
|
||||
};
|
||||
};
|
||||
|
||||
struct ShaderInfo {
|
||||
VkShaderStageFlags vk_push_constant_stages = 0;
|
||||
TightLocalVector<VkPipelineShaderStageCreateInfo> vk_stages_create_info;
|
||||
TightLocalVector<VkDescriptorSetLayout> vk_descriptor_set_layouts;
|
||||
VkPipelineLayout vk_pipeline_layout = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
public:
|
||||
virtual String shader_get_binary_cache_key() override final;
|
||||
virtual Vector<uint8_t> shader_compile_binary_from_spirv(VectorView<ShaderStageSPIRVData> p_spirv, const String &p_shader_name) override final;
|
||||
virtual ShaderID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) override final;
|
||||
virtual void shader_free(ShaderID p_shader) override final;
|
||||
|
||||
/*********************/
|
||||
/**** UNIFORM SET ****/
|
||||
/*********************/
|
||||
|
||||
// Descriptor sets require allocation from a pool.
|
||||
// The documentation on how to use pools properly
|
||||
// is scarce, and the documentation is strange.
|
||||
//
|
||||
// Basically, you can mix and match pools as you
|
||||
// like, but you'll run into fragmentation issues.
|
||||
// Because of this, the recommended approach is to
|
||||
// create a pool for every descriptor set type, as
|
||||
// this prevents fragmentation.
|
||||
//
|
||||
// This is implemented here as a having a list of
|
||||
// pools (each can contain up to 64 sets) for each
|
||||
// set layout. The amount of sets for each type
|
||||
// is used as the key.
|
||||
|
||||
private:
|
||||
static const uint32_t MAX_UNIFORM_POOL_ELEMENT = 65535;
|
||||
|
||||
struct DescriptorSetPoolKey {
|
||||
uint16_t uniform_type[UNIFORM_TYPE_MAX] = {};
|
||||
|
||||
bool operator<(const DescriptorSetPoolKey &p_other) const {
|
||||
return memcmp(uniform_type, p_other.uniform_type, sizeof(uniform_type)) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
using DescriptorSetPools = RBMap<DescriptorSetPoolKey, HashMap<VkDescriptorPool, uint32_t>>;
|
||||
DescriptorSetPools descriptor_set_pools;
|
||||
uint32_t max_descriptor_sets_per_pool = 0;
|
||||
|
||||
VkDescriptorPool _descriptor_set_pool_find_or_create(const DescriptorSetPoolKey &p_key, DescriptorSetPools::Iterator *r_pool_sets_it);
|
||||
void _descriptor_set_pool_unreference(DescriptorSetPools::Iterator p_pool_sets_it, VkDescriptorPool p_vk_descriptor_pool);
|
||||
|
||||
struct UniformSetInfo {
|
||||
VkDescriptorSet vk_descriptor_set = VK_NULL_HANDLE;
|
||||
VkDescriptorPool vk_descriptor_pool = VK_NULL_HANDLE;
|
||||
DescriptorSetPools::Iterator pool_sets_it = {};
|
||||
};
|
||||
|
||||
public:
|
||||
virtual UniformSetID uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index) override final;
|
||||
virtual void uniform_set_free(UniformSetID p_uniform_set) override final;
|
||||
|
||||
// ----- COMMANDS -----
|
||||
|
||||
virtual void command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
|
||||
|
||||
/******************/
|
||||
/**** TRANSFER ****/
|
||||
/******************/
|
||||
|
||||
virtual void command_clear_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, uint64_t p_offset, uint64_t p_size) override final;
|
||||
virtual void command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_dst_buffer, VectorView<BufferCopyRegion> p_regions) override final;
|
||||
|
||||
virtual void command_copy_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<TextureCopyRegion> p_regions) override final;
|
||||
virtual void command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) override final;
|
||||
virtual void command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) override final;
|
||||
|
||||
virtual void command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) override final;
|
||||
virtual void command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) override final;
|
||||
|
||||
/******************/
|
||||
/**** PIPELINE ****/
|
||||
/******************/
|
||||
private:
|
||||
struct PipelineCacheHeader {
|
||||
uint32_t magic = 0;
|
||||
uint32_t data_size = 0;
|
||||
uint64_t data_hash = 0;
|
||||
uint32_t vendor_id = 0;
|
||||
uint32_t device_id = 0;
|
||||
uint32_t driver_version = 0;
|
||||
uint8_t uuid[VK_UUID_SIZE] = {};
|
||||
uint8_t driver_abi = 0;
|
||||
};
|
||||
|
||||
struct PipelineCache {
|
||||
String file_path;
|
||||
size_t current_size = 0;
|
||||
Vector<uint8_t> buffer; // Header then data.
|
||||
VkPipelineCache vk_cache = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
static int caching_instance_count;
|
||||
PipelineCache pipelines_cache;
|
||||
String pipeline_cache_id;
|
||||
HashMap<uint64_t, bool> has_comp_alpha;
|
||||
|
||||
public:
|
||||
virtual void pipeline_free(PipelineID p_pipeline) override final;
|
||||
|
||||
// ----- BINDING -----
|
||||
|
||||
virtual void command_bind_push_constants(CommandBufferID p_cmd_buffer, ShaderID p_shader, uint32_t p_first_index, VectorView<uint32_t> p_data) override final;
|
||||
|
||||
// ----- CACHE -----
|
||||
|
||||
virtual bool pipeline_cache_create(const Vector<uint8_t> &p_data) override final;
|
||||
virtual void pipeline_cache_free() override final;
|
||||
virtual size_t pipeline_cache_query_size() override final;
|
||||
virtual Vector<uint8_t> pipeline_cache_serialize() override final;
|
||||
|
||||
/*******************/
|
||||
/**** RENDERING ****/
|
||||
/*******************/
|
||||
|
||||
// ----- SUBPASS -----
|
||||
|
||||
virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) override final;
|
||||
virtual void render_pass_free(RenderPassID p_render_pass) override final;
|
||||
|
||||
// ----- COMMANDS -----
|
||||
|
||||
virtual void command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_clear_values) override final;
|
||||
virtual void command_end_render_pass(CommandBufferID p_cmd_buffer) override final;
|
||||
virtual void command_next_render_subpass(CommandBufferID p_cmd_buffer, CommandBufferType p_cmd_buffer_type) override final;
|
||||
virtual void command_render_set_viewport(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_viewports) override final;
|
||||
virtual void command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_scissors) override final;
|
||||
virtual void command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView<AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects) override final;
|
||||
|
||||
// Binding.
|
||||
virtual void command_bind_render_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) override final;
|
||||
virtual void command_bind_render_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
|
||||
|
||||
// Drawing.
|
||||
virtual void command_render_draw(CommandBufferID p_cmd_buffer, uint32_t p_vertex_count, uint32_t p_instance_count, uint32_t p_base_vertex, uint32_t p_first_instance) override final;
|
||||
virtual void command_render_draw_indexed(CommandBufferID p_cmd_buffer, uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index, int32_t p_vertex_offset, uint32_t p_first_instance) override final;
|
||||
virtual void command_render_draw_indexed_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) override final;
|
||||
virtual void command_render_draw_indexed_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) override final;
|
||||
virtual void command_render_draw_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) override final;
|
||||
virtual void command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) override final;
|
||||
|
||||
// Buffer binding.
|
||||
virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) override final;
|
||||
virtual void command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) override final;
|
||||
|
||||
// Dynamic state.
|
||||
virtual void command_render_set_blend_constants(CommandBufferID p_cmd_buffer, const Color &p_constants) override final;
|
||||
virtual void command_render_set_line_width(CommandBufferID p_cmd_buffer, float p_width) override final;
|
||||
|
||||
// ----- PIPELINE -----
|
||||
|
||||
virtual PipelineID render_pipeline_create(
|
||||
ShaderID p_shader,
|
||||
VertexFormatID p_vertex_format,
|
||||
RenderPrimitive p_render_primitive,
|
||||
PipelineRasterizationState p_rasterization_state,
|
||||
PipelineMultisampleState p_multisample_state,
|
||||
PipelineDepthStencilState p_depth_stencil_state,
|
||||
PipelineColorBlendState p_blend_state,
|
||||
VectorView<int32_t> p_color_attachments,
|
||||
BitField<PipelineDynamicStateFlags> p_dynamic_state,
|
||||
RenderPassID p_render_pass,
|
||||
uint32_t p_render_subpass,
|
||||
VectorView<PipelineSpecializationConstant> p_specialization_constants) override final;
|
||||
|
||||
/*****************/
|
||||
/**** COMPUTE ****/
|
||||
/*****************/
|
||||
|
||||
// ----- COMMANDS -----
|
||||
|
||||
// Binding.
|
||||
virtual void command_bind_compute_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) override final;
|
||||
virtual void command_bind_compute_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
|
||||
|
||||
// Dispatching.
|
||||
virtual void command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) override final;
|
||||
virtual void command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) override final;
|
||||
|
||||
// ----- PIPELINE -----
|
||||
|
||||
virtual PipelineID compute_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) override final;
|
||||
|
||||
/*****************/
|
||||
/**** QUERIES ****/
|
||||
/*****************/
|
||||
|
||||
// ----- TIMESTAMP -----
|
||||
|
||||
// Basic.
|
||||
virtual QueryPoolID timestamp_query_pool_create(uint32_t p_query_count) override final;
|
||||
virtual void timestamp_query_pool_free(QueryPoolID p_pool_id) override final;
|
||||
virtual void timestamp_query_pool_get_results(QueryPoolID p_pool_id, uint32_t p_query_count, uint64_t *r_results) override final;
|
||||
virtual uint64_t timestamp_query_result_to_time(uint64_t p_result) override final;
|
||||
|
||||
// Commands.
|
||||
virtual void command_timestamp_query_pool_reset(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_query_count) override final;
|
||||
virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) override final;
|
||||
|
||||
/****************/
|
||||
/**** LABELS ****/
|
||||
/****************/
|
||||
|
||||
virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final;
|
||||
virtual void command_end_label(CommandBufferID p_cmd_buffer) override final;
|
||||
|
||||
/********************/
|
||||
/**** SUBMISSION ****/
|
||||
/********************/
|
||||
|
||||
virtual void begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) override final;
|
||||
virtual void end_segment() override final;
|
||||
|
||||
/**************/
|
||||
/**** MISC ****/
|
||||
/**************/
|
||||
|
||||
virtual void set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) override final;
|
||||
virtual uint64_t get_resource_native_handle(DriverResource p_type, ID p_driver_id) override final;
|
||||
virtual uint64_t get_total_memory_used() override final;
|
||||
virtual uint64_t limit_get(Limit p_limit) override final;
|
||||
virtual uint64_t api_trait_get(ApiTrait p_trait) override final;
|
||||
virtual bool has_feature(Features p_feature) override final;
|
||||
virtual const MultiviewCapabilities &get_multiview_capabilities() override final;
|
||||
virtual String get_api_name() const override final;
|
||||
virtual String get_api_version() const override final;
|
||||
virtual String get_pipeline_cache_uuid() const override final;
|
||||
virtual const Capabilities &get_capabilities() const override final;
|
||||
|
||||
virtual bool is_composite_alpha_supported(CommandQueueID p_queue) const override final;
|
||||
|
||||
private:
|
||||
/*********************/
|
||||
/**** BOOKKEEPING ****/
|
||||
/*********************/
|
||||
|
||||
using VersatileResource = VersatileResourceTemplate<
|
||||
BufferInfo,
|
||||
TextureInfo,
|
||||
VertexFormatInfo,
|
||||
ShaderInfo,
|
||||
UniformSetInfo>;
|
||||
PagedAllocator<VersatileResource> resources_allocator;
|
||||
|
||||
/******************/
|
||||
|
||||
public:
|
||||
RenderingDeviceDriverVulkan(RenderingContextDriverVulkan *p_context_driver);
|
||||
virtual ~RenderingDeviceDriverVulkan();
|
||||
};
|
||||
|
||||
#endif // RENDERING_DEVICE_DRIVER_VULKAN_H
|
||||
45
engine/drivers/vulkan/vulkan_hooks.cpp
Normal file
45
engine/drivers/vulkan/vulkan_hooks.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/**************************************************************************/
|
||||
/* vulkan_hooks.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "vulkan_hooks.h"
|
||||
|
||||
VulkanHooks *VulkanHooks::singleton = nullptr;
|
||||
|
||||
VulkanHooks::VulkanHooks() {
|
||||
if (singleton == nullptr) {
|
||||
singleton = this;
|
||||
}
|
||||
}
|
||||
|
||||
VulkanHooks::~VulkanHooks() {
|
||||
if (singleton == this) {
|
||||
singleton = nullptr;
|
||||
}
|
||||
}
|
||||
54
engine/drivers/vulkan/vulkan_hooks.h
Normal file
54
engine/drivers/vulkan/vulkan_hooks.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/**************************************************************************/
|
||||
/* vulkan_hooks.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef VULKAN_HOOKS_H
|
||||
#define VULKAN_HOOKS_H
|
||||
|
||||
#ifdef USE_VOLK
|
||||
#include <volk.h>
|
||||
#else
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
||||
class VulkanHooks {
|
||||
private:
|
||||
static VulkanHooks *singleton;
|
||||
|
||||
public:
|
||||
VulkanHooks();
|
||||
virtual ~VulkanHooks();
|
||||
virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) = 0;
|
||||
virtual bool get_physical_device(VkPhysicalDevice *r_device) = 0;
|
||||
virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) = 0;
|
||||
virtual void set_direct_queue_family_and_index(uint32_t p_queue_family_index, uint32_t p_queue_index) = 0;
|
||||
static VulkanHooks *get_singleton() { return singleton; }
|
||||
};
|
||||
|
||||
#endif // VULKAN_HOOKS_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue