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 ${Vulkan_INCLUDE_DIR})
|
||||
target_link_libraries(vk-bootstrap
|
||||
PUBLIC ${Vulkan_LIBRARY}
|
||||
PRIVATE
|
||||
vk-bootstrap-compiler-warnings)
|
||||
|
||||
|
@ -57,10 +57,15 @@ auto inst_builder_ret = instance_builder
|
||||
.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
|
||||
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")) {
|
||||
instance_builder.enable_layer("VK_LAYER_LUNARG_api_dump");
|
||||
}
|
||||
|
@ -3,7 +3,8 @@ target_link_libraries(vk-bootstrap-triangle
|
||||
PRIVATE
|
||||
glfw
|
||||
vk-bootstrap
|
||||
vk-bootstrap-compiler-warnings)
|
||||
vk-bootstrap-compiler-warnings
|
||||
${Vulkan_LIBRARY})
|
||||
|
||||
add_custom_command(
|
||||
TARGET vk-bootstrap-triangle
|
||||
|
@ -16,19 +16,186 @@
|
||||
|
||||
#include "VkBootstrap.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#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 detail {
|
||||
|
||||
template <typename T>
|
||||
void get_inst_proc_addr (
|
||||
T& out_ptr, const char* func_name, VkInstance instance, PFN_vkGetInstanceProcAddr ptr_vkGetInstanceProcAddr) {
|
||||
class VulkanFunctions {
|
||||
private:
|
||||
std::mutex init_mutex;
|
||||
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
|
||||
template <typename T, typename F, typename... Ts>
|
||||
auto get_vector (std::vector<T>& out, F&& f, Ts&&... ts) -> VkResult {
|
||||
@ -41,6 +208,7 @@ auto get_vector (std::vector<T>& out, F&& f, Ts&&... ts) -> VkResult {
|
||||
};
|
||||
out.resize (count);
|
||||
err = f (ts..., &count, out.data ());
|
||||
out.resize (count);
|
||||
} while (err == VK_INCOMPLETE);
|
||||
return err;
|
||||
}
|
||||
@ -52,6 +220,7 @@ auto get_vector_noerror (F&& f, Ts&&... ts) -> std::vector<T> {
|
||||
f (ts..., &count, nullptr);
|
||||
results.resize (count);
|
||||
f (ts..., &count, results.data ());
|
||||
results.resize (count);
|
||||
return results;
|
||||
}
|
||||
} // namespace detail
|
||||
@ -97,8 +266,7 @@ VkResult create_debug_utils_messenger (VkInstance instance,
|
||||
messengerCreateInfo.pfnUserCallback = debug_callback;
|
||||
|
||||
PFN_vkCreateDebugUtilsMessengerEXT createMessengerFunc;
|
||||
detail::get_inst_proc_addr (
|
||||
createMessengerFunc, "vkCreateDebugUtilsMessengerEXT", instance, vkGetInstanceProcAddr);
|
||||
detail::vk_functions.get_inst_proc_addr (createMessengerFunc, "vkCreateDebugUtilsMessengerEXT");
|
||||
|
||||
if (createMessengerFunc != nullptr) {
|
||||
return createMessengerFunc (instance, &messengerCreateInfo, allocation_callbacks, pDebugMessenger);
|
||||
@ -109,9 +277,10 @@ VkResult create_debug_utils_messenger (VkInstance instance,
|
||||
|
||||
void destroy_debug_utils_messenger (
|
||||
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, VkAllocationCallbacks* allocation_callbacks) {
|
||||
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT deleteMessengerFunc;
|
||||
detail::get_inst_proc_addr (
|
||||
deleteMessengerFunc, "vkDestroyDebugUtilsMessengerEXT", instance, vkGetInstanceProcAddr);
|
||||
detail::vk_functions.get_inst_proc_addr (deleteMessengerFunc, "vkDestroyDebugUtilsMessengerEXT");
|
||||
|
||||
if (deleteMessengerFunc != nullptr) {
|
||||
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 () {
|
||||
auto available_layers_ret =
|
||||
detail::get_vector<VkLayerProperties> (this->available_layers, vkEnumerateInstanceLayerProperties);
|
||||
auto available_layers_ret = detail::get_vector<VkLayerProperties> (
|
||||
this->available_layers, detail::vk_functions.fp_vkEnumerateInstanceLayerProperties);
|
||||
if (available_layers_ret != VK_SUCCESS) {
|
||||
this->available_layers.clear ();
|
||||
}
|
||||
@ -332,7 +514,7 @@ SystemInfo::SystemInfo () {
|
||||
validation_layers_available = true;
|
||||
|
||||
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) {
|
||||
this->available_extensions.clear ();
|
||||
}
|
||||
@ -344,7 +526,7 @@ SystemInfo::SystemInfo () {
|
||||
for (auto& layer : this->available_layers) {
|
||||
std::vector<VkExtensionProperties> layer_extensions;
|
||||
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) {
|
||||
for (auto& ext : layer_extensions)
|
||||
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.debug_messenger != nullptr)
|
||||
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 {
|
||||
|
||||
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);
|
||||
|
||||
if (info.required_api_version > VK_MAKE_VERSION (1, 0, 0) ||
|
||||
info.desired_api_version > VK_MAKE_VERSION (1, 0, 0)) {
|
||||
PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion;
|
||||
detail::get_inst_proc_addr (
|
||||
pfn_vkEnumerateInstanceVersion, "vkEnumerateInstanceVersion", nullptr, vkGetInstanceProcAddr);
|
||||
PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion =
|
||||
detail::vk_functions.fp_vkEnumerateInstanceVersion;
|
||||
|
||||
uint32_t queried_api_version = VK_MAKE_VERSION (1, 0, 0);
|
||||
if (pfn_vkEnumerateInstanceVersion != nullptr) {
|
||||
@ -455,7 +643,7 @@ detail::Result<Instance> InstanceBuilder::build () const {
|
||||
for (auto& layer : info.layers)
|
||||
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);
|
||||
}
|
||||
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 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)
|
||||
return detail::Result<Instance> (InstanceError::failed_create_instance, res);
|
||||
|
||||
detail::vk_functions.init_instance_funcs (instance.instance);
|
||||
|
||||
if (info.use_debug_messenger) {
|
||||
res = create_debug_utils_messenger (instance.instance,
|
||||
info.debug_callback,
|
||||
@ -530,6 +721,7 @@ detail::Result<Instance> InstanceBuilder::build () const {
|
||||
}
|
||||
instance.allocation_callbacks = info.allocation_callbacks;
|
||||
instance.instance_version = api_version;
|
||||
instance.fp_vkGetInstanceProcAddr = detail::vk_functions.ptr_vkGetInstanceProcAddr;
|
||||
return instance;
|
||||
}
|
||||
|
||||
@ -574,9 +766,7 @@ InstanceBuilder& InstanceBuilder::enable_validation_layers (bool enable_validati
|
||||
return *this;
|
||||
}
|
||||
InstanceBuilder& InstanceBuilder::request_validation_layers (bool enable_validation) {
|
||||
info.enable_validation_layers =
|
||||
enable_validation &&
|
||||
detail::check_layer_supported (system.available_layers, detail::validation_layer_name);
|
||||
info.request_validation_layers = enable_validation;
|
||||
return *this;
|
||||
}
|
||||
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) {
|
||||
std::vector<VkExtensionProperties> available_extensions;
|
||||
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 {};
|
||||
|
||||
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++) {
|
||||
VkBool32 presentSupport = false;
|
||||
if (surface != VK_NULL_HANDLE) {
|
||||
VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR (
|
||||
VkResult res = detail::vk_functions.fp_vkGetPhysicalDeviceSurfaceSupportKHR (
|
||||
phys_device, static_cast<uint32_t> (i), surface, &presentSupport);
|
||||
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{};
|
||||
desc.phys_device = phys_device;
|
||||
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties> (
|
||||
vkGetPhysicalDeviceQueueFamilyProperties, phys_device);
|
||||
detail::vk_functions.fp_vkGetPhysicalDeviceQueueFamilyProperties, phys_device);
|
||||
desc.queue_families = queue_families;
|
||||
|
||||
vkGetPhysicalDeviceProperties (phys_device, &desc.device_properties);
|
||||
vkGetPhysicalDeviceFeatures (phys_device, &desc.device_features);
|
||||
vkGetPhysicalDeviceMemoryProperties (phys_device, &desc.mem_properties);
|
||||
detail::vk_functions.fp_vkGetPhysicalDeviceProperties (phys_device, &desc.device_properties);
|
||||
detail::vk_functions.fp_vkGetPhysicalDeviceFeatures (phys_device, &desc.device_features);
|
||||
detail::vk_functions.fp_vkGetPhysicalDeviceMemoryProperties (phys_device, &desc.mem_properties);
|
||||
return desc;
|
||||
}
|
||||
|
||||
@ -840,10 +1030,14 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable (Phy
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> present_modes;
|
||||
|
||||
auto formats_ret = detail::get_vector<VkSurfaceFormatKHR> (
|
||||
formats, vkGetPhysicalDeviceSurfaceFormatsKHR, pd.phys_device, system_info.surface);
|
||||
auto present_modes_ret = detail::get_vector<VkPresentModeKHR> (
|
||||
present_modes, vkGetPhysicalDeviceSurfacePresentModesKHR, pd.phys_device, system_info.surface);
|
||||
auto formats_ret = detail::get_vector<VkSurfaceFormatKHR> (formats,
|
||||
detail::vk_functions.fp_vkGetPhysicalDeviceSurfaceFormatsKHR,
|
||||
pd.phys_device,
|
||||
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) {
|
||||
swapChainAdequate = !formats.empty () && !present_modes.empty ();
|
||||
@ -898,7 +1092,7 @@ detail::Result<PhysicalDevice> PhysicalDeviceSelector::select () const {
|
||||
std::vector<VkPhysicalDevice> physical_devices;
|
||||
|
||||
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) {
|
||||
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::failed_enumerate_physical_devices,
|
||||
physical_devices_ret };
|
||||
@ -1092,7 +1286,7 @@ detail::Result<uint32_t> Device::get_dedicated_queue_index (QueueType type) cons
|
||||
namespace detail {
|
||||
VkQueue get_queue (VkDevice device, uint32_t family) {
|
||||
VkQueue out_queue;
|
||||
vkGetDeviceQueue (device, family, 0, &out_queue);
|
||||
detail::vk_functions.fp_vkGetDeviceQueue (device, family, 0, &out_queue);
|
||||
return out_queue;
|
||||
}
|
||||
} // namespace detail
|
||||
@ -1115,7 +1309,7 @@ CustomQueueDescription::CustomQueueDescription (uint32_t index, uint32_t count,
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -1135,7 +1329,7 @@ detail::Result<Device> DeviceBuilder::build () const {
|
||||
|
||||
if (queue_descriptions.size () == 0) {
|
||||
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;
|
||||
VkResult res = vkCreateDevice (info.physical_device.physical_device,
|
||||
VkResult res = detail::vk_functions.fp_vkCreateDevice (info.physical_device.physical_device,
|
||||
&device_create_info,
|
||||
info.allocation_callbacks,
|
||||
&device.device);
|
||||
@ -1240,7 +1434,8 @@ Result<SurfaceSupportDetails> query_surface_support_details (VkPhysicalDevice ph
|
||||
return make_error_code (SurfaceSupportError::surface_handle_null);
|
||||
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities);
|
||||
VkResult res = detail::vk_functions.fp_vkGetPhysicalDeviceSurfaceCapabilitiesKHR (
|
||||
phys_device, surface, &capabilities);
|
||||
if (res != VK_SUCCESS) {
|
||||
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;
|
||||
|
||||
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)
|
||||
return { make_error_code (SurfaceSupportError::failed_enumerate_surface_formats), formats_ret };
|
||||
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)
|
||||
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) {
|
||||
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.oldSwapchain = info.old_swapchain;
|
||||
Swapchain swapchain{};
|
||||
VkResult res = vkCreateSwapchainKHR (
|
||||
VkResult res = detail::vk_functions.fp_vkCreateSwapchainKHR (
|
||||
info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain);
|
||||
if (res != VK_SUCCESS) {
|
||||
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 () {
|
||||
std::vector<VkImage> swapchain_images;
|
||||
|
||||
auto swapchain_images_ret =
|
||||
detail::get_vector<VkImage> (swapchain_images, vkGetSwapchainImagesKHR, device, swapchain);
|
||||
auto swapchain_images_ret = detail::get_vector<VkImage> (
|
||||
swapchain_images, detail::vk_functions.fp_vkGetSwapchainImagesKHR, device, swapchain);
|
||||
if (swapchain_images_ret != VK_SUCCESS) {
|
||||
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.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)
|
||||
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) {
|
||||
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) {
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
|
||||
namespace vkb {
|
||||
|
||||
namespace detail {
|
||||
@ -111,7 +112,6 @@ template <typename T> class Result {
|
||||
bool m_init;
|
||||
};
|
||||
|
||||
/* TODO implement operator == and operator != as friend or global */
|
||||
} // namespace detail
|
||||
|
||||
enum class InstanceError {
|
||||
@ -165,9 +165,18 @@ const char* to_string (QueueError err);
|
||||
const char* to_string (DeviceError 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 {
|
||||
private:
|
||||
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
|
||||
bool is_layer_available (const char* layer_name) const;
|
||||
// Returns true if an extension is available
|
||||
@ -179,6 +188,7 @@ struct SystemInfo {
|
||||
bool debug_utils_available = false;
|
||||
};
|
||||
|
||||
|
||||
class InstanceBuilder;
|
||||
class PhysicalDeviceSelector;
|
||||
|
||||
@ -187,6 +197,8 @@ struct Instance {
|
||||
VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
|
||||
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
|
||||
|
||||
PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr;
|
||||
|
||||
private:
|
||||
bool headless = false;
|
||||
uint32_t instance_version = VK_MAKE_VERSION (1, 0, 0);
|
||||
@ -199,8 +211,10 @@ void destroy_instance (Instance instance); // release instance resources
|
||||
|
||||
class InstanceBuilder {
|
||||
public:
|
||||
// contains useful information about the available vulkan capabilities, like layers and instance extensions.
|
||||
SystemInfo get_system_info () const;
|
||||
// Default constructor, will load vulkan.
|
||||
explicit InstanceBuilder ();
|
||||
// Optional: Can use your own PFN_vkGetInstanceProcAddr
|
||||
explicit InstanceBuilder (PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
|
||||
|
||||
// Create a VkInstance. Return an error if it failed.
|
||||
detail::Result<Instance> build () const;
|
||||
@ -291,25 +305,15 @@ class InstanceBuilder {
|
||||
// Custom allocator
|
||||
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
|
||||
|
||||
bool request_validation_layers = false;
|
||||
bool enable_validation_layers = false;
|
||||
bool use_debug_messenger = false;
|
||||
bool headless_context = false;
|
||||
|
||||
PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr;
|
||||
} 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,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
@ -359,7 +363,7 @@ enum class PreferredDeviceType {
|
||||
class PhysicalDeviceSelector {
|
||||
public:
|
||||
// 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;
|
||||
|
||||
@ -482,7 +486,7 @@ struct Device {
|
||||
|
||||
// For advanced device queue setup
|
||||
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 count = 0;
|
||||
std::vector<float> priorities;
|
||||
@ -493,7 +497,7 @@ void destroy_device (Device device);
|
||||
class DeviceBuilder {
|
||||
public:
|
||||
// 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;
|
||||
|
||||
@ -548,8 +552,8 @@ void destroy_swapchain (Swapchain const& swapchain);
|
||||
|
||||
class SwapchainBuilder {
|
||||
public:
|
||||
SwapchainBuilder (Device const& device);
|
||||
SwapchainBuilder (Device const& device, VkSurfaceKHR const surface);
|
||||
explicit SwapchainBuilder (Device const& device);
|
||||
explicit SwapchainBuilder (Device const& device, VkSurfaceKHR const surface);
|
||||
|
||||
detail::Result<Swapchain> build () const;
|
||||
|
||||
|
@ -3,16 +3,22 @@
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
// TODO
|
||||
// Getting queues
|
||||
// get dedicated vs distinct compute queues
|
||||
|
||||
// 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]") {
|
||||
GIVEN ("A window and a vulkan instance") {
|
||||
|
||||
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;
|
||||
auto instance_ret = instance_builder.use_default_debug_messenger ().build ();
|
||||
REQUIRE (instance_ret);
|
||||
@ -48,7 +54,7 @@ TEST_CASE ("Instance with surface", "[VkBootstrap.bootstrap]") {
|
||||
REQUIRE (phys_dev_ret.has_value ());
|
||||
}
|
||||
|
||||
destroy_surface (instance.instance, surface);
|
||||
destroy_surface (instance_ret, surface);
|
||||
vkb::destroy_instance (instance);
|
||||
destroy_window_glfw (window);
|
||||
}
|
||||
@ -176,7 +182,7 @@ TEST_CASE ("Device Configuration", "[VkBootstrap.bootstrap]") {
|
||||
vkb::destroy_device (device_ret.value ());
|
||||
}
|
||||
|
||||
destroy_surface (instance_ret.value ().instance, surface);
|
||||
destroy_surface (instance_ret, surface);
|
||||
vkb::destroy_instance (instance_ret.value ());
|
||||
}
|
||||
|
||||
@ -258,7 +264,7 @@ TEST_CASE ("Swapchain", "[VkBootstrap.bootstrap]") {
|
||||
}
|
||||
|
||||
vkb::destroy_device (device_ret.value ());
|
||||
destroy_surface (instance_ret.value ().instance, surface);
|
||||
destroy_surface (instance_ret, surface);
|
||||
vkb::destroy_instance (instance_ret.value ());
|
||||
}
|
||||
}
|
||||
@ -307,6 +313,70 @@ TEST_CASE ("Allocation Callbacks", "[VkBootstrap.bootstrap]") {
|
||||
vkb::destroy_swapchain (swapchain_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 ());
|
||||
}
|
||||
|
||||
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,6 +5,16 @@
|
||||
#include <memory>
|
||||
#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
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
@ -36,6 +46,44 @@ VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window) {
|
||||
}
|
||||
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