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:
Charles Giessen 2020-06-17 17:13:39 -06:00 committed by Charles Giessen
parent 511cac8db4
commit 812ce2cf0a
9 changed files with 417 additions and 94 deletions

0
.gitmodules vendored
View File

View File

@ -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)

View File

@ -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");
} }

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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
) )

View File

@ -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 ();
}
}

View File

@ -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;
}
};