Add support for Vulkan 1.1 & 1.2

This commit is contained in:
Lynix
2020-03-26 20:42:57 +01:00
parent 42d58bd77c
commit d892e8eaff
12 changed files with 143 additions and 45 deletions

View File

@@ -11,6 +11,7 @@
#include <Nazara/VulkanRenderer/Config.hpp>
#include <Nazara/VulkanRenderer/VulkanDevice.hpp>
#include <array>
#include <unordered_set>
#include <Nazara/VulkanRenderer/Debug.hpp>
namespace Nz
@@ -40,7 +41,7 @@ namespace Nz
return dummy;
}
bool Vulkan::Initialize(UInt32 apiVersion, const ParameterList& parameters)
bool Vulkan::Initialize(UInt32 targetApiVersion, const ParameterList& parameters)
{
NazaraAssert(!IsInitialized(), "Vulkan is already initialized");
@@ -66,7 +67,7 @@ namespace Nz
long long iParam;
if (parameters.GetIntegerParameter("VkAppInfo_OverrideAPIVersion", &iParam))
apiVersion = static_cast<UInt32>(iParam);
targetApiVersion = static_cast<UInt32>(iParam);
if (parameters.GetIntegerParameter("VkAppInfo_OverrideApplicationVersion", &iParam))
appVersion = static_cast<UInt32>(iParam);
@@ -74,6 +75,17 @@ namespace Nz
if (parameters.GetIntegerParameter("VkAppInfo_OverrideEngineVersion", &iParam))
engineVersion = static_cast<UInt32>(iParam);
if (Vk::Loader::vkEnumerateInstanceVersion)
{
UInt32 supportedApiVersion;
Vk::Loader::vkEnumerateInstanceVersion(&supportedApiVersion);
targetApiVersion = std::min(targetApiVersion, supportedApiVersion);
}
else
// vkEnumerateInstanceVersion is available from Vulkan 1.1, fallback to 1.0 if not supported
targetApiVersion = VK_API_VERSION_1_0;
VkApplicationInfo appInfo = {
VK_STRUCTURE_TYPE_APPLICATION_INFO,
nullptr,
@@ -81,7 +93,7 @@ namespace Nz
appVersion,
engineName.GetConstBuffer(),
engineVersion,
apiVersion
targetApiVersion
};
VkInstanceCreateFlags createFlags = 0;
@@ -115,6 +127,15 @@ namespace Nz
}
}
// Get extension list
std::unordered_set<std::string> availableExtensions;
std::vector<VkExtensionProperties> extensionList;
if (Vk::Loader::EnumerateInstanceExtensionProperties(&extensionList))
{
for (VkExtensionProperties& extProperty : extensionList)
availableExtensions.insert(extProperty.extensionName);
}
if (!parameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledExtensions", &bParam) || !bParam)
{
enabledExtensions.push_back("VK_KHR_surface");
@@ -401,7 +422,7 @@ namespace Nz
if (!s_initializationParameters.GetBooleanParameter("VkDeviceInfo_OverrideEnabledExtensions", &bParam) || !bParam)
{
// Swapchain extension is required for rendering
enabledExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
enabledExtensions.emplace_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}

View File

@@ -69,12 +69,21 @@ namespace Nz
{
ErrorFlags flags(ErrorFlag_ThrowException, true);
UInt32 deviceVersion = deviceInfo.properties.apiVersion;
#define NAZARA_VULKANRENDERER_DEVICE_EXT_BEGIN(ext) if (IsExtensionLoaded(#ext)) {
#define NAZARA_VULKANRENDERER_DEVICE_EXT_END() }
#define NAZARA_VULKANRENDERER_DEVICE_FUNCTION(func) func = reinterpret_cast<PFN_##func>(GetProcAddr(#func));
#define NAZARA_VULKANRENDERER_DEVICE_CORE_EXT_FUNCTION(func, coreVersion, suffix, extName) \
if (deviceVersion >= coreVersion) \
func = reinterpret_cast<PFN_##func>(GetProcAddr(#func)); \
else if (IsExtensionLoaded("VK_" #suffix "_" #extName)) \
func = reinterpret_cast<PFN_##func##suffix>(GetProcAddr(#func #suffix));
#include <Nazara/VulkanRenderer/Wrapper/DeviceFunctions.hpp>
#undef NAZARA_VULKANRENDERER_DEVICE_CORE_EXT_FUNCTION
#undef NAZARA_VULKANRENDERER_DEVICE_EXT_BEGIN
#undef NAZARA_VULKANRENDERER_DEVICE_EXT_END
#undef NAZARA_VULKANRENDERER_DEVICE_FUNCTION
@@ -164,15 +173,17 @@ namespace Nz
m_physicalDevice = nullptr;
// Reset functions pointers
#define NAZARA_VULKANRENDERER_DEVICE_FUNCTION(func) func = nullptr;
#define NAZARA_VULKANRENDERER_DEVICE_CORE_EXT_FUNCTION(func, ...) NAZARA_VULKANRENDERER_DEVICE_FUNCTION(func)
#define NAZARA_VULKANRENDERER_DEVICE_EXT_BEGIN(ext)
#define NAZARA_VULKANRENDERER_DEVICE_EXT_END()
#define NAZARA_VULKANRENDERER_DEVICE_FUNCTION(func) func = nullptr;
#include <Nazara/VulkanRenderer/Wrapper/DeviceFunctions.hpp>
#undef NAZARA_VULKANRENDERER_DEVICE_CORE_EXT_FUNCTION
#undef NAZARA_VULKANRENDERER_DEVICE_FUNCTION
#undef NAZARA_VULKANRENDERER_DEVICE_EXT_BEGIN
#undef NAZARA_VULKANRENDERER_DEVICE_EXT_END
#undef NAZARA_VULKANRENDERER_DEVICE_FUNCTION
}
void Device::WaitAndDestroyDevice()

View File

@@ -21,6 +21,8 @@ namespace Nz
return false;
}
m_apiVersion = createInfo.pApplicationInfo->apiVersion;
// Store the allocator to access them when needed
if (allocator)
m_allocator = *allocator;
@@ -43,15 +45,22 @@ namespace Nz
#define NAZARA_VULKANRENDERER_INSTANCE_EXT_END() }
#define NAZARA_VULKANRENDERER_INSTANCE_FUNCTION(func) func = reinterpret_cast<PFN_##func>(GetProcAddr(#func));
#define NAZARA_VULKANRENDERER_INSTANCE_CORE_EXT_FUNCTION(func, coreVersion, suffix, extName) \
if (m_apiVersion >= coreVersion) \
func = reinterpret_cast<PFN_##func>(GetProcAddr(#func)); \
else if (IsExtensionLoaded("VK_" #suffix "_" #extName)) \
func = reinterpret_cast<PFN_##func##suffix>(GetProcAddr(#func #suffix));
#include <Nazara/VulkanRenderer/Wrapper/InstanceFunctions.hpp>
#undef NAZARA_VULKANRENDERER_INSTANCE_CORE_EXT_FUNCTION
#undef NAZARA_VULKANRENDERER_INSTANCE_EXT_BEGIN
#undef NAZARA_VULKANRENDERER_INSTANCE_EXT_END
#undef NAZARA_VULKANRENDERER_INSTANCE_FUNCTION
}
catch (const std::exception& e)
{
NazaraError(String("Failed to query instance function: ") + e.what());
NazaraError(std::string("Failed to query instance function: ") + e.what());
return false;
}
@@ -87,8 +96,8 @@ namespace Nz
{
NazaraAssert(extensionProperties, "Invalid extension properties vector");
// First, query physical device count
UInt32 extensionPropertyCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t
// First, query extension count
UInt32 extensionPropertyCount = 0;
m_lastErrorCode = vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionPropertyCount, nullptr);
if (m_lastErrorCode != VkResult::VK_SUCCESS)
{
@@ -99,7 +108,7 @@ namespace Nz
if (extensionPropertyCount == 0)
return true; //< No extension available
// Now we can get the list of the available physical device
// Now we can get the list of the available extensions
extensionProperties->resize(extensionPropertyCount);
m_lastErrorCode = vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionPropertyCount, extensionProperties->data());
if (m_lastErrorCode != VkResult::VK_SUCCESS)
@@ -139,9 +148,11 @@ namespace Nz
#define NAZARA_VULKANRENDERER_INSTANCE_EXT_BEGIN(ext)
#define NAZARA_VULKANRENDERER_INSTANCE_EXT_END()
#define NAZARA_VULKANRENDERER_INSTANCE_FUNCTION(func) func = nullptr;
#define NAZARA_VULKANRENDERER_INSTANCE_CORE_EXT_FUNCTION(func, ...) NAZARA_VULKANRENDERER_INSTANCE_FUNCTION(func)
#include <Nazara/VulkanRenderer/Wrapper/InstanceFunctions.hpp>
#undef NAZARA_VULKANRENDERER_INSTANCE_CORE_EXT_FUNCTION
#undef NAZARA_VULKANRENDERER_INSTANCE_EXT_BEGIN
#undef NAZARA_VULKANRENDERER_INSTANCE_EXT_END
#undef NAZARA_VULKANRENDERER_INSTANCE_FUNCTION

View File

@@ -4,6 +4,7 @@
#include <Nazara/VulkanRenderer/Wrapper/Loader.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/VulkanRenderer/Utils.hpp>
#include <Nazara/VulkanRenderer/Debug.hpp>
@@ -77,7 +78,7 @@ namespace Nz
return false;
}
// vkGetInstanceProcAddr is the only function that's garantee to be exported
// vkGetInstanceProcAddr is the only function that's guarantee to be exported
vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(s_vulkanLib.GetSymbol("vkGetInstanceProcAddr"));
if (!vkGetInstanceProcAddr)
{
@@ -85,28 +86,49 @@ namespace Nz
return false;
}
auto GetProcAddr = [&](const char* name, bool opt)
{
PFN_vkVoidFunction func = vkGetInstanceProcAddr(nullptr, name);
if (!func && !opt)
NazaraError("Failed to get " + std::string(name) + " address");
return func;
};
// all other functions should be loaded using vkGetInstanceProcAddr
#define NAZARA_VULKANRENDERER_LOAD_GLOBAL(func) func = reinterpret_cast<PFN_##func>(vkGetInstanceProcAddr(nullptr, #func))
#define NAZARA_VULKANRENDERER_LOAD_GLOBAL(func) func = reinterpret_cast<PFN_##func>(GetProcAddr(#func))
try
{
ErrorFlags flags(ErrorFlag_ThrowException, true);
NAZARA_VULKANRENDERER_LOAD_GLOBAL(vkCreateInstance);
NAZARA_VULKANRENDERER_LOAD_GLOBAL(vkEnumerateInstanceExtensionProperties);
NAZARA_VULKANRENDERER_LOAD_GLOBAL(vkEnumerateInstanceLayerProperties);
#define NAZARA_VULKANRENDERER_GLOBAL_FUNCTION(func) func = reinterpret_cast<PFN_##func>(GetProcAddr(#func, false));
#define NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_OPT(func) func = reinterpret_cast<PFN_##func>(GetProcAddr(#func, true));
#undef NAZARA_VULKANRENDERER_LOAD_GLOBAL
#include <Nazara/VulkanRenderer/Wrapper/GlobalFunctions.hpp>
#undef NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_OPT
#undef NAZARA_VULKANRENDERER_GLOBAL_FUNCTION
}
catch (const std::exception& e)
{
NazaraError(std::string("Failed to query device function: ") + e.what());
return false;
}
s_lastErrorCode = VkResult::VK_SUCCESS;
return true;
}
#define NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(func) PFN_##func Loader::func = nullptr
PFN_vkGetInstanceProcAddr Loader::vkGetInstanceProcAddr = nullptr;
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkCreateInstance);
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkEnumerateInstanceExtensionProperties);
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkEnumerateInstanceLayerProperties);
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkGetInstanceProcAddr);
#define NAZARA_VULKANRENDERER_GLOBAL_FUNCTION(func) PFN_##func Loader::func = nullptr;
#define NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_OPT NAZARA_VULKANRENDERER_GLOBAL_FUNCTION
#undef NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL
#include <Nazara/VulkanRenderer/Wrapper/GlobalFunctions.hpp>
#undef NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_OPT
#undef NAZARA_VULKANRENDERER_GLOBAL_FUNCTION
DynLib Loader::s_vulkanLib;
VkResult Loader::s_lastErrorCode;