mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-22 15:24:34 +00:00
Dynamically load vulkan instead of statically link.
Make vk-bootstrap capable of loading the vulkan runtime and not need to link against the library. This improves the usability of vk-bootstrap since now you don't need the vulkan library on your system to build. This commit also changes how SystemInfo works so as to allow the dynamic vulkan loading.
This commit is contained in:
parent
511cac8db4
commit
812ce2cf0a
0
.gitmodules
vendored
0
.gitmodules
vendored
@ -32,7 +32,6 @@ target_compile_options(vk-bootstrap-compiler-warnings
|
|||||||
target_include_directories(vk-bootstrap PUBLIC src)
|
target_include_directories(vk-bootstrap PUBLIC src)
|
||||||
target_include_directories(vk-bootstrap PUBLIC ${Vulkan_INCLUDE_DIR})
|
target_include_directories(vk-bootstrap PUBLIC ${Vulkan_INCLUDE_DIR})
|
||||||
target_link_libraries(vk-bootstrap
|
target_link_libraries(vk-bootstrap
|
||||||
PUBLIC ${Vulkan_LIBRARY}
|
|
||||||
PRIVATE
|
PRIVATE
|
||||||
vk-bootstrap-compiler-warnings)
|
vk-bootstrap-compiler-warnings)
|
||||||
|
|
||||||
|
@ -57,10 +57,15 @@ auto inst_builder_ret = instance_builder
|
|||||||
.build();
|
.build();
|
||||||
```
|
```
|
||||||
|
|
||||||
To query the available layers and extensions, use the `get_system_info()` function of `vkb::InstanceBuilder` to get a `SystemInfo` struct. It contains a `is_layer_available()` and `is_extension_available()` function to check for a layer or extensions before enabling it. It also has booleans for if the validation layers are present and if the VK_EXT_debug_utils extension is available.
|
To query the available layers and extensions, get a `SystemInfo` struct from `SystemInfo::get_system_info()`. It contains a `is_layer_available()` and `is_extension_available()` function to check for a layer or extensions before enabling it. It also has booleans for if the validation layers are present and if the VK_EXT_debug_utils extension is available.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto system_info = instance_builder.get_system_info();
|
auto system_info_ret = vkb::SystemInfo.get_system_info();
|
||||||
|
if (!system_info_ret) {
|
||||||
|
printf("%s\n", system_info_ret.error().message());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
auto system_info = system_info_ret.value();
|
||||||
if (system_info.is_layer_available("VK_LAYER_LUNARG_api_dump")) {
|
if (system_info.is_layer_available("VK_LAYER_LUNARG_api_dump")) {
|
||||||
instance_builder.enable_layer("VK_LAYER_LUNARG_api_dump");
|
instance_builder.enable_layer("VK_LAYER_LUNARG_api_dump");
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@ target_link_libraries(vk-bootstrap-triangle
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
glfw
|
glfw
|
||||||
vk-bootstrap
|
vk-bootstrap
|
||||||
vk-bootstrap-compiler-warnings)
|
vk-bootstrap-compiler-warnings
|
||||||
|
${Vulkan_LIBRARY})
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET vk-bootstrap-triangle
|
TARGET vk-bootstrap-triangle
|
||||||
|
@ -16,18 +16,185 @@
|
|||||||
|
|
||||||
#include "VkBootstrap.h"
|
#include "VkBootstrap.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <fcntl.h>
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <windows.h>
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace vkb {
|
namespace vkb {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <typename T>
|
class VulkanFunctions {
|
||||||
void get_inst_proc_addr (
|
private:
|
||||||
T& out_ptr, const char* func_name, VkInstance instance, PFN_vkGetInstanceProcAddr ptr_vkGetInstanceProcAddr) {
|
std::mutex init_mutex;
|
||||||
out_ptr = reinterpret_cast<T> (ptr_vkGetInstanceProcAddr (instance, func_name));
|
struct VulkanLibrary {
|
||||||
}
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
void* library;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
HMODULE library;
|
||||||
|
#endif
|
||||||
|
PFN_vkGetInstanceProcAddr ptr_vkGetInstanceProcAddr = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
VulkanLibrary () {
|
||||||
|
#if defined(__linux__)
|
||||||
|
library = dlopen ("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if (!library) library = dlopen ("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
library = dlopen ("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if (!library) library = dlopen ("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
library = LoadLibrary (TEXT ("vulkan-1.dll"));
|
||||||
|
#else
|
||||||
|
assert (false && "Unsupported platform");
|
||||||
|
#endif
|
||||||
|
if (!library) return;
|
||||||
|
load_func (ptr_vkGetInstanceProcAddr, "vkGetInstanceProcAddr");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void load_func (T& func_dest, const char* func_name) {
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
func_dest = reinterpret_cast<T> (dlsym (library, func_name));
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
func_dest = reinterpret_cast<T> (GetProcAddress (library, func_name));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void close () {
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
dlclose (library);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
FreeLibrary (library);
|
||||||
|
#endif
|
||||||
|
library = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
VulkanLibrary& get_vulkan_library () {
|
||||||
|
static VulkanLibrary lib;
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_vulkan (PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr) {
|
||||||
|
if (fp_vkGetInstanceProcAddr != nullptr) {
|
||||||
|
ptr_vkGetInstanceProcAddr = fp_vkGetInstanceProcAddr;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
auto& lib = get_vulkan_library ();
|
||||||
|
ptr_vkGetInstanceProcAddr = lib.ptr_vkGetInstanceProcAddr;
|
||||||
|
return lib.library != nullptr && lib.ptr_vkGetInstanceProcAddr != VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void get_proc_addr (T& out_ptr, const char* func_name) {
|
||||||
|
out_ptr = reinterpret_cast<T> (ptr_vkGetInstanceProcAddr (instance, func_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_pre_instance_funcs () {
|
||||||
|
get_proc_addr (fp_vkEnumerateInstanceExtensionProperties, "vkEnumerateInstanceExtensionProperties");
|
||||||
|
get_proc_addr (fp_vkEnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties");
|
||||||
|
get_proc_addr (fp_vkEnumerateInstanceVersion, "vkEnumerateInstanceVersion");
|
||||||
|
get_proc_addr (fp_vkCreateInstance, "vkCreateInstance");
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
PFN_vkGetInstanceProcAddr ptr_vkGetInstanceProcAddr = nullptr;
|
||||||
|
VkInstance instance = nullptr;
|
||||||
|
|
||||||
|
PFN_vkEnumerateInstanceExtensionProperties fp_vkEnumerateInstanceExtensionProperties = nullptr;
|
||||||
|
PFN_vkEnumerateInstanceLayerProperties fp_vkEnumerateInstanceLayerProperties = nullptr;
|
||||||
|
PFN_vkEnumerateInstanceVersion fp_vkEnumerateInstanceVersion = nullptr;
|
||||||
|
PFN_vkCreateInstance fp_vkCreateInstance = nullptr;
|
||||||
|
PFN_vkDestroyInstance fp_vkDestroyInstance = nullptr;
|
||||||
|
|
||||||
|
PFN_vkEnumeratePhysicalDevices fp_vkEnumeratePhysicalDevices = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceFeatures fp_vkGetPhysicalDeviceFeatures = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceFeatures2 fp_vkGetPhysicalDeviceFeatures2 = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceFormatProperties fp_vkGetPhysicalDeviceFormatProperties = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceImageFormatProperties fp_vkGetPhysicalDeviceImageFormatProperties = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceProperties fp_vkGetPhysicalDeviceProperties = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceProperties2 fp_vkGetPhysicalDeviceProperties2 = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties fp_vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties2 fp_vkGetPhysicalDeviceQueueFamilyProperties2 = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceMemoryProperties fp_vkGetPhysicalDeviceMemoryProperties = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceFormatProperties2 fp_vkGetPhysicalDeviceFormatProperties2 = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceMemoryProperties2 fp_vkGetPhysicalDeviceMemoryProperties2 = nullptr;
|
||||||
|
|
||||||
|
PFN_vkCreateDevice fp_vkCreateDevice = nullptr;
|
||||||
|
PFN_vkDestroyDevice fp_vkDestroyDevice = nullptr;
|
||||||
|
PFN_vkEnumerateDeviceExtensionProperties fp_vkEnumerateDeviceExtensionProperties = nullptr;
|
||||||
|
PFN_vkGetDeviceQueue fp_vkGetDeviceQueue = nullptr;
|
||||||
|
|
||||||
|
PFN_vkCreateImageView fp_vkCreateImageView = nullptr;
|
||||||
|
PFN_vkDestroyImageView fp_vkDestroyImageView = nullptr;
|
||||||
|
|
||||||
|
PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fp_vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fp_vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fp_vkGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fp_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
|
||||||
|
PFN_vkCreateSwapchainKHR fp_vkCreateSwapchainKHR = nullptr;
|
||||||
|
PFN_vkDestroySwapchainKHR fp_vkDestroySwapchainKHR = nullptr;
|
||||||
|
PFN_vkGetSwapchainImagesKHR fp_vkGetSwapchainImagesKHR = nullptr;
|
||||||
|
|
||||||
|
bool init_vulkan_funcs (PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr) {
|
||||||
|
std::lock_guard<std::mutex> lg (init_mutex);
|
||||||
|
if (!load_vulkan (fp_vkGetInstanceProcAddr)) return false;
|
||||||
|
init_pre_instance_funcs ();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void get_inst_proc_addr (T& out_ptr, const char* func_name) {
|
||||||
|
std::lock_guard<std::mutex> lg (init_mutex);
|
||||||
|
get_proc_addr (out_ptr, func_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_instance_funcs (VkInstance inst) {
|
||||||
|
std::lock_guard<std::mutex> lg (init_mutex);
|
||||||
|
|
||||||
|
instance = inst;
|
||||||
|
get_proc_addr (fp_vkDestroyInstance, "vkDestroyInstance");
|
||||||
|
get_proc_addr (fp_vkEnumeratePhysicalDevices, "vkEnumeratePhysicalDevices");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceFeatures, "vkGetPhysicalDeviceFeatures");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceFeatures2, "vkGetPhysicalDeviceFeatures2");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceFormatProperties, "vkGetPhysicalDeviceFormatProperties");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceImageFormatProperties, "vkGetPhysicalDeviceImageFormatProperties");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceProperties2, "vkGetPhysicalDeviceProperties2");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceQueueFamilyProperties, "vkGetPhysicalDeviceQueueFamilyProperties");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceQueueFamilyProperties2, "vkGetPhysicalDeviceQueueFamilyProperties2");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceFormatProperties2, "vkGetPhysicalDeviceFormatProperties2");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2");
|
||||||
|
|
||||||
|
get_proc_addr (fp_vkCreateDevice, "vkCreateDevice");
|
||||||
|
get_proc_addr (fp_vkDestroyDevice, "vkDestroyDevice");
|
||||||
|
get_proc_addr (fp_vkEnumerateDeviceExtensionProperties, "vkEnumerateDeviceExtensionProperties");
|
||||||
|
get_proc_addr (fp_vkGetDeviceQueue, "vkGetDeviceQueue");
|
||||||
|
|
||||||
|
get_proc_addr (fp_vkCreateImageView, "vkCreateImageView");
|
||||||
|
get_proc_addr (fp_vkDestroyImageView, "vkDestroyImageView");
|
||||||
|
|
||||||
|
get_proc_addr (fp_vkDestroySurfaceKHR, "vkDestroySurfaceKHR");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceSurfaceSupportKHR, "vkGetPhysicalDeviceSurfaceSupportKHR");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceSurfaceFormatsKHR, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceSurfacePresentModesKHR, "vkGetPhysicalDeviceSurfacePresentModesKHR");
|
||||||
|
get_proc_addr (fp_vkGetPhysicalDeviceSurfaceCapabilitiesKHR, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
|
||||||
|
get_proc_addr (fp_vkCreateSwapchainKHR, "vkCreateSwapchainKHR");
|
||||||
|
get_proc_addr (fp_vkDestroySwapchainKHR, "vkDestroySwapchainKHR");
|
||||||
|
get_proc_addr (fp_vkGetSwapchainImagesKHR, "vkGetSwapchainImagesKHR");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VulkanFunctions vk_functions;
|
||||||
|
|
||||||
// Helper for robustly executing the two-call pattern
|
// Helper for robustly executing the two-call pattern
|
||||||
template <typename T, typename F, typename... Ts>
|
template <typename T, typename F, typename... Ts>
|
||||||
@ -41,6 +208,7 @@ auto get_vector (std::vector<T>& out, F&& f, Ts&&... ts) -> VkResult {
|
|||||||
};
|
};
|
||||||
out.resize (count);
|
out.resize (count);
|
||||||
err = f (ts..., &count, out.data ());
|
err = f (ts..., &count, out.data ());
|
||||||
|
out.resize (count);
|
||||||
} while (err == VK_INCOMPLETE);
|
} while (err == VK_INCOMPLETE);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -52,6 +220,7 @@ auto get_vector_noerror (F&& f, Ts&&... ts) -> std::vector<T> {
|
|||||||
f (ts..., &count, nullptr);
|
f (ts..., &count, nullptr);
|
||||||
results.resize (count);
|
results.resize (count);
|
||||||
f (ts..., &count, results.data ());
|
f (ts..., &count, results.data ());
|
||||||
|
results.resize (count);
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -97,8 +266,7 @@ VkResult create_debug_utils_messenger (VkInstance instance,
|
|||||||
messengerCreateInfo.pfnUserCallback = debug_callback;
|
messengerCreateInfo.pfnUserCallback = debug_callback;
|
||||||
|
|
||||||
PFN_vkCreateDebugUtilsMessengerEXT createMessengerFunc;
|
PFN_vkCreateDebugUtilsMessengerEXT createMessengerFunc;
|
||||||
detail::get_inst_proc_addr (
|
detail::vk_functions.get_inst_proc_addr (createMessengerFunc, "vkCreateDebugUtilsMessengerEXT");
|
||||||
createMessengerFunc, "vkCreateDebugUtilsMessengerEXT", instance, vkGetInstanceProcAddr);
|
|
||||||
|
|
||||||
if (createMessengerFunc != nullptr) {
|
if (createMessengerFunc != nullptr) {
|
||||||
return createMessengerFunc (instance, &messengerCreateInfo, allocation_callbacks, pDebugMessenger);
|
return createMessengerFunc (instance, &messengerCreateInfo, allocation_callbacks, pDebugMessenger);
|
||||||
@ -109,9 +277,10 @@ VkResult create_debug_utils_messenger (VkInstance instance,
|
|||||||
|
|
||||||
void destroy_debug_utils_messenger (
|
void destroy_debug_utils_messenger (
|
||||||
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, VkAllocationCallbacks* allocation_callbacks) {
|
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, VkAllocationCallbacks* allocation_callbacks) {
|
||||||
|
|
||||||
PFN_vkDestroyDebugUtilsMessengerEXT deleteMessengerFunc;
|
PFN_vkDestroyDebugUtilsMessengerEXT deleteMessengerFunc;
|
||||||
detail::get_inst_proc_addr (
|
detail::vk_functions.get_inst_proc_addr (deleteMessengerFunc, "vkDestroyDebugUtilsMessengerEXT");
|
||||||
deleteMessengerFunc, "vkDestroyDebugUtilsMessengerEXT", instance, vkGetInstanceProcAddr);
|
|
||||||
if (deleteMessengerFunc != nullptr) {
|
if (deleteMessengerFunc != nullptr) {
|
||||||
deleteMessengerFunc (instance, debugMessenger, allocation_callbacks);
|
deleteMessengerFunc (instance, debugMessenger, allocation_callbacks);
|
||||||
}
|
}
|
||||||
@ -320,9 +489,22 @@ const char* to_string (SwapchainError err) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::Result<SystemInfo> SystemInfo::get_system_info () {
|
||||||
|
if (!detail::vk_functions.init_vulkan_funcs (nullptr)) {
|
||||||
|
return make_error_code (InstanceError::vulkan_unavailable);
|
||||||
|
}
|
||||||
|
return SystemInfo ();
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::Result<SystemInfo> SystemInfo::get_system_info (PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr) {
|
||||||
|
// Using externally provided function pointers, assume the loader is available
|
||||||
|
detail::vk_functions.init_vulkan_funcs (fp_vkGetInstanceProcAddr);
|
||||||
|
return SystemInfo ();
|
||||||
|
}
|
||||||
|
|
||||||
SystemInfo::SystemInfo () {
|
SystemInfo::SystemInfo () {
|
||||||
auto available_layers_ret =
|
auto available_layers_ret = detail::get_vector<VkLayerProperties> (
|
||||||
detail::get_vector<VkLayerProperties> (this->available_layers, vkEnumerateInstanceLayerProperties);
|
this->available_layers, detail::vk_functions.fp_vkEnumerateInstanceLayerProperties);
|
||||||
if (available_layers_ret != VK_SUCCESS) {
|
if (available_layers_ret != VK_SUCCESS) {
|
||||||
this->available_layers.clear ();
|
this->available_layers.clear ();
|
||||||
}
|
}
|
||||||
@ -332,7 +514,7 @@ SystemInfo::SystemInfo () {
|
|||||||
validation_layers_available = true;
|
validation_layers_available = true;
|
||||||
|
|
||||||
auto available_extensions_ret = detail::get_vector<VkExtensionProperties> (
|
auto available_extensions_ret = detail::get_vector<VkExtensionProperties> (
|
||||||
this->available_extensions, vkEnumerateInstanceExtensionProperties, nullptr);
|
this->available_extensions, detail::vk_functions.fp_vkEnumerateInstanceExtensionProperties, nullptr);
|
||||||
if (available_extensions_ret != VK_SUCCESS) {
|
if (available_extensions_ret != VK_SUCCESS) {
|
||||||
this->available_extensions.clear ();
|
this->available_extensions.clear ();
|
||||||
}
|
}
|
||||||
@ -344,7 +526,7 @@ SystemInfo::SystemInfo () {
|
|||||||
for (auto& layer : this->available_layers) {
|
for (auto& layer : this->available_layers) {
|
||||||
std::vector<VkExtensionProperties> layer_extensions;
|
std::vector<VkExtensionProperties> layer_extensions;
|
||||||
auto layer_extensions_ret = detail::get_vector<VkExtensionProperties> (
|
auto layer_extensions_ret = detail::get_vector<VkExtensionProperties> (
|
||||||
layer_extensions, vkEnumerateInstanceExtensionProperties, layer.layerName);
|
layer_extensions, detail::vk_functions.fp_vkEnumerateInstanceExtensionProperties, layer.layerName);
|
||||||
if (layer_extensions_ret != VK_SUCCESS) {
|
if (layer_extensions_ret != VK_SUCCESS) {
|
||||||
for (auto& ext : layer_extensions)
|
for (auto& ext : layer_extensions)
|
||||||
if (strcmp (ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
|
if (strcmp (ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
|
||||||
@ -365,21 +547,27 @@ void destroy_instance (Instance instance) {
|
|||||||
if (instance.instance != VK_NULL_HANDLE) {
|
if (instance.instance != VK_NULL_HANDLE) {
|
||||||
if (instance.debug_messenger != nullptr)
|
if (instance.debug_messenger != nullptr)
|
||||||
destroy_debug_utils_messenger (instance.instance, instance.debug_messenger, instance.allocation_callbacks);
|
destroy_debug_utils_messenger (instance.instance, instance.debug_messenger, instance.allocation_callbacks);
|
||||||
vkDestroyInstance (instance.instance, instance.allocation_callbacks);
|
detail::vk_functions.fp_vkDestroyInstance (instance.instance, instance.allocation_callbacks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemInfo InstanceBuilder::get_system_info () const { return system; }
|
InstanceBuilder::InstanceBuilder (PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr) {
|
||||||
|
info.fp_vkGetInstanceProcAddr = fp_vkGetInstanceProcAddr;
|
||||||
|
}
|
||||||
|
InstanceBuilder::InstanceBuilder () {}
|
||||||
|
|
||||||
detail::Result<Instance> InstanceBuilder::build () const {
|
detail::Result<Instance> InstanceBuilder::build () const {
|
||||||
|
|
||||||
|
auto sys_info_ret = SystemInfo::get_system_info ();
|
||||||
|
if (!sys_info_ret) return sys_info_ret.error ();
|
||||||
|
auto system = sys_info_ret.value ();
|
||||||
|
|
||||||
uint32_t api_version = VK_MAKE_VERSION (1, 0, 0);
|
uint32_t api_version = VK_MAKE_VERSION (1, 0, 0);
|
||||||
|
|
||||||
if (info.required_api_version > VK_MAKE_VERSION (1, 0, 0) ||
|
if (info.required_api_version > VK_MAKE_VERSION (1, 0, 0) ||
|
||||||
info.desired_api_version > VK_MAKE_VERSION (1, 0, 0)) {
|
info.desired_api_version > VK_MAKE_VERSION (1, 0, 0)) {
|
||||||
PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion;
|
PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion =
|
||||||
detail::get_inst_proc_addr (
|
detail::vk_functions.fp_vkEnumerateInstanceVersion;
|
||||||
pfn_vkEnumerateInstanceVersion, "vkEnumerateInstanceVersion", nullptr, vkGetInstanceProcAddr);
|
|
||||||
|
|
||||||
uint32_t queried_api_version = VK_MAKE_VERSION (1, 0, 0);
|
uint32_t queried_api_version = VK_MAKE_VERSION (1, 0, 0);
|
||||||
if (pfn_vkEnumerateInstanceVersion != nullptr) {
|
if (pfn_vkEnumerateInstanceVersion != nullptr) {
|
||||||
@ -455,7 +643,7 @@ detail::Result<Instance> InstanceBuilder::build () const {
|
|||||||
for (auto& layer : info.layers)
|
for (auto& layer : info.layers)
|
||||||
layers.push_back (layer);
|
layers.push_back (layer);
|
||||||
|
|
||||||
if (info.enable_validation_layers) {
|
if (info.enable_validation_layers || (info.request_validation_layers && system.validation_layers_available)) {
|
||||||
layers.push_back (detail::validation_layer_name);
|
layers.push_back (detail::validation_layer_name);
|
||||||
}
|
}
|
||||||
bool all_layers_supported = detail::check_layers_supported (system.available_layers, layers);
|
bool all_layers_supported = detail::check_layers_supported (system.available_layers, layers);
|
||||||
@ -509,10 +697,13 @@ detail::Result<Instance> InstanceBuilder::build () const {
|
|||||||
instance_create_info.ppEnabledLayerNames = layers.data ();
|
instance_create_info.ppEnabledLayerNames = layers.data ();
|
||||||
|
|
||||||
Instance instance;
|
Instance instance;
|
||||||
VkResult res = vkCreateInstance (&instance_create_info, info.allocation_callbacks, &instance.instance);
|
VkResult res = detail::vk_functions.fp_vkCreateInstance (
|
||||||
|
&instance_create_info, info.allocation_callbacks, &instance.instance);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
return detail::Result<Instance> (InstanceError::failed_create_instance, res);
|
return detail::Result<Instance> (InstanceError::failed_create_instance, res);
|
||||||
|
|
||||||
|
detail::vk_functions.init_instance_funcs (instance.instance);
|
||||||
|
|
||||||
if (info.use_debug_messenger) {
|
if (info.use_debug_messenger) {
|
||||||
res = create_debug_utils_messenger (instance.instance,
|
res = create_debug_utils_messenger (instance.instance,
|
||||||
info.debug_callback,
|
info.debug_callback,
|
||||||
@ -530,6 +721,7 @@ detail::Result<Instance> InstanceBuilder::build () const {
|
|||||||
}
|
}
|
||||||
instance.allocation_callbacks = info.allocation_callbacks;
|
instance.allocation_callbacks = info.allocation_callbacks;
|
||||||
instance.instance_version = api_version;
|
instance.instance_version = api_version;
|
||||||
|
instance.fp_vkGetInstanceProcAddr = detail::vk_functions.ptr_vkGetInstanceProcAddr;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,9 +766,7 @@ InstanceBuilder& InstanceBuilder::enable_validation_layers (bool enable_validati
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
InstanceBuilder& InstanceBuilder::request_validation_layers (bool enable_validation) {
|
InstanceBuilder& InstanceBuilder::request_validation_layers (bool enable_validation) {
|
||||||
info.enable_validation_layers =
|
info.request_validation_layers = enable_validation;
|
||||||
enable_validation &&
|
|
||||||
detail::check_layer_supported (system.available_layers, detail::validation_layer_name);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
InstanceBuilder& InstanceBuilder::use_default_debug_messenger () {
|
InstanceBuilder& InstanceBuilder::use_default_debug_messenger () {
|
||||||
@ -634,7 +824,7 @@ std::vector<const char*> check_device_extension_support (
|
|||||||
VkPhysicalDevice device, std::vector<const char*> desired_extensions) {
|
VkPhysicalDevice device, std::vector<const char*> desired_extensions) {
|
||||||
std::vector<VkExtensionProperties> available_extensions;
|
std::vector<VkExtensionProperties> available_extensions;
|
||||||
auto available_extensions_ret = detail::get_vector<VkExtensionProperties> (
|
auto available_extensions_ret = detail::get_vector<VkExtensionProperties> (
|
||||||
available_extensions, vkEnumerateDeviceExtensionProperties, device, nullptr);
|
available_extensions, detail::vk_functions.fp_vkEnumerateDeviceExtensionProperties, device, nullptr);
|
||||||
if (available_extensions_ret != VK_SUCCESS) return {};
|
if (available_extensions_ret != VK_SUCCESS) return {};
|
||||||
|
|
||||||
std::vector<const char*> extensions_to_enable;
|
std::vector<const char*> extensions_to_enable;
|
||||||
@ -776,7 +966,7 @@ int get_present_queue_index (VkPhysicalDevice const phys_device,
|
|||||||
for (size_t i = 0; i < families.size (); i++) {
|
for (size_t i = 0; i < families.size (); i++) {
|
||||||
VkBool32 presentSupport = false;
|
VkBool32 presentSupport = false;
|
||||||
if (surface != VK_NULL_HANDLE) {
|
if (surface != VK_NULL_HANDLE) {
|
||||||
VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR (
|
VkResult res = detail::vk_functions.fp_vkGetPhysicalDeviceSurfaceSupportKHR (
|
||||||
phys_device, static_cast<uint32_t> (i), surface, &presentSupport);
|
phys_device, static_cast<uint32_t> (i), surface, &presentSupport);
|
||||||
if (res != VK_SUCCESS) return -1; // TODO: determine if this should fail another way
|
if (res != VK_SUCCESS) return -1; // TODO: determine if this should fail another way
|
||||||
}
|
}
|
||||||
@ -792,12 +982,12 @@ PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_devi
|
|||||||
PhysicalDeviceSelector::PhysicalDeviceDesc desc{};
|
PhysicalDeviceSelector::PhysicalDeviceDesc desc{};
|
||||||
desc.phys_device = phys_device;
|
desc.phys_device = phys_device;
|
||||||
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties> (
|
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties> (
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties, phys_device);
|
detail::vk_functions.fp_vkGetPhysicalDeviceQueueFamilyProperties, phys_device);
|
||||||
desc.queue_families = queue_families;
|
desc.queue_families = queue_families;
|
||||||
|
|
||||||
vkGetPhysicalDeviceProperties (phys_device, &desc.device_properties);
|
detail::vk_functions.fp_vkGetPhysicalDeviceProperties (phys_device, &desc.device_properties);
|
||||||
vkGetPhysicalDeviceFeatures (phys_device, &desc.device_features);
|
detail::vk_functions.fp_vkGetPhysicalDeviceFeatures (phys_device, &desc.device_features);
|
||||||
vkGetPhysicalDeviceMemoryProperties (phys_device, &desc.mem_properties);
|
detail::vk_functions.fp_vkGetPhysicalDeviceMemoryProperties (phys_device, &desc.mem_properties);
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -840,10 +1030,14 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable (Phy
|
|||||||
std::vector<VkSurfaceFormatKHR> formats;
|
std::vector<VkSurfaceFormatKHR> formats;
|
||||||
std::vector<VkPresentModeKHR> present_modes;
|
std::vector<VkPresentModeKHR> present_modes;
|
||||||
|
|
||||||
auto formats_ret = detail::get_vector<VkSurfaceFormatKHR> (
|
auto formats_ret = detail::get_vector<VkSurfaceFormatKHR> (formats,
|
||||||
formats, vkGetPhysicalDeviceSurfaceFormatsKHR, pd.phys_device, system_info.surface);
|
detail::vk_functions.fp_vkGetPhysicalDeviceSurfaceFormatsKHR,
|
||||||
auto present_modes_ret = detail::get_vector<VkPresentModeKHR> (
|
pd.phys_device,
|
||||||
present_modes, vkGetPhysicalDeviceSurfacePresentModesKHR, pd.phys_device, system_info.surface);
|
system_info.surface);
|
||||||
|
auto present_modes_ret = detail::get_vector<VkPresentModeKHR> (present_modes,
|
||||||
|
detail::vk_functions.fp_vkGetPhysicalDeviceSurfacePresentModesKHR,
|
||||||
|
pd.phys_device,
|
||||||
|
system_info.surface);
|
||||||
|
|
||||||
if (formats_ret == VK_SUCCESS && present_modes_ret == VK_SUCCESS) {
|
if (formats_ret == VK_SUCCESS && present_modes_ret == VK_SUCCESS) {
|
||||||
swapChainAdequate = !formats.empty () && !present_modes.empty ();
|
swapChainAdequate = !formats.empty () && !present_modes.empty ();
|
||||||
@ -898,7 +1092,7 @@ detail::Result<PhysicalDevice> PhysicalDeviceSelector::select () const {
|
|||||||
std::vector<VkPhysicalDevice> physical_devices;
|
std::vector<VkPhysicalDevice> physical_devices;
|
||||||
|
|
||||||
auto physical_devices_ret = detail::get_vector<VkPhysicalDevice> (
|
auto physical_devices_ret = detail::get_vector<VkPhysicalDevice> (
|
||||||
physical_devices, vkEnumeratePhysicalDevices, system_info.instance);
|
physical_devices, detail::vk_functions.fp_vkEnumeratePhysicalDevices, system_info.instance);
|
||||||
if (physical_devices_ret != VK_SUCCESS) {
|
if (physical_devices_ret != VK_SUCCESS) {
|
||||||
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::failed_enumerate_physical_devices,
|
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::failed_enumerate_physical_devices,
|
||||||
physical_devices_ret };
|
physical_devices_ret };
|
||||||
@ -1092,7 +1286,7 @@ detail::Result<uint32_t> Device::get_dedicated_queue_index (QueueType type) cons
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
VkQueue get_queue (VkDevice device, uint32_t family) {
|
VkQueue get_queue (VkDevice device, uint32_t family) {
|
||||||
VkQueue out_queue;
|
VkQueue out_queue;
|
||||||
vkGetDeviceQueue (device, family, 0, &out_queue);
|
detail::vk_functions.fp_vkGetDeviceQueue (device, family, 0, &out_queue);
|
||||||
return out_queue;
|
return out_queue;
|
||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -1115,7 +1309,7 @@ CustomQueueDescription::CustomQueueDescription (uint32_t index, uint32_t count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void destroy_device (Device device) {
|
void destroy_device (Device device) {
|
||||||
vkDestroyDevice (device.device, device.allocation_callbacks);
|
detail::vk_functions.fp_vkDestroyDevice (device.device, device.allocation_callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceBuilder::DeviceBuilder (PhysicalDevice phys_device) {
|
DeviceBuilder::DeviceBuilder (PhysicalDevice phys_device) {
|
||||||
@ -1135,7 +1329,7 @@ detail::Result<Device> DeviceBuilder::build () const {
|
|||||||
|
|
||||||
if (queue_descriptions.size () == 0) {
|
if (queue_descriptions.size () == 0) {
|
||||||
for (uint32_t i = 0; i < info.queue_families.size (); i++) {
|
for (uint32_t i = 0; i < info.queue_families.size (); i++) {
|
||||||
queue_descriptions.push_back ({ i, 1, std::vector<float>{ 1.0f } });
|
queue_descriptions.push_back (CustomQueueDescription{ i, 1, std::vector<float>{ 1.0f } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1174,7 +1368,7 @@ detail::Result<Device> DeviceBuilder::build () const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Device device;
|
Device device;
|
||||||
VkResult res = vkCreateDevice (info.physical_device.physical_device,
|
VkResult res = detail::vk_functions.fp_vkCreateDevice (info.physical_device.physical_device,
|
||||||
&device_create_info,
|
&device_create_info,
|
||||||
info.allocation_callbacks,
|
info.allocation_callbacks,
|
||||||
&device.device);
|
&device.device);
|
||||||
@ -1240,7 +1434,8 @@ Result<SurfaceSupportDetails> query_surface_support_details (VkPhysicalDevice ph
|
|||||||
return make_error_code (SurfaceSupportError::surface_handle_null);
|
return make_error_code (SurfaceSupportError::surface_handle_null);
|
||||||
|
|
||||||
VkSurfaceCapabilitiesKHR capabilities;
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities);
|
VkResult res = detail::vk_functions.fp_vkGetPhysicalDeviceSurfaceCapabilitiesKHR (
|
||||||
|
phys_device, surface, &capabilities);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
return { make_error_code (SurfaceSupportError::failed_get_surface_capabilities), res };
|
return { make_error_code (SurfaceSupportError::failed_get_surface_capabilities), res };
|
||||||
}
|
}
|
||||||
@ -1249,11 +1444,11 @@ Result<SurfaceSupportDetails> query_surface_support_details (VkPhysicalDevice ph
|
|||||||
std::vector<VkPresentModeKHR> present_modes;
|
std::vector<VkPresentModeKHR> present_modes;
|
||||||
|
|
||||||
auto formats_ret = detail::get_vector<VkSurfaceFormatKHR> (
|
auto formats_ret = detail::get_vector<VkSurfaceFormatKHR> (
|
||||||
formats, vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
|
formats, detail::vk_functions.fp_vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
|
||||||
if (formats_ret != VK_SUCCESS)
|
if (formats_ret != VK_SUCCESS)
|
||||||
return { make_error_code (SurfaceSupportError::failed_enumerate_surface_formats), formats_ret };
|
return { make_error_code (SurfaceSupportError::failed_enumerate_surface_formats), formats_ret };
|
||||||
auto present_modes_ret = detail::get_vector<VkPresentModeKHR> (
|
auto present_modes_ret = detail::get_vector<VkPresentModeKHR> (
|
||||||
present_modes, vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface);
|
present_modes, detail::vk_functions.fp_vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface);
|
||||||
if (present_modes_ret != VK_SUCCESS)
|
if (present_modes_ret != VK_SUCCESS)
|
||||||
return { make_error_code (SurfaceSupportError::failed_enumerate_present_modes), present_modes_ret };
|
return { make_error_code (SurfaceSupportError::failed_enumerate_present_modes), present_modes_ret };
|
||||||
|
|
||||||
@ -1310,8 +1505,8 @@ VkExtent2D find_extent (
|
|||||||
|
|
||||||
void destroy_swapchain (Swapchain const& swapchain) {
|
void destroy_swapchain (Swapchain const& swapchain) {
|
||||||
if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE) {
|
if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE) {
|
||||||
vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocation_callbacks);
|
detail::vk_functions.fp_vkDestroySwapchainKHR (
|
||||||
|
swapchain.device, swapchain.swapchain, swapchain.allocation_callbacks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1404,7 +1599,7 @@ detail::Result<Swapchain> SwapchainBuilder::build () const {
|
|||||||
swapchain_create_info.clipped = info.clipped;
|
swapchain_create_info.clipped = info.clipped;
|
||||||
swapchain_create_info.oldSwapchain = info.old_swapchain;
|
swapchain_create_info.oldSwapchain = info.old_swapchain;
|
||||||
Swapchain swapchain{};
|
Swapchain swapchain{};
|
||||||
VkResult res = vkCreateSwapchainKHR (
|
VkResult res = detail::vk_functions.fp_vkCreateSwapchainKHR (
|
||||||
info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain);
|
info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
return detail::Error{ SwapchainError::failed_create_swapchain, res };
|
return detail::Error{ SwapchainError::failed_create_swapchain, res };
|
||||||
@ -1423,8 +1618,8 @@ detail::Result<Swapchain> SwapchainBuilder::build () const {
|
|||||||
detail::Result<std::vector<VkImage>> Swapchain::get_images () {
|
detail::Result<std::vector<VkImage>> Swapchain::get_images () {
|
||||||
std::vector<VkImage> swapchain_images;
|
std::vector<VkImage> swapchain_images;
|
||||||
|
|
||||||
auto swapchain_images_ret =
|
auto swapchain_images_ret = detail::get_vector<VkImage> (
|
||||||
detail::get_vector<VkImage> (swapchain_images, vkGetSwapchainImagesKHR, device, swapchain);
|
swapchain_images, detail::vk_functions.fp_vkGetSwapchainImagesKHR, device, swapchain);
|
||||||
if (swapchain_images_ret != VK_SUCCESS) {
|
if (swapchain_images_ret != VK_SUCCESS) {
|
||||||
return detail::Error{ SwapchainError::failed_get_swapchain_images, swapchain_images_ret };
|
return detail::Error{ SwapchainError::failed_get_swapchain_images, swapchain_images_ret };
|
||||||
}
|
}
|
||||||
@ -1454,7 +1649,8 @@ detail::Result<std::vector<VkImageView>> Swapchain::get_image_views () {
|
|||||||
createInfo.subresourceRange.baseArrayLayer = 0;
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
createInfo.subresourceRange.layerCount = 1;
|
createInfo.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
VkResult res = vkCreateImageView (device, &createInfo, allocation_callbacks, &views[i]);
|
VkResult res = detail::vk_functions.fp_vkCreateImageView (
|
||||||
|
device, &createInfo, allocation_callbacks, &views[i]);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
return detail::Error{ SwapchainError::failed_create_swapchain_image_views, res };
|
return detail::Error{ SwapchainError::failed_create_swapchain_image_views, res };
|
||||||
}
|
}
|
||||||
@ -1462,7 +1658,7 @@ detail::Result<std::vector<VkImageView>> Swapchain::get_image_views () {
|
|||||||
}
|
}
|
||||||
void Swapchain::destroy_image_views (std::vector<VkImageView> const& image_views) {
|
void Swapchain::destroy_image_views (std::vector<VkImageView> const& image_views) {
|
||||||
for (auto& image_view : image_views) {
|
for (auto& image_view : image_views) {
|
||||||
vkDestroyImageView (device, image_view, allocation_callbacks);
|
detail::vk_functions.fp_vkDestroyImageView (device, image_view, allocation_callbacks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SwapchainBuilder& SwapchainBuilder::set_old_swapchain (VkSwapchainKHR old_swapchain) {
|
SwapchainBuilder& SwapchainBuilder::set_old_swapchain (VkSwapchainKHR old_swapchain) {
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
|
||||||
namespace vkb {
|
namespace vkb {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -111,7 +112,6 @@ template <typename T> class Result {
|
|||||||
bool m_init;
|
bool m_init;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO implement operator == and operator != as friend or global */
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
enum class InstanceError {
|
enum class InstanceError {
|
||||||
@ -165,9 +165,18 @@ const char* to_string (QueueError err);
|
|||||||
const char* to_string (DeviceError err);
|
const char* to_string (DeviceError err);
|
||||||
const char* to_string (SwapchainError err);
|
const char* to_string (SwapchainError err);
|
||||||
|
|
||||||
|
// Gathers useful information about the available vulkan capabilities, like layers and instance extensions.
|
||||||
|
// Use this for enabling features conditionally, ie if you would like an extension but can use a fallback if
|
||||||
|
// it isn't supported but need to know if support is available first.
|
||||||
struct SystemInfo {
|
struct SystemInfo {
|
||||||
|
private:
|
||||||
SystemInfo ();
|
SystemInfo ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Use get_system_info to create a SystemInfo struct. This is because loading vulkan could fail.
|
||||||
|
static detail::Result<SystemInfo> get_system_info ();
|
||||||
|
static detail::Result<SystemInfo> get_system_info (PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
|
||||||
|
|
||||||
// Returns true if a layer is available
|
// Returns true if a layer is available
|
||||||
bool is_layer_available (const char* layer_name) const;
|
bool is_layer_available (const char* layer_name) const;
|
||||||
// Returns true if an extension is available
|
// Returns true if an extension is available
|
||||||
@ -179,6 +188,7 @@ struct SystemInfo {
|
|||||||
bool debug_utils_available = false;
|
bool debug_utils_available = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class InstanceBuilder;
|
class InstanceBuilder;
|
||||||
class PhysicalDeviceSelector;
|
class PhysicalDeviceSelector;
|
||||||
|
|
||||||
@ -187,6 +197,8 @@ struct Instance {
|
|||||||
VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
|
VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
|
||||||
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
|
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool headless = false;
|
bool headless = false;
|
||||||
uint32_t instance_version = VK_MAKE_VERSION (1, 0, 0);
|
uint32_t instance_version = VK_MAKE_VERSION (1, 0, 0);
|
||||||
@ -199,8 +211,10 @@ void destroy_instance (Instance instance); // release instance resources
|
|||||||
|
|
||||||
class InstanceBuilder {
|
class InstanceBuilder {
|
||||||
public:
|
public:
|
||||||
// contains useful information about the available vulkan capabilities, like layers and instance extensions.
|
// Default constructor, will load vulkan.
|
||||||
SystemInfo get_system_info () const;
|
explicit InstanceBuilder ();
|
||||||
|
// Optional: Can use your own PFN_vkGetInstanceProcAddr
|
||||||
|
explicit InstanceBuilder (PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
|
||||||
|
|
||||||
// Create a VkInstance. Return an error if it failed.
|
// Create a VkInstance. Return an error if it failed.
|
||||||
detail::Result<Instance> build () const;
|
detail::Result<Instance> build () const;
|
||||||
@ -291,25 +305,15 @@ class InstanceBuilder {
|
|||||||
// Custom allocator
|
// Custom allocator
|
||||||
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
|
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
bool request_validation_layers = false;
|
||||||
bool enable_validation_layers = false;
|
bool enable_validation_layers = false;
|
||||||
bool use_debug_messenger = false;
|
bool use_debug_messenger = false;
|
||||||
bool headless_context = false;
|
bool headless_context = false;
|
||||||
|
|
||||||
|
PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr;
|
||||||
} info;
|
} info;
|
||||||
|
|
||||||
SystemInfo system;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VkResult create_debug_utils_messenger (VkInstance instance,
|
|
||||||
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback,
|
|
||||||
VkDebugUtilsMessageSeverityFlagsEXT severity,
|
|
||||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
|
||||||
VkDebugUtilsMessengerEXT* pDebugMessenger,
|
|
||||||
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE);
|
|
||||||
|
|
||||||
void destroy_debug_utils_messenger (VkInstance instance,
|
|
||||||
VkDebugUtilsMessengerEXT debugMessenger,
|
|
||||||
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE);
|
|
||||||
|
|
||||||
VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
@ -359,7 +363,7 @@ enum class PreferredDeviceType {
|
|||||||
class PhysicalDeviceSelector {
|
class PhysicalDeviceSelector {
|
||||||
public:
|
public:
|
||||||
// Requires a vkb::Instance to construct, needed to pass instance creation info.
|
// Requires a vkb::Instance to construct, needed to pass instance creation info.
|
||||||
PhysicalDeviceSelector (Instance const& instance);
|
explicit PhysicalDeviceSelector (Instance const& instance);
|
||||||
|
|
||||||
detail::Result<PhysicalDevice> select () const;
|
detail::Result<PhysicalDevice> select () const;
|
||||||
|
|
||||||
@ -482,7 +486,7 @@ struct Device {
|
|||||||
|
|
||||||
// For advanced device queue setup
|
// For advanced device queue setup
|
||||||
struct CustomQueueDescription {
|
struct CustomQueueDescription {
|
||||||
CustomQueueDescription (uint32_t index, uint32_t count, std::vector<float> priorities);
|
explicit CustomQueueDescription (uint32_t index, uint32_t count, std::vector<float> priorities);
|
||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
std::vector<float> priorities;
|
std::vector<float> priorities;
|
||||||
@ -493,7 +497,7 @@ void destroy_device (Device device);
|
|||||||
class DeviceBuilder {
|
class DeviceBuilder {
|
||||||
public:
|
public:
|
||||||
// Any features and extensions that are requested/required in PhysicalDeviceSelector are automatically enabled.
|
// Any features and extensions that are requested/required in PhysicalDeviceSelector are automatically enabled.
|
||||||
DeviceBuilder (PhysicalDevice physical_device);
|
explicit DeviceBuilder (PhysicalDevice physical_device);
|
||||||
|
|
||||||
detail::Result<Device> build () const;
|
detail::Result<Device> build () const;
|
||||||
|
|
||||||
@ -548,8 +552,8 @@ void destroy_swapchain (Swapchain const& swapchain);
|
|||||||
|
|
||||||
class SwapchainBuilder {
|
class SwapchainBuilder {
|
||||||
public:
|
public:
|
||||||
SwapchainBuilder (Device const& device);
|
explicit SwapchainBuilder (Device const& device);
|
||||||
SwapchainBuilder (Device const& device, VkSurfaceKHR const surface);
|
explicit SwapchainBuilder (Device const& device, VkSurfaceKHR const surface);
|
||||||
|
|
||||||
detail::Result<Swapchain> build () const;
|
detail::Result<Swapchain> build () const;
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
add_executable(vk-bootstrap-test main.cpp bootstrap_tests.cpp error_code_tests.cpp)
|
add_executable(vk-bootstrap-test main.cpp bootstrap_tests.cpp error_code_tests.cpp)
|
||||||
target_link_libraries(vk-bootstrap-test
|
target_link_libraries(vk-bootstrap-test
|
||||||
PRIVATE
|
PRIVATE
|
||||||
vk-bootstrap
|
vk-bootstrap
|
||||||
vk-bootstrap-compiler-warnings
|
vk-bootstrap-compiler-warnings
|
||||||
glfw
|
glfw
|
||||||
Catch2
|
Catch2
|
||||||
)
|
)
|
@ -3,16 +3,22 @@
|
|||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Getting queues
|
|
||||||
// get dedicated vs distinct compute queues
|
|
||||||
|
|
||||||
// changing present modes and/or image formats
|
// changing present modes and/or image formats
|
||||||
|
|
||||||
|
void destroy_surface (vkb::detail::Result<vkb::Instance> instance_ret, VkSurfaceKHR surface) {
|
||||||
|
PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = reinterpret_cast<PFN_vkDestroySurfaceKHR> (
|
||||||
|
instance_ret->fp_vkGetInstanceProcAddr (instance_ret->instance, "vkDestroySurfaceKHR"));
|
||||||
|
fp_vkDestroySurfaceKHR (instance_ret->instance, surface, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE ("Instance with surface", "[VkBootstrap.bootstrap]") {
|
TEST_CASE ("Instance with surface", "[VkBootstrap.bootstrap]") {
|
||||||
GIVEN ("A window and a vulkan instance") {
|
GIVEN ("A window and a vulkan instance") {
|
||||||
|
|
||||||
auto window = create_window_glfw ("Instance with surface");
|
auto window = create_window_glfw ("Instance with surface");
|
||||||
|
|
||||||
|
auto sys_info_ret = vkb::SystemInfo::get_system_info ();
|
||||||
|
REQUIRE (sys_info_ret);
|
||||||
|
|
||||||
vkb::InstanceBuilder instance_builder;
|
vkb::InstanceBuilder instance_builder;
|
||||||
auto instance_ret = instance_builder.use_default_debug_messenger ().build ();
|
auto instance_ret = instance_builder.use_default_debug_messenger ().build ();
|
||||||
REQUIRE (instance_ret);
|
REQUIRE (instance_ret);
|
||||||
@ -48,7 +54,7 @@ TEST_CASE ("Instance with surface", "[VkBootstrap.bootstrap]") {
|
|||||||
REQUIRE (phys_dev_ret.has_value ());
|
REQUIRE (phys_dev_ret.has_value ());
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_surface (instance.instance, surface);
|
destroy_surface (instance_ret, surface);
|
||||||
vkb::destroy_instance (instance);
|
vkb::destroy_instance (instance);
|
||||||
destroy_window_glfw (window);
|
destroy_window_glfw (window);
|
||||||
}
|
}
|
||||||
@ -176,7 +182,7 @@ TEST_CASE ("Device Configuration", "[VkBootstrap.bootstrap]") {
|
|||||||
vkb::destroy_device (device_ret.value ());
|
vkb::destroy_device (device_ret.value ());
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_surface (instance_ret.value ().instance, surface);
|
destroy_surface (instance_ret, surface);
|
||||||
vkb::destroy_instance (instance_ret.value ());
|
vkb::destroy_instance (instance_ret.value ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +264,7 @@ TEST_CASE ("Swapchain", "[VkBootstrap.bootstrap]") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vkb::destroy_device (device_ret.value ());
|
vkb::destroy_device (device_ret.value ());
|
||||||
destroy_surface (instance_ret.value ().instance, surface);
|
destroy_surface (instance_ret, surface);
|
||||||
vkb::destroy_instance (instance_ret.value ());
|
vkb::destroy_instance (instance_ret.value ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,6 +313,70 @@ TEST_CASE ("Allocation Callbacks", "[VkBootstrap.bootstrap]") {
|
|||||||
vkb::destroy_swapchain (swapchain_ret.value ());
|
vkb::destroy_swapchain (swapchain_ret.value ());
|
||||||
vkb::destroy_device (device_ret.value ());
|
vkb::destroy_device (device_ret.value ());
|
||||||
|
|
||||||
destroy_surface (instance_ret.value ().instance, surface);
|
destroy_surface (instance_ret, surface);
|
||||||
vkb::destroy_instance (instance_ret.value ());
|
vkb::destroy_instance (instance_ret.value ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE ("SystemInfo Loading Vulkan Automatically", "[VkBootstrap.loading]") {
|
||||||
|
auto info_ret = vkb::SystemInfo::get_system_info ();
|
||||||
|
REQUIRE (info_ret);
|
||||||
|
vkb::InstanceBuilder builder;
|
||||||
|
auto ret = builder.build ();
|
||||||
|
REQUIRE (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE ("SystemInfo Loading Vulkan Manually", "[VkBootstrap.loading]") {
|
||||||
|
VulkanLibrary vk_lib;
|
||||||
|
REQUIRE (vk_lib.ptr_vkGetInstanceProcAddr != NULL);
|
||||||
|
auto info_ret = vkb::SystemInfo::get_system_info (vk_lib.ptr_vkGetInstanceProcAddr);
|
||||||
|
REQUIRE (info_ret);
|
||||||
|
vkb::InstanceBuilder builder;
|
||||||
|
auto ret = builder.build ();
|
||||||
|
REQUIRE (ret);
|
||||||
|
vk_lib.close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE ("InstanceBuilder Loading Vulkan Automatically", "[VkBootstrap.loading]") {
|
||||||
|
vkb::InstanceBuilder builder;
|
||||||
|
auto ret = builder.build ();
|
||||||
|
REQUIRE (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE ("InstanceBuilder Loading Vulkan Manually", "[VkBootstrap.loading]") {
|
||||||
|
VulkanLibrary vk_lib;
|
||||||
|
REQUIRE (vk_lib.ptr_vkGetInstanceProcAddr != NULL);
|
||||||
|
vkb::InstanceBuilder builder{ vk_lib.ptr_vkGetInstanceProcAddr };
|
||||||
|
auto ret = builder.build ();
|
||||||
|
vk_lib.close ();
|
||||||
|
}
|
||||||
|
TEST_CASE ("ReLoading Vulkan Automatically", "[VkBootstrap.loading]") {
|
||||||
|
{
|
||||||
|
vkb::InstanceBuilder builder;
|
||||||
|
auto ret = builder.build ();
|
||||||
|
REQUIRE(ret);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
vkb::InstanceBuilder builder;
|
||||||
|
auto ret = builder.build ();
|
||||||
|
REQUIRE(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE ("ReLoading Vulkan Manually", "[VkBootstrap.loading]") {
|
||||||
|
{
|
||||||
|
VulkanLibrary vk_lib;
|
||||||
|
REQUIRE (vk_lib.ptr_vkGetInstanceProcAddr != NULL);
|
||||||
|
vkb::InstanceBuilder builder{ vk_lib.ptr_vkGetInstanceProcAddr };
|
||||||
|
auto ret = builder.build ();
|
||||||
|
REQUIRE(ret);
|
||||||
|
vk_lib.close ();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
VulkanLibrary vk_lib;
|
||||||
|
REQUIRE (vk_lib.ptr_vkGetInstanceProcAddr != NULL);
|
||||||
|
vkb::InstanceBuilder builder{ vk_lib.ptr_vkGetInstanceProcAddr };
|
||||||
|
auto ret = builder.build ();
|
||||||
|
REQUIRE(ret);
|
||||||
|
vk_lib.close ();
|
||||||
|
}
|
||||||
|
}
|
@ -5,17 +5,27 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <fcntl.h>
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <windows.h>
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
#include "../src/VkBootstrap.h"
|
#include "../src/VkBootstrap.h"
|
||||||
|
|
||||||
GLFWwindow* create_window_glfw (const char * window_name = "", bool resize = true) {
|
GLFWwindow* create_window_glfw (const char* window_name = "", bool resize = true) {
|
||||||
glfwInit ();
|
glfwInit ();
|
||||||
glfwWindowHint (GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint (GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
if (!resize) glfwWindowHint (GLFW_RESIZABLE, GLFW_FALSE);
|
if (!resize) glfwWindowHint (GLFW_RESIZABLE, GLFW_FALSE);
|
||||||
|
|
||||||
return glfwCreateWindow (1024,1024, window_name, NULL, NULL);
|
return glfwCreateWindow (1024, 1024, window_name, NULL, NULL);
|
||||||
}
|
}
|
||||||
void destroy_window_glfw (GLFWwindow* window) {
|
void destroy_window_glfw (GLFWwindow* window) {
|
||||||
glfwDestroyWindow (window);
|
glfwDestroyWindow (window);
|
||||||
@ -36,6 +46,44 @@ VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window) {
|
|||||||
}
|
}
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
void destroy_surface (VkInstance instance, VkSurfaceKHR surface) {
|
|
||||||
vkDestroySurfaceKHR (instance, surface, nullptr);
|
struct VulkanLibrary {
|
||||||
}
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
void* library;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
|
HMODULE library;
|
||||||
|
#endif
|
||||||
|
PFN_vkGetInstanceProcAddr ptr_vkGetInstanceProcAddr = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
VulkanLibrary () {
|
||||||
|
#if defined(__linux__)
|
||||||
|
library = dlopen ("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if (!library) library = dlopen ("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
library = dlopen ("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if (!library) library = dlopen ("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
library = LoadLibrary (TEXT ("vulkan-1.dll"));
|
||||||
|
#else
|
||||||
|
assert (false && "Unsupported platform");
|
||||||
|
#endif
|
||||||
|
if (!library) return;
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
ptr_vkGetInstanceProcAddr =
|
||||||
|
reinterpret_cast<PFN_vkGetInstanceProcAddr> (dlsym (library, "vkGetInstanceProcAddr"));
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
ptr_vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr> (
|
||||||
|
GetProcAddress (library, "vkGetInstanceProcAddr"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void close () {
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
dlclose (library);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
FreeLibrary (library);
|
||||||
|
#endif
|
||||||
|
library = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user