mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-29 01:44:35 +00:00
Moved all source code into 2 files
This will make it easier to include in other projects. Revamped how pNext chains work to no longer cause crashes.
This commit is contained in:
parent
ca312010fd
commit
37bc741658
@ -3,15 +3,7 @@ project(VulkanBootstrap)
|
|||||||
|
|
||||||
find_package(Vulkan REQUIRED)
|
find_package(Vulkan REQUIRED)
|
||||||
|
|
||||||
add_library(vk-bootstrap
|
add_library(vk-bootstrap src/VkBootstrap.h src/VkBootstrap.cpp)
|
||||||
src/VkBootstrap.h
|
|
||||||
src/Util.h
|
|
||||||
src/Instance.h
|
|
||||||
src/Device.h
|
|
||||||
src/Swapchain.h
|
|
||||||
src/Instance.cpp
|
|
||||||
src/Device.cpp
|
|
||||||
src/Swapchain.cpp)
|
|
||||||
|
|
||||||
target_include_directories(vk-bootstrap PUBLIC src)
|
target_include_directories(vk-bootstrap PUBLIC src)
|
||||||
|
|
||||||
@ -31,5 +23,6 @@ add_executable(vk-bootstrap-test tests/run_tests.cpp)
|
|||||||
|
|
||||||
target_link_libraries(vk-bootstrap-test vk-bootstrap)
|
target_link_libraries(vk-bootstrap-test vk-bootstrap)
|
||||||
target_link_libraries(vk-bootstrap-test glfw)
|
target_link_libraries(vk-bootstrap-test glfw)
|
||||||
|
target_link_libraries(vk-bootstrap-test Catch2)
|
||||||
|
|
||||||
endif(VK_BOOTSTRAP_TEST)
|
endif()
|
10
README.md
10
README.md
@ -13,29 +13,29 @@ This library simplifies the tedious process of:
|
|||||||
## Example
|
## Example
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
vkbs::InstanceBuilder builder;
|
vkb::InstanceBuilder builder;
|
||||||
builder.setup_validation_layers()
|
builder.setup_validation_layers()
|
||||||
.set_app_name ("example")
|
.set_app_name ("example")
|
||||||
.set_default_debug_messenger ();
|
.set_default_debug_messenger ();
|
||||||
auto inst_ret = builder.build ();
|
auto inst_ret = builder.build ();
|
||||||
vkbs::Instance inst;
|
vkb::Instance inst;
|
||||||
if (inst_ret.has_value()) {
|
if (inst_ret.has_value()) {
|
||||||
// successfully created instance
|
// successfully created instance
|
||||||
inst = inst_ret.value();
|
inst = inst_ret.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
vkbs::PhysicalDeviceSelector(inst);
|
vkb::PhysicalDeviceSelector(inst);
|
||||||
selector.set_surface (/* from user created window*/)
|
selector.set_surface (/* from user created window*/)
|
||||||
.set_minimum_version (1, 0)
|
.set_minimum_version (1, 0)
|
||||||
.require_dedicated_transfer_queue();
|
.require_dedicated_transfer_queue();
|
||||||
auto phys_ret = selector.select ();
|
auto phys_ret = selector.select ();
|
||||||
vkbs::PhysicalDevice phys;
|
vkb::PhysicalDevice phys;
|
||||||
if (phys_ret.has_value()) {
|
if (phys_ret.has_value()) {
|
||||||
// successfully selected a sufficient physical device
|
// successfully selected a sufficient physical device
|
||||||
phys = phys_ret.value();
|
phys = phys_ret.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
vkbs::DeviceBuilder device_builder(phys_dev);
|
vkb::DeviceBuilder device_builder(phys_dev);
|
||||||
auto dev_ret = device_builder.build ();
|
auto dev_ret = device_builder.build ();
|
||||||
if(dev_ret.has_value()){
|
if(dev_ret.has_value()){
|
||||||
// successfully created a vulkan device
|
// successfully created a vulkan device
|
||||||
|
180
src/Device.h
180
src/Device.h
@ -1,180 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Util.h"
|
|
||||||
|
|
||||||
#include "Instance.h"
|
|
||||||
|
|
||||||
namespace vkbs
|
|
||||||
{
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
struct SurfaceSupportDetails
|
|
||||||
{
|
|
||||||
VkSurfaceCapabilitiesKHR capabilities;
|
|
||||||
std::vector<VkSurfaceFormatKHR> formats;
|
|
||||||
std::vector<VkPresentModeKHR> present_modes;
|
|
||||||
};
|
|
||||||
|
|
||||||
Expected<SurfaceSupportDetails, VkResult> query_surface_support_details (
|
|
||||||
VkPhysicalDevice phys_device, VkSurfaceKHR surface);
|
|
||||||
|
|
||||||
struct QueueFamilies
|
|
||||||
{
|
|
||||||
int graphics = -1;
|
|
||||||
int present = -1;
|
|
||||||
int transfer = -1;
|
|
||||||
int compute = -1;
|
|
||||||
int sparse = -1;
|
|
||||||
uint32_t count_graphics = 0;
|
|
||||||
uint32_t count_transfer = 0;
|
|
||||||
uint32_t count_compute = 0;
|
|
||||||
uint32_t count_sparse = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
VkFormat find_supported_format (VkPhysicalDevice physical_device,
|
|
||||||
const std::vector<VkFormat>& candidates,
|
|
||||||
VkImageTiling tiling,
|
|
||||||
VkFormatFeatureFlags features);
|
|
||||||
|
|
||||||
bool check_device_extension_support (VkPhysicalDevice device, std::vector<std::string> extensions);
|
|
||||||
|
|
||||||
detail::QueueFamilies find_queue_families (VkPhysicalDevice physDevice, VkSurfaceKHR windowSurface);
|
|
||||||
|
|
||||||
bool supports_features (VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested);
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
// ---- Physical Device ---- //
|
|
||||||
|
|
||||||
struct PhysicalDevice
|
|
||||||
{
|
|
||||||
VkPhysicalDevice phys_device = VK_NULL_HANDLE;
|
|
||||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
VkPhysicalDeviceProperties physical_device_properties{};
|
|
||||||
VkPhysicalDeviceFeatures physical_device_features{};
|
|
||||||
VkPhysicalDeviceMemoryProperties memory_properties{};
|
|
||||||
|
|
||||||
detail::QueueFamilies queue_family_properties;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
void populate_physical_device_details (PhysicalDevice physical_device);
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
struct PhysicalDeviceSelector
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PhysicalDeviceSelector (Instance instance);
|
|
||||||
|
|
||||||
detail::Expected<PhysicalDevice, VkResult> select ();
|
|
||||||
|
|
||||||
PhysicalDeviceSelector& set_surface (VkSurfaceKHR instance);
|
|
||||||
|
|
||||||
PhysicalDeviceSelector& prefer_discrete (bool prefer_discrete = true);
|
|
||||||
PhysicalDeviceSelector& prefer_integrated (bool prefer_integrated = true);
|
|
||||||
PhysicalDeviceSelector& allow_fallback (bool fallback = true);
|
|
||||||
|
|
||||||
PhysicalDeviceSelector& require_present (bool require = true);
|
|
||||||
PhysicalDeviceSelector& require_dedicated_transfer_queue ();
|
|
||||||
PhysicalDeviceSelector& require_dedicated_compute_queue ();
|
|
||||||
|
|
||||||
PhysicalDeviceSelector& required_device_memory_size (VkDeviceSize size);
|
|
||||||
PhysicalDeviceSelector& desired_device_memory_size (VkDeviceSize size);
|
|
||||||
|
|
||||||
PhysicalDeviceSelector& add_required_extension (std::string extension);
|
|
||||||
PhysicalDeviceSelector& add_desired_extension (std::string extension);
|
|
||||||
|
|
||||||
PhysicalDeviceSelector& set_desired_version (uint32_t major, uint32_t minor);
|
|
||||||
PhysicalDeviceSelector& set_minimum_version (uint32_t major = 1, uint32_t minor = 0);
|
|
||||||
|
|
||||||
PhysicalDeviceSelector& set_required_features (VkPhysicalDeviceFeatures features);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct PhysicalDeviceInfo
|
|
||||||
{
|
|
||||||
VkInstance instance = VK_NULL_HANDLE;
|
|
||||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
|
||||||
bool headless = false;
|
|
||||||
} info;
|
|
||||||
|
|
||||||
struct SelectionCriteria
|
|
||||||
{
|
|
||||||
bool prefer_discrete = true;
|
|
||||||
bool prefer_integrated = false;
|
|
||||||
bool allow_fallback = true;
|
|
||||||
bool require_present = true;
|
|
||||||
bool require_dedicated_transfer_queue = false;
|
|
||||||
bool require_dedicated_compute_queue = false;
|
|
||||||
VkDeviceSize required_mem_size = 0;
|
|
||||||
VkDeviceSize desired_mem_size = 0;
|
|
||||||
|
|
||||||
std::vector<std::string> required_extensions;
|
|
||||||
std::vector<std::string> desired_extensions;
|
|
||||||
|
|
||||||
uint32_t required_version = VK_MAKE_VERSION (1, 0, 0);
|
|
||||||
uint32_t desired_version = VK_MAKE_VERSION (1, 0, 0);
|
|
||||||
|
|
||||||
VkPhysicalDeviceFeatures required_features{};
|
|
||||||
|
|
||||||
} criteria;
|
|
||||||
|
|
||||||
enum class Suitable
|
|
||||||
{
|
|
||||||
yes,
|
|
||||||
partial,
|
|
||||||
no
|
|
||||||
};
|
|
||||||
|
|
||||||
Suitable is_device_suitable (VkPhysicalDevice phys_device);
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---- Device ---- //
|
|
||||||
|
|
||||||
struct Device
|
|
||||||
{
|
|
||||||
VkDevice device = VK_NULL_HANDLE;
|
|
||||||
VkAllocationCallbacks* allocator = VK_NULL_HANDLE;
|
|
||||||
PhysicalDevice physical_device;
|
|
||||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
|
||||||
};
|
|
||||||
|
|
||||||
void destroy_device (Device device);
|
|
||||||
|
|
||||||
class DeviceBuilder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DeviceBuilder (PhysicalDevice device);
|
|
||||||
detail::Expected<Device, VkResult> build ();
|
|
||||||
|
|
||||||
template <typename T> DeviceBuilder& add_pNext (T* structure);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct DeviceInfo
|
|
||||||
{
|
|
||||||
VkDeviceCreateFlags flags;
|
|
||||||
VkBaseOutStructure* pNext_chain = nullptr;
|
|
||||||
VkAllocationCallbacks* allocator = VK_NULL_HANDLE;
|
|
||||||
PhysicalDevice physical_device;
|
|
||||||
std::vector<std::string> extensions;
|
|
||||||
} info;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---- Queue ---- //
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
VkQueue get_queue (Device const& device, uint32_t family, uint32_t index = 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_present (Device const& device);
|
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_graphics (Device const& device, uint32_t index = 0);
|
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_compute (Device const& device, uint32_t index = 0);
|
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_transfer (Device const& device, uint32_t index = 0);
|
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_sparse (Device const& device, uint32_t index = 0);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace vkbs
|
|
349
src/Instance.cpp
349
src/Instance.cpp
@ -1,349 +0,0 @@
|
|||||||
#include "Instance.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace vkbs
|
|
||||||
{
|
|
||||||
|
|
||||||
const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s)
|
|
||||||
{
|
|
||||||
switch (s)
|
|
||||||
{
|
|
||||||
case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
|
|
||||||
return "VERBOSE";
|
|
||||||
case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
|
||||||
return "ERROR";
|
|
||||||
case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
|
|
||||||
return "WARNING";
|
|
||||||
case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
|
|
||||||
return "INFO";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s)
|
|
||||||
{
|
|
||||||
switch (s)
|
|
||||||
{
|
|
||||||
case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
|
|
||||||
return "General";
|
|
||||||
case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:
|
|
||||||
return "Validation";
|
|
||||||
case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
|
|
||||||
return "Performance";
|
|
||||||
default:
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
VkResult create_debug_utils_messenger (VkInstance instance,
|
|
||||||
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback,
|
|
||||||
VkDebugUtilsMessageSeverityFlagsEXT severity,
|
|
||||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
|
||||||
const VkAllocationCallbacks* pAllocator,
|
|
||||||
VkDebugUtilsMessengerEXT* pDebugMessenger)
|
|
||||||
{
|
|
||||||
if (debug_callback == nullptr) debug_callback = default_debug_callback;
|
|
||||||
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
|
|
||||||
messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
||||||
messengerCreateInfo.messageSeverity = severity;
|
|
||||||
messengerCreateInfo.messageType = type;
|
|
||||||
messengerCreateInfo.pfnUserCallback = debug_callback;
|
|
||||||
|
|
||||||
|
|
||||||
auto vkCreateDebugUtilsMessengerEXT_func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr (
|
|
||||||
instance, "vkCreateDebugUtilsMessengerEXT");
|
|
||||||
if (vkCreateDebugUtilsMessengerEXT_func != nullptr)
|
|
||||||
{
|
|
||||||
return vkCreateDebugUtilsMessengerEXT_func (instance, &messengerCreateInfo, pAllocator, pDebugMessenger);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_debug_utils_messenger (
|
|
||||||
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator)
|
|
||||||
{
|
|
||||||
auto vkDestroyDebugUtilsMessengerEXT_func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr (
|
|
||||||
instance, "vkDestroyDebugUtilsMessengerEXT");
|
|
||||||
if (vkDestroyDebugUtilsMessengerEXT_func != nullptr)
|
|
||||||
{
|
|
||||||
vkDestroyDebugUtilsMessengerEXT_func (instance, debugMessenger, pAllocator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkBool32 default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
||||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
|
||||||
void* pUserData)
|
|
||||||
{
|
|
||||||
auto ms = DebugMessageSeverity (messageSeverity);
|
|
||||||
auto mt = DebugMessageType (messageType);
|
|
||||||
printf ("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage);
|
|
||||||
return VK_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool check_layers_supported (std::vector<const char*> layer_names)
|
|
||||||
{
|
|
||||||
auto available_layers = detail::get_vector<VkLayerProperties> (vkEnumerateInstanceLayerProperties);
|
|
||||||
if (!available_layers.has_value ()) return false; // maybe report error?
|
|
||||||
bool all_found = true;
|
|
||||||
for (const auto& layer_name : layer_names)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (const auto& layer_properties : available_layers.value ())
|
|
||||||
{
|
|
||||||
if (strcmp (layer_name, layer_properties.layerName) == 0)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) all_found = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return all_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
void destroy_instance (Instance instance)
|
|
||||||
{
|
|
||||||
if (instance.debug_messenger != nullptr)
|
|
||||||
detail::destroy_debug_utils_messenger (instance.instance, instance.debug_messenger, instance.allocator);
|
|
||||||
if (instance.instance != VK_NULL_HANDLE)
|
|
||||||
vkDestroyInstance (instance.instance, instance.allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
detail::Expected<Instance, VkResult> InstanceBuilder::build ()
|
|
||||||
{
|
|
||||||
|
|
||||||
VkApplicationInfo app_info = {};
|
|
||||||
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
||||||
app_info.pNext = nullptr;
|
|
||||||
app_info.pApplicationName = info.app_name.c_str ();
|
|
||||||
app_info.applicationVersion = info.application_version;
|
|
||||||
app_info.pEngineName = info.engine_name.c_str ();
|
|
||||||
app_info.engineVersion = info.engine_version;
|
|
||||||
app_info.apiVersion = info.api_version;
|
|
||||||
|
|
||||||
std::vector<const char*> extensions;
|
|
||||||
for (auto& ext : info.extensions)
|
|
||||||
extensions.push_back (ext.c_str ());
|
|
||||||
if (info.debug_callback != nullptr)
|
|
||||||
{
|
|
||||||
extensions.push_back (VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info.headless_context)
|
|
||||||
{
|
|
||||||
extensions.push_back (VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
#if defined(_WIN32)
|
|
||||||
extentions.push_back (VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
|
||||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
||||||
extentions.push_back (VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
|
||||||
#elif defined(_DIRECT2DISPLAY)
|
|
||||||
extentions.push_back (VK_KHR_DISPLAY_EXTENSION_NAME);
|
|
||||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
||||||
extentions.push_back (VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
|
||||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
|
||||||
extentions.push_back (VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
|
||||||
#elif defined(VK_USE_PLATFORM_X11_HKR)
|
|
||||||
extentions.push_back (VK_KHR_X11_SURFACE_EXTENSION_NAME);
|
|
||||||
#elif defined(VK_USE_PLATFORM_IOS_MVK)
|
|
||||||
extentions.push_back (VK_MVK_IOS_SURFACE_EXTENSION_NAME);
|
|
||||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
|
||||||
extentions.push_back (VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<const char*> layers;
|
|
||||||
for (auto& layer : info.layers)
|
|
||||||
layers.push_back (layer.c_str ());
|
|
||||||
|
|
||||||
if (info.enable_validation_layers)
|
|
||||||
{
|
|
||||||
layers.push_back ("VK_LAYER_KHRONOS_validation");
|
|
||||||
}
|
|
||||||
bool all_layers_supported = detail::check_layers_supported (layers);
|
|
||||||
if (!all_layers_supported)
|
|
||||||
{
|
|
||||||
return detail::Error<VkResult>{ VK_ERROR_LAYER_NOT_PRESENT, "Not all layers supported!" };
|
|
||||||
}
|
|
||||||
|
|
||||||
VkBaseOutStructure pNext_chain;
|
|
||||||
pNext_chain.pNext = (VkBaseOutStructure*)info.pNext;
|
|
||||||
if (info.use_debug_messenger)
|
|
||||||
{
|
|
||||||
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
|
|
||||||
messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
||||||
messengerCreateInfo.messageSeverity = info.debug_message_severity;
|
|
||||||
messengerCreateInfo.messageType = info.debug_message_type;
|
|
||||||
messengerCreateInfo.pfnUserCallback = info.debug_callback;
|
|
||||||
detail::pNext_append (&pNext_chain, &messengerCreateInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.enabled_validation_features.size () != 0 || info.disabled_validation_features.size ())
|
|
||||||
{
|
|
||||||
VkValidationFeaturesEXT features{};
|
|
||||||
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
|
|
||||||
features.pNext = nullptr;
|
|
||||||
features.enabledValidationFeatureCount = info.enabled_validation_features.size ();
|
|
||||||
features.pEnabledValidationFeatures = info.enabled_validation_features.data ();
|
|
||||||
features.disabledValidationFeatureCount = info.disabled_validation_features.size ();
|
|
||||||
features.pDisabledValidationFeatures = info.disabled_validation_features.data ();
|
|
||||||
detail::pNext_append (&pNext_chain, &features);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.disabled_validation_checks.size () != 0)
|
|
||||||
{
|
|
||||||
VkValidationFlagsEXT checks{};
|
|
||||||
checks.sType = VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT;
|
|
||||||
checks.pNext = nullptr;
|
|
||||||
checks.disabledValidationCheckCount = info.disabled_validation_checks.size ();
|
|
||||||
checks.pDisabledValidationChecks = info.disabled_validation_checks.data ();
|
|
||||||
detail::pNext_append (&pNext_chain, &checks);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkInstanceCreateInfo instance_create_info = {};
|
|
||||||
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
||||||
instance_create_info.pNext = pNext_chain.pNext;
|
|
||||||
instance_create_info.flags = info.flags;
|
|
||||||
instance_create_info.pApplicationInfo = &app_info;
|
|
||||||
instance_create_info.enabledExtensionCount = static_cast<uint32_t> (extensions.size ());
|
|
||||||
instance_create_info.ppEnabledExtensionNames = extensions.data ();
|
|
||||||
instance_create_info.enabledLayerCount = static_cast<uint32_t> (layers.size ());
|
|
||||||
instance_create_info.ppEnabledLayerNames = layers.data ();
|
|
||||||
|
|
||||||
Instance instance;
|
|
||||||
VkResult res = vkCreateInstance (&instance_create_info, info.allocator, &instance.instance);
|
|
||||||
if (res != VK_SUCCESS) return detail::Error<VkResult>{ res, "Failed to create instance" };
|
|
||||||
|
|
||||||
res = detail::create_debug_utils_messenger (instance.instance,
|
|
||||||
info.debug_callback,
|
|
||||||
info.debug_message_severity,
|
|
||||||
info.debug_message_type,
|
|
||||||
info.allocator,
|
|
||||||
&instance.debug_messenger);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
return detail::Error<VkResult>{ res, "Failed to create setup debug callback" };
|
|
||||||
|
|
||||||
if (info.headless_context)
|
|
||||||
{
|
|
||||||
instance.headless = true;
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceBuilder& InstanceBuilder::set_app_name (std::string app_name)
|
|
||||||
{
|
|
||||||
info.app_name = app_name;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::set_engine_name (std::string engine_name)
|
|
||||||
{
|
|
||||||
info.engine_name = engine_name;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceBuilder& InstanceBuilder::set_app_version (uint32_t major, uint32_t minor, uint32_t patch)
|
|
||||||
{
|
|
||||||
info.application_version = VK_MAKE_VERSION (major, minor, patch);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::set_engine_version (uint32_t major, uint32_t minor, uint32_t patch)
|
|
||||||
{
|
|
||||||
info.engine_version = VK_MAKE_VERSION (major, minor, patch);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::set_api_version (uint32_t major, uint32_t minor, uint32_t patch)
|
|
||||||
{
|
|
||||||
info.api_version = VK_MAKE_VERSION (major, minor, patch);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceBuilder& InstanceBuilder::add_layer (std::string layer_name)
|
|
||||||
{
|
|
||||||
info.layers.push_back (layer_name);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::add_extension (std::string extension_name)
|
|
||||||
{
|
|
||||||
info.extensions.push_back (extension_name);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceBuilder& InstanceBuilder::setup_validation_layers (bool enable_validation)
|
|
||||||
{
|
|
||||||
info.enable_validation_layers = enable_validation;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::set_default_debug_messenger ()
|
|
||||||
{
|
|
||||||
info.use_debug_messenger = true;
|
|
||||||
info.debug_callback = detail::default_debug_callback;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceBuilder& InstanceBuilder::set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback)
|
|
||||||
{
|
|
||||||
info.use_debug_messenger = true;
|
|
||||||
info.debug_callback = callback;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::set_headless (bool headless)
|
|
||||||
{
|
|
||||||
info.headless_context = headless;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceBuilder& InstanceBuilder::set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity)
|
|
||||||
{
|
|
||||||
info.debug_message_severity = severity;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity)
|
|
||||||
{
|
|
||||||
info.debug_message_severity = info.debug_message_severity | severity;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type)
|
|
||||||
{
|
|
||||||
info.debug_message_type = type;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type)
|
|
||||||
{
|
|
||||||
info.debug_message_type = info.debug_message_type | type;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceBuilder& InstanceBuilder::add_validation_disable (VkValidationCheckEXT check)
|
|
||||||
{
|
|
||||||
info.disabled_validation_checks.push_back (check);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::add_validation_feature_enable (VkValidationFeatureEnableEXT enable)
|
|
||||||
{
|
|
||||||
info.enabled_validation_features.push_back (enable);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
InstanceBuilder& InstanceBuilder::add_validation_feature_disable (VkValidationFeatureDisableEXT disable)
|
|
||||||
{
|
|
||||||
info.disabled_validation_features.push_back (disable);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceBuilder& InstanceBuilder::set_allocator_callback (VkAllocationCallbacks* allocator)
|
|
||||||
{
|
|
||||||
info.allocator = allocator;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace vkbs
|
|
113
src/Instance.h
113
src/Instance.h
@ -1,113 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Util.h"
|
|
||||||
|
|
||||||
namespace vkbs
|
|
||||||
{
|
|
||||||
|
|
||||||
const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s);
|
|
||||||
const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s);
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
VkResult create_debug_utils_messenger (VkInstance instance,
|
|
||||||
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback,
|
|
||||||
VkDebugUtilsMessageSeverityFlagsEXT severity,
|
|
||||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
|
||||||
const VkAllocationCallbacks* pAllocator,
|
|
||||||
VkDebugUtilsMessengerEXT* pDebugMessenger);
|
|
||||||
|
|
||||||
void destroy_debug_utils_messenger (
|
|
||||||
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator);
|
|
||||||
|
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
||||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
|
||||||
void* pUserData);
|
|
||||||
|
|
||||||
bool check_layers_supported (std::vector<const char*> layer_names);
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
struct Instance
|
|
||||||
{
|
|
||||||
VkInstance instance = VK_NULL_HANDLE;
|
|
||||||
VkAllocationCallbacks* allocator = VK_NULL_HANDLE;
|
|
||||||
VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
|
|
||||||
bool headless = false;
|
|
||||||
bool validation_enabled = false;
|
|
||||||
bool debug_callback_enabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
void destroy_instance (Instance instance); // release instance resources
|
|
||||||
|
|
||||||
class InstanceBuilder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
detail::Expected<Instance, VkResult> build (); // use builder pattern
|
|
||||||
|
|
||||||
InstanceBuilder& set_app_name (std::string app_name);
|
|
||||||
InstanceBuilder& set_engine_name (std::string engine_name);
|
|
||||||
|
|
||||||
InstanceBuilder& set_app_version (uint32_t major, uint32_t minor, uint32_t patch);
|
|
||||||
InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch);
|
|
||||||
InstanceBuilder& set_api_version (uint32_t major, uint32_t minor, uint32_t patch);
|
|
||||||
|
|
||||||
InstanceBuilder& add_layer (std::string app_name);
|
|
||||||
InstanceBuilder& add_extension (std::string app_name);
|
|
||||||
|
|
||||||
InstanceBuilder& setup_validation_layers (bool enable_validation = true);
|
|
||||||
InstanceBuilder& set_headless (bool headless = false);
|
|
||||||
|
|
||||||
InstanceBuilder& set_default_debug_messenger ();
|
|
||||||
InstanceBuilder& set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback);
|
|
||||||
InstanceBuilder& set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity);
|
|
||||||
InstanceBuilder& add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity);
|
|
||||||
InstanceBuilder& set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type);
|
|
||||||
InstanceBuilder& add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type);
|
|
||||||
|
|
||||||
InstanceBuilder& add_validation_disable (VkValidationCheckEXT check);
|
|
||||||
InstanceBuilder& add_validation_feature_enable (VkValidationFeatureEnableEXT enable);
|
|
||||||
InstanceBuilder& add_validation_feature_disable (VkValidationFeatureDisableEXT disable);
|
|
||||||
|
|
||||||
InstanceBuilder& set_allocator_callback (VkAllocationCallbacks* allocator);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct InstanceInfo
|
|
||||||
{
|
|
||||||
// VkApplicationInfo
|
|
||||||
std::string app_name;
|
|
||||||
std::string engine_name;
|
|
||||||
uint32_t application_version = 0;
|
|
||||||
uint32_t engine_version = 0;
|
|
||||||
uint32_t api_version = VK_MAKE_VERSION (1, 0, 0);
|
|
||||||
|
|
||||||
// VkInstanceCreateInfo
|
|
||||||
std::vector<std::string> layers;
|
|
||||||
std::vector<std::string> extensions;
|
|
||||||
VkInstanceCreateFlags flags = 0;
|
|
||||||
void* pNext = nullptr;
|
|
||||||
VkAllocationCallbacks* allocator = nullptr;
|
|
||||||
|
|
||||||
// debug callback
|
|
||||||
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback = nullptr;
|
|
||||||
VkDebugUtilsMessageSeverityFlagsEXT debug_message_severity =
|
|
||||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
|
||||||
VkDebugUtilsMessageTypeFlagsEXT debug_message_type =
|
|
||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
|
||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
|
||||||
|
|
||||||
// validation features
|
|
||||||
std::vector<VkValidationCheckEXT> disabled_validation_checks;
|
|
||||||
std::vector<VkValidationFeatureEnableEXT> enabled_validation_features;
|
|
||||||
std::vector<VkValidationFeatureDisableEXT> disabled_validation_features;
|
|
||||||
|
|
||||||
// booleans
|
|
||||||
bool ignore_non_critical_issues = true;
|
|
||||||
bool enable_validation_layers = false;
|
|
||||||
bool use_debug_messenger = false;
|
|
||||||
bool headless_context = false;
|
|
||||||
} info;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace vkbs
|
|
@ -1,162 +0,0 @@
|
|||||||
#include "Swapchain.h"
|
|
||||||
|
|
||||||
namespace vkbs
|
|
||||||
{
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector<VkSurfaceFormatKHR> const& availableFormats)
|
|
||||||
{
|
|
||||||
for (const auto& availableFormat : availableFormats)
|
|
||||||
{
|
|
||||||
if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
|
||||||
{
|
|
||||||
return availableFormat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return availableFormats[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPresentModeKHR choose_swap_present_mode (std::vector<VkPresentModeKHR> const& availablePresentModes)
|
|
||||||
{
|
|
||||||
for (const auto& availablePresentMode : availablePresentModes)
|
|
||||||
{
|
|
||||||
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
|
||||||
{
|
|
||||||
return availablePresentMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkExtent2D choose_swap_extent (
|
|
||||||
VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height)
|
|
||||||
{
|
|
||||||
if (capabilities.currentExtent.width != UINT32_MAX)
|
|
||||||
{
|
|
||||||
return capabilities.currentExtent;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const int WIDTH = 800;
|
|
||||||
const int HEIGHT = 600;
|
|
||||||
VkExtent2D actualExtent = { WIDTH, HEIGHT };
|
|
||||||
|
|
||||||
actualExtent.width = std::max (capabilities.minImageExtent.width,
|
|
||||||
std::min (capabilities.maxImageExtent.width, actualExtent.width));
|
|
||||||
actualExtent.height = std::max (capabilities.minImageExtent.height,
|
|
||||||
std::min (capabilities.maxImageExtent.height, actualExtent.height));
|
|
||||||
|
|
||||||
return actualExtent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
SwapchainBuilder::SwapchainBuilder (Device const& device)
|
|
||||||
{
|
|
||||||
info.device = device.device;
|
|
||||||
info.physical_device = device.physical_device;
|
|
||||||
info.surface = device.surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
detail::Expected<Swapchain, VkResult> SwapchainBuilder::build ()
|
|
||||||
{
|
|
||||||
auto surface_support =
|
|
||||||
detail::query_surface_support_details (info.physical_device.phys_device, info.surface);
|
|
||||||
if (!surface_support.has_value ())
|
|
||||||
return detail::Error<VkResult>{ surface_support.error ().error_code, "can't get surface support" };
|
|
||||||
VkSurfaceFormatKHR surfaceFormat =
|
|
||||||
detail::choose_swapchain_surface_format (surface_support.value ().formats);
|
|
||||||
VkPresentModeKHR presentMode = detail::choose_swap_present_mode (surface_support.value ().present_modes);
|
|
||||||
VkExtent2D extent = detail::choose_swap_extent (surface_support.value ().capabilities);
|
|
||||||
|
|
||||||
uint32_t imageCount = surface_support.value ().capabilities.minImageCount + 1;
|
|
||||||
if (surface_support.value ().capabilities.maxImageCount > 0 &&
|
|
||||||
imageCount > surface_support.value ().capabilities.maxImageCount)
|
|
||||||
{
|
|
||||||
imageCount = surface_support.value ().capabilities.maxImageCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSwapchainCreateInfoKHR swapchain_create_info = {};
|
|
||||||
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
||||||
swapchain_create_info.surface = info.surface;
|
|
||||||
|
|
||||||
swapchain_create_info.minImageCount = imageCount;
|
|
||||||
swapchain_create_info.imageFormat = surfaceFormat.format;
|
|
||||||
swapchain_create_info.imageColorSpace = surfaceFormat.colorSpace;
|
|
||||||
swapchain_create_info.imageExtent = extent;
|
|
||||||
swapchain_create_info.imageArrayLayers = 1;
|
|
||||||
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
||||||
|
|
||||||
detail::QueueFamilies indices =
|
|
||||||
detail::find_queue_families (info.physical_device.phys_device, info.surface);
|
|
||||||
uint32_t queueFamilyIndices[] = { static_cast<uint32_t> (indices.graphics),
|
|
||||||
static_cast<uint32_t> (indices.present) };
|
|
||||||
|
|
||||||
if (indices.graphics != indices.present)
|
|
||||||
{
|
|
||||||
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
||||||
swapchain_create_info.queueFamilyIndexCount = 2;
|
|
||||||
swapchain_create_info.pQueueFamilyIndices = queueFamilyIndices;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
swapchain_create_info.preTransform = surface_support.value ().capabilities.currentTransform;
|
|
||||||
swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
||||||
swapchain_create_info.presentMode = presentMode;
|
|
||||||
swapchain_create_info.clipped = VK_TRUE;
|
|
||||||
swapchain_create_info.oldSwapchain = info.old_swapchain;
|
|
||||||
Swapchain swapchain;
|
|
||||||
VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
return detail::Error<VkResult>{ res, "Failed to create swapchain" };
|
|
||||||
}
|
|
||||||
auto swapchain_images =
|
|
||||||
detail::get_vector<VkImage> (vkGetSwapchainImagesKHR, info.device, swapchain.swapchain);
|
|
||||||
|
|
||||||
swapchain.image_format = surfaceFormat.format;
|
|
||||||
swapchain.extent = extent;
|
|
||||||
|
|
||||||
return swapchain;
|
|
||||||
}
|
|
||||||
detail::Expected<Swapchain, VkResult> SwapchainBuilder::recreate (Swapchain const& swapchain)
|
|
||||||
{
|
|
||||||
info.old_swapchain = swapchain.swapchain;
|
|
||||||
return build ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwapchainBuilder::destroy (Swapchain const& swapchain)
|
|
||||||
{
|
|
||||||
vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SwapchainBuilder& SwapchainBuilder::set_desired_format (VkFormat format)
|
|
||||||
{
|
|
||||||
info.desired_format = format;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
SwapchainBuilder& SwapchainBuilder::set_fallback_format (VkFormat format)
|
|
||||||
{
|
|
||||||
info.fallback_format = format;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
SwapchainBuilder& SwapchainBuilder::set_desired_present_mode (VkPresentModeKHR present_mode)
|
|
||||||
{
|
|
||||||
info.desired_present_mode = present_mode;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
SwapchainBuilder& SwapchainBuilder::set_fallback_present_mode (VkPresentModeKHR present_mode)
|
|
||||||
{
|
|
||||||
info.fallback_present_mode = present_mode;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace vkbs
|
|
@ -1,58 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Util.h"
|
|
||||||
#include "Instance.h"
|
|
||||||
#include "Device.h"
|
|
||||||
|
|
||||||
namespace vkbs
|
|
||||||
{
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector<VkSurfaceFormatKHR> const& availableFormats);
|
|
||||||
VkPresentModeKHR choose_swap_present_mode (std::vector<VkPresentModeKHR> const& availablePresentModes);
|
|
||||||
VkExtent2D choose_swap_extent (VkSurfaceCapabilitiesKHR const& capabilities);
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
struct Swapchain
|
|
||||||
{
|
|
||||||
VkDevice device = VK_NULL_HANDLE;
|
|
||||||
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
|
||||||
VkAllocationCallbacks* allocator = VK_NULL_HANDLE;
|
|
||||||
std::vector<VkImage> images;
|
|
||||||
VkFormat image_format = VK_FORMAT_UNDEFINED;
|
|
||||||
VkExtent2D extent = { 0, 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
class SwapchainBuilder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SwapchainBuilder (Device const& device);
|
|
||||||
|
|
||||||
detail::Expected<Swapchain, VkResult> build ();
|
|
||||||
detail::Expected<Swapchain, VkResult> recreate (Swapchain const& swapchain);
|
|
||||||
void destroy (Swapchain const& swapchain);
|
|
||||||
|
|
||||||
SwapchainBuilder& set_desired_format (VkFormat format);
|
|
||||||
SwapchainBuilder& set_fallback_format (VkFormat format);
|
|
||||||
|
|
||||||
SwapchainBuilder& set_desired_present_mode (VkPresentModeKHR present_mode);
|
|
||||||
SwapchainBuilder& set_fallback_present_mode (VkPresentModeKHR present_mode);
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct SwapchainInfo
|
|
||||||
{
|
|
||||||
VkDevice device = VK_NULL_HANDLE;
|
|
||||||
PhysicalDevice physical_device;
|
|
||||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
|
||||||
VkSwapchainKHR old_swapchain = VK_NULL_HANDLE;
|
|
||||||
VkFormat desired_format = VK_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
VkFormat fallback_format = VK_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
VkPresentModeKHR fallback_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
std::vector<VkPresentModeKHR> acceptable_present_modes;
|
|
||||||
uint32_t desired_width = 256;
|
|
||||||
uint32_t desired_height = 256;
|
|
||||||
} info;
|
|
||||||
};
|
|
||||||
} // namespace vkbs
|
|
170
src/Util.h
170
src/Util.h
@ -1,170 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
|
||||||
|
|
||||||
namespace vkbs
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template <typename T> struct Error
|
|
||||||
{
|
|
||||||
T error_code;
|
|
||||||
const char* msg;
|
|
||||||
};
|
|
||||||
template <typename E, typename U> class Expected
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Expected (const E& expect) : m_expect{ expect }, m_init{ true } {}
|
|
||||||
Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {}
|
|
||||||
Expected (const Error<U>& error) : m_error{ error }, m_init{ false } {}
|
|
||||||
Expected (Error<U>&& error) : m_error{ std::move (error) }, m_init{ false } {}
|
|
||||||
~Expected () { destroy (); }
|
|
||||||
Expected (Expected const& expected) : m_init (expected.m_init)
|
|
||||||
{
|
|
||||||
if (m_init)
|
|
||||||
new (&m_expect) E{ expected.m_expect };
|
|
||||||
else
|
|
||||||
new (&m_error) Error<U>{ expected.m_error };
|
|
||||||
}
|
|
||||||
Expected (Expected&& expected) : m_init (expected.m_init)
|
|
||||||
{
|
|
||||||
if (m_init)
|
|
||||||
new (&m_expect) E{ std::move (expected.m_expect) };
|
|
||||||
else
|
|
||||||
new (&m_error) Error<U>{ std::move (expected.m_error) };
|
|
||||||
expected.destroy ();
|
|
||||||
}
|
|
||||||
|
|
||||||
Expected& operator= (const E& expect)
|
|
||||||
{
|
|
||||||
destroy ();
|
|
||||||
m_init = true;
|
|
||||||
new (&m_expect) E{ expect };
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Expected& operator= (E&& expect)
|
|
||||||
{
|
|
||||||
destroy ();
|
|
||||||
m_init = true;
|
|
||||||
new (&m_expect) E{ std::move (expect) };
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Expected& operator= (const Error<U>& error)
|
|
||||||
{
|
|
||||||
destroy ();
|
|
||||||
m_init = false;
|
|
||||||
new (&m_error) Error<U>{ error };
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Expected& operator= (Error<U>&& error)
|
|
||||||
{
|
|
||||||
destroy ();
|
|
||||||
m_init = false;
|
|
||||||
new (&m_error) Error<U>{ std::move (error) };
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
// clang-format off
|
|
||||||
const E* operator-> () const { assert (m_init); return &m_expect; }
|
|
||||||
E* operator-> () { assert (m_init); return &m_expect; }
|
|
||||||
const E& operator* () const& { assert (m_init); return m_expect; }
|
|
||||||
E& operator* () & { assert (m_init); return m_expect; }
|
|
||||||
E&& operator* () && { assert (m_init); return std::move (m_expect); }
|
|
||||||
const E& value () const& { assert (m_init); return m_expect; }
|
|
||||||
E& value () & { assert (m_init); return m_expect; }
|
|
||||||
const E&& value () const&& { assert (m_init); return std::move (m_expect); }
|
|
||||||
E&& value () && { assert (m_init); return std::move (m_expect); }
|
|
||||||
const Error<U>& error () const& { assert (!m_init); return m_error; }
|
|
||||||
Error<U>& error () & { assert (!m_init); return m_error; }
|
|
||||||
const Error<U>&& error () const&& { assert (!m_init); return std::move (m_error); }
|
|
||||||
Error<U>&& error () && { assert (!m_init); return move (m_error); }
|
|
||||||
// clang-format on
|
|
||||||
bool has_value () const { return m_init; }
|
|
||||||
explicit operator bool () const { return m_init; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void destroy ()
|
|
||||||
{
|
|
||||||
if (m_init)
|
|
||||||
m_expect.~E ();
|
|
||||||
else
|
|
||||||
m_error.~Error<U> ();
|
|
||||||
}
|
|
||||||
union
|
|
||||||
{
|
|
||||||
E m_expect;
|
|
||||||
Error<U> m_error;
|
|
||||||
};
|
|
||||||
bool m_init;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* TODO implement operator == and operator != as friend or global */
|
|
||||||
|
|
||||||
|
|
||||||
// Helper for robustly executing the two-call pattern
|
|
||||||
template <typename T, typename F, typename... Ts>
|
|
||||||
auto get_vector_init (F&& f, T init, Ts&&... ts) -> Expected<std::vector<T>, VkResult>
|
|
||||||
{
|
|
||||||
uint32_t count = 0;
|
|
||||||
std::vector<T> results;
|
|
||||||
VkResult err;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
err = f (ts..., &count, nullptr);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
return Error<VkResult>{ err, "" };
|
|
||||||
};
|
|
||||||
results.resize (count, init);
|
|
||||||
err = f (ts..., &count, results.data ());
|
|
||||||
} while (err == VK_INCOMPLETE);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
return Error<VkResult>{ err, "" };
|
|
||||||
};
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename F, typename... Ts>
|
|
||||||
auto get_vector (F&& f, Ts&&... ts) -> Expected<std::vector<T>, VkResult>
|
|
||||||
{
|
|
||||||
return get_vector_init (f, T (), ts...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename F, typename... Ts>
|
|
||||||
auto get_vector_noerror (F&& f, T init, Ts&&... ts) -> std::vector<T>
|
|
||||||
{
|
|
||||||
uint32_t count = 0;
|
|
||||||
std::vector<T> results;
|
|
||||||
f (ts..., &count, nullptr);
|
|
||||||
results.resize (count, init);
|
|
||||||
f (ts..., &count, results.data ());
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
template <typename T, typename F, typename... Ts>
|
|
||||||
auto get_vector_noerror (F&& f, Ts&&... ts) -> std::vector<T>
|
|
||||||
{
|
|
||||||
return get_vector_noerror (f, T (), ts...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> void pNext_append (VkBaseOutStructure* chain, T* structure)
|
|
||||||
{
|
|
||||||
if (chain == nullptr) return;
|
|
||||||
|
|
||||||
while (chain->pNext != nullptr)
|
|
||||||
{
|
|
||||||
chain = chain->pNext;
|
|
||||||
}
|
|
||||||
chain->pNext = (VkBaseOutStructure*)structure;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
} // namespace vkbs
|
|
@ -1,10 +1,369 @@
|
|||||||
#include "Device.h"
|
#include "VkBootstrap.h"
|
||||||
|
|
||||||
#include <set>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
namespace vkbs
|
namespace vkb
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s)
|
||||||
|
{
|
||||||
|
switch (s)
|
||||||
|
{
|
||||||
|
case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
|
||||||
|
return "VERBOSE";
|
||||||
|
case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
||||||
|
return "ERROR";
|
||||||
|
case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
|
||||||
|
return "WARNING";
|
||||||
|
case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
|
||||||
|
return "INFO";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s)
|
||||||
|
{
|
||||||
|
switch (s)
|
||||||
|
{
|
||||||
|
case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
|
||||||
|
return "General";
|
||||||
|
case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:
|
||||||
|
return "Validation";
|
||||||
|
case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
|
||||||
|
return "Performance";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
VkResult create_debug_utils_messenger (VkInstance instance,
|
||||||
|
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback,
|
||||||
|
VkDebugUtilsMessageSeverityFlagsEXT severity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkDebugUtilsMessengerEXT* pDebugMessenger)
|
||||||
|
{
|
||||||
|
if (debug_callback == nullptr) debug_callback = default_debug_callback;
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
|
||||||
|
messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||||
|
messengerCreateInfo.pNext = nullptr;
|
||||||
|
messengerCreateInfo.messageSeverity = severity;
|
||||||
|
messengerCreateInfo.messageType = type;
|
||||||
|
messengerCreateInfo.pfnUserCallback = debug_callback;
|
||||||
|
|
||||||
|
|
||||||
|
auto vkCreateDebugUtilsMessengerEXT_func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr (
|
||||||
|
instance, "vkCreateDebugUtilsMessengerEXT");
|
||||||
|
if (vkCreateDebugUtilsMessengerEXT_func != nullptr)
|
||||||
|
{
|
||||||
|
return vkCreateDebugUtilsMessengerEXT_func (instance, &messengerCreateInfo, pAllocator, pDebugMessenger);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_debug_utils_messenger (
|
||||||
|
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator)
|
||||||
|
{
|
||||||
|
auto vkDestroyDebugUtilsMessengerEXT_func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr (
|
||||||
|
instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||||
|
if (vkDestroyDebugUtilsMessengerEXT_func != nullptr)
|
||||||
|
{
|
||||||
|
vkDestroyDebugUtilsMessengerEXT_func (instance, debugMessenger, pAllocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBool32 default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
|
void* pUserData)
|
||||||
|
{
|
||||||
|
auto ms = DebugMessageSeverity (messageSeverity);
|
||||||
|
auto mt = DebugMessageType (messageType);
|
||||||
|
printf ("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage);
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_layers_supported (std::vector<const char*> layer_names)
|
||||||
|
{
|
||||||
|
auto available_layers = detail::get_vector<VkLayerProperties> (vkEnumerateInstanceLayerProperties);
|
||||||
|
if (!available_layers.has_value ())
|
||||||
|
{
|
||||||
|
return false; // maybe report error?
|
||||||
|
}
|
||||||
|
bool all_found = true;
|
||||||
|
for (const auto& layer_name : layer_names)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (const auto& layer_properties : available_layers.value ())
|
||||||
|
{
|
||||||
|
if (strcmp (layer_name, layer_properties.layerName) == 0)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) all_found = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_found;
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void setup_pNext_chain (T& structure, std::vector<VkBaseOutStructure*>& structs)
|
||||||
|
{
|
||||||
|
structure.pNext = nullptr;
|
||||||
|
if (structs.size () <= 0) return;
|
||||||
|
for (int i = 0; i < structs.size () - 1; i++)
|
||||||
|
{
|
||||||
|
VkBaseOutStructure* cur = reinterpret_cast<VkBaseOutStructure*> (&structs[i]);
|
||||||
|
cur = reinterpret_cast<VkBaseOutStructure*> (&structs[i + 1]);
|
||||||
|
}
|
||||||
|
structure.pNext = &structs.at (0);
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
void destroy_instance (Instance instance)
|
||||||
|
{
|
||||||
|
if (instance.debug_messenger != nullptr)
|
||||||
|
detail::destroy_debug_utils_messenger (instance.instance, instance.debug_messenger, instance.allocator);
|
||||||
|
if (instance.instance != VK_NULL_HANDLE)
|
||||||
|
vkDestroyInstance (instance.instance, instance.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::Expected<Instance, VkResult> InstanceBuilder::build ()
|
||||||
|
{
|
||||||
|
|
||||||
|
VkApplicationInfo app_info = {};
|
||||||
|
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
|
app_info.pNext = nullptr;
|
||||||
|
app_info.pApplicationName = info.app_name.c_str ();
|
||||||
|
app_info.applicationVersion = info.application_version;
|
||||||
|
app_info.pEngineName = info.engine_name.c_str ();
|
||||||
|
app_info.engineVersion = info.engine_version;
|
||||||
|
app_info.apiVersion = info.api_version;
|
||||||
|
|
||||||
|
std::vector<const char*> extensions;
|
||||||
|
for (auto& ext : info.extensions)
|
||||||
|
extensions.push_back (ext.c_str ());
|
||||||
|
if (info.debug_callback != nullptr)
|
||||||
|
{
|
||||||
|
extensions.push_back ("VK_EXT_debug_utils");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.headless_context)
|
||||||
|
{
|
||||||
|
extensions.push_back (VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#if defined(_WIN32)
|
||||||
|
extensions.push_back (VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||||
|
extensions.push_back (VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
||||||
|
#elif defined(_DIRECT2DISPLAY)
|
||||||
|
extensions.push_back (VK_KHR_DISPLAY_EXTENSION_NAME);
|
||||||
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||||
|
extensions.push_back (VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||||
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||||
|
extensions.push_back (VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
||||||
|
#elif defined(VK_USE_PLATFORM_X11_HKR)
|
||||||
|
extensions.push_back (VK_KHR_X11_SURFACE_EXTENSION_NAME);
|
||||||
|
#elif defined(VK_USE_PLATFORM_IOS_MVK)
|
||||||
|
extensions.push_back (VK_MVK_IOS_SURFACE_EXTENSION_NAME);
|
||||||
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||||
|
extensions.push_back (VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
std::vector<const char*> layers;
|
||||||
|
for (auto& layer : info.layers)
|
||||||
|
layers.push_back (layer.c_str ());
|
||||||
|
|
||||||
|
if (info.enable_validation_layers)
|
||||||
|
{
|
||||||
|
layers.push_back ("VK_LAYER_KHRONOS_validation");
|
||||||
|
}
|
||||||
|
bool all_layers_supported = detail::check_layers_supported (layers);
|
||||||
|
if (!all_layers_supported)
|
||||||
|
{
|
||||||
|
return detail::Error<VkResult>{ VK_ERROR_LAYER_NOT_PRESENT, "Not all layers supported!" };
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
|
||||||
|
if (info.use_debug_messenger)
|
||||||
|
{
|
||||||
|
messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||||
|
messengerCreateInfo.pNext = nullptr;
|
||||||
|
messengerCreateInfo.messageSeverity = info.debug_message_severity;
|
||||||
|
messengerCreateInfo.messageType = info.debug_message_type;
|
||||||
|
messengerCreateInfo.pfnUserCallback = info.debug_callback;
|
||||||
|
info.pNext_elements.push_back (reinterpret_cast<VkBaseOutStructure*> (&messengerCreateInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkValidationFeaturesEXT features{};
|
||||||
|
if (info.enabled_validation_features.size () != 0 || info.disabled_validation_features.size ())
|
||||||
|
{
|
||||||
|
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
|
||||||
|
features.pNext = nullptr;
|
||||||
|
features.enabledValidationFeatureCount = info.enabled_validation_features.size ();
|
||||||
|
features.pEnabledValidationFeatures = info.enabled_validation_features.data ();
|
||||||
|
features.disabledValidationFeatureCount = info.disabled_validation_features.size ();
|
||||||
|
features.pDisabledValidationFeatures = info.disabled_validation_features.data ();
|
||||||
|
info.pNext_elements.push_back (reinterpret_cast<VkBaseOutStructure*> (&features));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkValidationFlagsEXT checks{};
|
||||||
|
if (info.disabled_validation_checks.size () != 0)
|
||||||
|
{
|
||||||
|
checks.sType = VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT;
|
||||||
|
checks.pNext = nullptr;
|
||||||
|
checks.disabledValidationCheckCount = info.disabled_validation_checks.size ();
|
||||||
|
checks.pDisabledValidationChecks = info.disabled_validation_checks.data ();
|
||||||
|
info.pNext_elements.push_back (reinterpret_cast<VkBaseOutStructure*> (&checks));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkInstanceCreateInfo instance_create_info = {};
|
||||||
|
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
|
detail::setup_pNext_chain (instance_create_info, info.pNext_elements);
|
||||||
|
instance_create_info.flags = info.flags;
|
||||||
|
instance_create_info.pApplicationInfo = &app_info;
|
||||||
|
instance_create_info.enabledExtensionCount = static_cast<uint32_t> (extensions.size ());
|
||||||
|
instance_create_info.ppEnabledExtensionNames = extensions.data ();
|
||||||
|
instance_create_info.enabledLayerCount = static_cast<uint32_t> (layers.size ());
|
||||||
|
instance_create_info.ppEnabledLayerNames = layers.data ();
|
||||||
|
|
||||||
|
Instance instance;
|
||||||
|
VkResult res = vkCreateInstance (&instance_create_info, nullptr, &instance.instance);
|
||||||
|
if (res != VK_SUCCESS) return detail::Error<VkResult>{ res, "Failed to create instance" };
|
||||||
|
|
||||||
|
if (info.use_debug_messenger)
|
||||||
|
{
|
||||||
|
res = detail::create_debug_utils_messenger (instance.instance,
|
||||||
|
info.debug_callback,
|
||||||
|
info.debug_message_severity,
|
||||||
|
info.debug_message_type,
|
||||||
|
info.allocator,
|
||||||
|
&instance.debug_messenger);
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
return detail::Error<VkResult>{ res, "Failed to create setup debug callback" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.headless_context)
|
||||||
|
{
|
||||||
|
instance.headless = true;
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceBuilder& InstanceBuilder::set_app_name (std::string app_name)
|
||||||
|
{
|
||||||
|
info.app_name = app_name;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::set_engine_name (std::string engine_name)
|
||||||
|
{
|
||||||
|
info.engine_name = engine_name;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceBuilder& InstanceBuilder::set_app_version (uint32_t major, uint32_t minor, uint32_t patch)
|
||||||
|
{
|
||||||
|
info.application_version = VK_MAKE_VERSION (major, minor, patch);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::set_engine_version (uint32_t major, uint32_t minor, uint32_t patch)
|
||||||
|
{
|
||||||
|
info.engine_version = VK_MAKE_VERSION (major, minor, patch);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::set_api_version (uint32_t major, uint32_t minor, uint32_t patch)
|
||||||
|
{
|
||||||
|
info.api_version = VK_MAKE_VERSION (major, minor, patch);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceBuilder& InstanceBuilder::add_layer (std::string layer_name)
|
||||||
|
{
|
||||||
|
info.layers.push_back (layer_name);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::add_extension (std::string extension_name)
|
||||||
|
{
|
||||||
|
info.extensions.push_back (extension_name);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceBuilder& InstanceBuilder::setup_validation_layers (bool enable_validation)
|
||||||
|
{
|
||||||
|
info.enable_validation_layers = enable_validation;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::set_default_debug_messenger ()
|
||||||
|
{
|
||||||
|
info.use_debug_messenger = true;
|
||||||
|
info.debug_callback = detail::default_debug_callback;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceBuilder& InstanceBuilder::set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback)
|
||||||
|
{
|
||||||
|
info.use_debug_messenger = true;
|
||||||
|
info.debug_callback = callback;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::set_headless (bool headless)
|
||||||
|
{
|
||||||
|
info.headless_context = headless;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceBuilder& InstanceBuilder::set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity)
|
||||||
|
{
|
||||||
|
info.debug_message_severity = severity;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity)
|
||||||
|
{
|
||||||
|
info.debug_message_severity = info.debug_message_severity | severity;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type)
|
||||||
|
{
|
||||||
|
info.debug_message_type = type;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type)
|
||||||
|
{
|
||||||
|
info.debug_message_type = info.debug_message_type | type;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceBuilder& InstanceBuilder::add_validation_disable (VkValidationCheckEXT check)
|
||||||
|
{
|
||||||
|
info.disabled_validation_checks.push_back (check);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::add_validation_feature_enable (VkValidationFeatureEnableEXT enable)
|
||||||
|
{
|
||||||
|
info.enabled_validation_features.push_back (enable);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
InstanceBuilder& InstanceBuilder::add_validation_feature_disable (VkValidationFeatureDisableEXT disable)
|
||||||
|
{
|
||||||
|
info.disabled_validation_features.push_back (disable);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceBuilder& InstanceBuilder::set_allocator_callback (VkAllocationCallbacks* allocator)
|
||||||
|
{
|
||||||
|
info.allocator = allocator;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
Expected<SurfaceSupportDetails, VkResult> query_surface_support_details (
|
Expected<SurfaceSupportDetails, VkResult> query_surface_support_details (
|
||||||
@ -428,12 +787,12 @@ detail::Expected<Device, VkResult> DeviceBuilder::build ()
|
|||||||
std::vector<const char*> extensions;
|
std::vector<const char*> extensions;
|
||||||
for (auto& ext : info.extensions)
|
for (auto& ext : info.extensions)
|
||||||
extensions.push_back (ext.c_str ());
|
extensions.push_back (ext.c_str ());
|
||||||
if (info.physical_device.surface != VK_NULL_HANDLE)
|
// if (info.physical_device.surface != VK_NULL_HANDLE)
|
||||||
extensions.push_back ({ VK_KHR_SWAPCHAIN_EXTENSION_NAME });
|
// extensions.push_back ({ VK_KHR_SWAPCHAIN_EXTENSION_NAME });
|
||||||
|
|
||||||
VkDeviceCreateInfo device_create_info = {};
|
VkDeviceCreateInfo device_create_info = {};
|
||||||
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
device_create_info.pNext = info.pNext_chain;
|
detail::setup_pNext_chain (device_create_info, info.pNext_chain);
|
||||||
device_create_info.flags = info.flags;
|
device_create_info.flags = info.flags;
|
||||||
device_create_info.queueCreateInfoCount = static_cast<uint32_t> (queueCreateInfos.size ());
|
device_create_info.queueCreateInfoCount = static_cast<uint32_t> (queueCreateInfos.size ());
|
||||||
device_create_info.pQueueCreateInfos = queueCreateInfos.data ();
|
device_create_info.pQueueCreateInfos = queueCreateInfos.data ();
|
||||||
@ -453,10 +812,7 @@ detail::Expected<Device, VkResult> DeviceBuilder::build ()
|
|||||||
|
|
||||||
template <typename T> DeviceBuilder& DeviceBuilder::add_pNext (T* structure)
|
template <typename T> DeviceBuilder& DeviceBuilder::add_pNext (T* structure)
|
||||||
{
|
{
|
||||||
if (info.pNext_chain == nullptr)
|
info.pNext_chain.push_back (reinterpret_cast<VkBaseOutStructure*> (structure));
|
||||||
info.pNext_chain = (VkBaseOutStructure*)structure;
|
|
||||||
else
|
|
||||||
detail::pNext_append (info.pNext_chain, structure);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,5 +861,162 @@ detail::Expected<VkQueue, VkResult> get_queue_sparse (Device const& device, uint
|
|||||||
return detail::get_queue (device, device.physical_device.queue_family_properties.sparse, index);
|
return detail::get_queue (device, device.physical_device.queue_family_properties.sparse, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector<VkSurfaceFormatKHR> const& availableFormats)
|
||||||
|
{
|
||||||
|
for (const auto& availableFormat : availableFormats)
|
||||||
|
{
|
||||||
|
if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||||
|
{
|
||||||
|
return availableFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace vkbs
|
return availableFormats[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPresentModeKHR choose_swap_present_mode (std::vector<VkPresentModeKHR> const& availablePresentModes)
|
||||||
|
{
|
||||||
|
for (const auto& availablePresentMode : availablePresentModes)
|
||||||
|
{
|
||||||
|
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||||
|
{
|
||||||
|
return availablePresentMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkExtent2D choose_swap_extent (
|
||||||
|
VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height)
|
||||||
|
{
|
||||||
|
if (capabilities.currentExtent.width != UINT32_MAX)
|
||||||
|
{
|
||||||
|
return capabilities.currentExtent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int WIDTH = 800;
|
||||||
|
const int HEIGHT = 600;
|
||||||
|
VkExtent2D actualExtent = { WIDTH, HEIGHT };
|
||||||
|
|
||||||
|
actualExtent.width = std::max (capabilities.minImageExtent.width,
|
||||||
|
std::min (capabilities.maxImageExtent.width, actualExtent.width));
|
||||||
|
actualExtent.height = std::max (capabilities.minImageExtent.height,
|
||||||
|
std::min (capabilities.maxImageExtent.height, actualExtent.height));
|
||||||
|
|
||||||
|
return actualExtent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
SwapchainBuilder::SwapchainBuilder (Device const& device)
|
||||||
|
{
|
||||||
|
info.device = device.device;
|
||||||
|
info.physical_device = device.physical_device;
|
||||||
|
info.surface = device.surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::Expected<Swapchain, VkResult> SwapchainBuilder::build ()
|
||||||
|
{
|
||||||
|
auto surface_support =
|
||||||
|
detail::query_surface_support_details (info.physical_device.phys_device, info.surface);
|
||||||
|
if (!surface_support.has_value ())
|
||||||
|
return detail::Error<VkResult>{ surface_support.error ().error_code, "can't get surface support" };
|
||||||
|
VkSurfaceFormatKHR surfaceFormat =
|
||||||
|
detail::choose_swapchain_surface_format (surface_support.value ().formats);
|
||||||
|
VkPresentModeKHR presentMode = detail::choose_swap_present_mode (surface_support.value ().present_modes);
|
||||||
|
VkExtent2D extent = detail::choose_swap_extent (
|
||||||
|
surface_support.value ().capabilities, info.desired_width, info.desired_height);
|
||||||
|
|
||||||
|
uint32_t imageCount = surface_support.value ().capabilities.minImageCount + 1;
|
||||||
|
if (surface_support.value ().capabilities.maxImageCount > 0 &&
|
||||||
|
imageCount > surface_support.value ().capabilities.maxImageCount)
|
||||||
|
{
|
||||||
|
imageCount = surface_support.value ().capabilities.maxImageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR swapchain_create_info = {};
|
||||||
|
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
swapchain_create_info.surface = info.surface;
|
||||||
|
|
||||||
|
swapchain_create_info.minImageCount = imageCount;
|
||||||
|
swapchain_create_info.imageFormat = surfaceFormat.format;
|
||||||
|
swapchain_create_info.imageColorSpace = surfaceFormat.colorSpace;
|
||||||
|
swapchain_create_info.imageExtent = extent;
|
||||||
|
swapchain_create_info.imageArrayLayers = 1;
|
||||||
|
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
|
||||||
|
detail::QueueFamilies indices =
|
||||||
|
detail::find_queue_families (info.physical_device.phys_device, info.surface);
|
||||||
|
uint32_t queueFamilyIndices[] = { static_cast<uint32_t> (indices.graphics),
|
||||||
|
static_cast<uint32_t> (indices.present) };
|
||||||
|
|
||||||
|
if (indices.graphics != indices.present)
|
||||||
|
{
|
||||||
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
swapchain_create_info.queueFamilyIndexCount = 2;
|
||||||
|
swapchain_create_info.pQueueFamilyIndices = queueFamilyIndices;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
swapchain_create_info.preTransform = surface_support.value ().capabilities.currentTransform;
|
||||||
|
swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
swapchain_create_info.presentMode = presentMode;
|
||||||
|
swapchain_create_info.clipped = VK_TRUE;
|
||||||
|
swapchain_create_info.oldSwapchain = info.old_swapchain;
|
||||||
|
Swapchain swapchain;
|
||||||
|
VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain);
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
return detail::Error<VkResult>{ res, "Failed to create swapchain" };
|
||||||
|
}
|
||||||
|
auto swapchain_images =
|
||||||
|
detail::get_vector<VkImage> (vkGetSwapchainImagesKHR, info.device, swapchain.swapchain);
|
||||||
|
|
||||||
|
swapchain.image_format = surfaceFormat.format;
|
||||||
|
swapchain.extent = extent;
|
||||||
|
|
||||||
|
return swapchain;
|
||||||
|
}
|
||||||
|
detail::Expected<Swapchain, VkResult> SwapchainBuilder::recreate (Swapchain const& swapchain)
|
||||||
|
{
|
||||||
|
info.old_swapchain = swapchain.swapchain;
|
||||||
|
return build ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainBuilder::destroy (Swapchain const& swapchain)
|
||||||
|
{
|
||||||
|
vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SwapchainBuilder& SwapchainBuilder::set_desired_format (VkFormat format)
|
||||||
|
{
|
||||||
|
info.desired_format = format;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SwapchainBuilder& SwapchainBuilder::set_fallback_format (VkFormat format)
|
||||||
|
{
|
||||||
|
info.fallback_format = format;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SwapchainBuilder& SwapchainBuilder::set_desired_present_mode (VkPresentModeKHR present_mode)
|
||||||
|
{
|
||||||
|
info.desired_present_mode = present_mode;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SwapchainBuilder& SwapchainBuilder::set_fallback_present_mode (VkPresentModeKHR present_mode)
|
||||||
|
{
|
||||||
|
info.fallback_present_mode = present_mode;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace vkb
|
@ -1,5 +1,482 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Instance.h"
|
#include <cassert>
|
||||||
#include "Device.h"
|
|
||||||
#include "Swapchain.h"
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
namespace vkb
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename T> struct Error
|
||||||
|
{
|
||||||
|
T error_code;
|
||||||
|
const char* msg;
|
||||||
|
};
|
||||||
|
template <typename E, typename U> class Expected
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Expected (const E& expect) : m_expect{ expect }, m_init{ true } {}
|
||||||
|
Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {}
|
||||||
|
Expected (const Error<U>& error) : m_error{ error }, m_init{ false } {}
|
||||||
|
Expected (Error<U>&& error) : m_error{ std::move (error) }, m_init{ false } {}
|
||||||
|
~Expected () { destroy (); }
|
||||||
|
Expected (Expected const& expected) : m_init (expected.m_init)
|
||||||
|
{
|
||||||
|
if (m_init)
|
||||||
|
new (&m_expect) E{ expected.m_expect };
|
||||||
|
else
|
||||||
|
new (&m_error) Error<U>{ expected.m_error };
|
||||||
|
}
|
||||||
|
Expected (Expected&& expected) : m_init (expected.m_init)
|
||||||
|
{
|
||||||
|
if (m_init)
|
||||||
|
new (&m_expect) E{ std::move (expected.m_expect) };
|
||||||
|
else
|
||||||
|
new (&m_error) Error<U>{ std::move (expected.m_error) };
|
||||||
|
expected.destroy ();
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected& operator= (const E& expect)
|
||||||
|
{
|
||||||
|
destroy ();
|
||||||
|
m_init = true;
|
||||||
|
new (&m_expect) E{ expect };
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Expected& operator= (E&& expect)
|
||||||
|
{
|
||||||
|
destroy ();
|
||||||
|
m_init = true;
|
||||||
|
new (&m_expect) E{ std::move (expect) };
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Expected& operator= (const Error<U>& error)
|
||||||
|
{
|
||||||
|
destroy ();
|
||||||
|
m_init = false;
|
||||||
|
new (&m_error) Error<U>{ error };
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Expected& operator= (Error<U>&& error)
|
||||||
|
{
|
||||||
|
destroy ();
|
||||||
|
m_init = false;
|
||||||
|
new (&m_error) Error<U>{ std::move (error) };
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
// clang-format off
|
||||||
|
const E* operator-> () const { assert (m_init); return &m_expect; }
|
||||||
|
E* operator-> () { assert (m_init); return &m_expect; }
|
||||||
|
const E& operator* () const& { assert (m_init); return m_expect; }
|
||||||
|
E& operator* () & { assert (m_init); return m_expect; }
|
||||||
|
E&& operator* () && { assert (m_init); return std::move (m_expect); }
|
||||||
|
const E& value () const& { assert (m_init); return m_expect; }
|
||||||
|
E& value () & { assert (m_init); return m_expect; }
|
||||||
|
const E&& value () const&& { assert (m_init); return std::move (m_expect); }
|
||||||
|
E&& value () && { assert (m_init); return std::move (m_expect); }
|
||||||
|
const Error<U>& error () const& { assert (!m_init); return m_error; }
|
||||||
|
Error<U>& error () & { assert (!m_init); return m_error; }
|
||||||
|
const Error<U>&& error () const&& { assert (!m_init); return std::move (m_error); }
|
||||||
|
Error<U>&& error () && { assert (!m_init); return move (m_error); }
|
||||||
|
// clang-format on
|
||||||
|
bool has_value () const { return m_init; }
|
||||||
|
explicit operator bool () const { return m_init; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void destroy ()
|
||||||
|
{
|
||||||
|
if (m_init)
|
||||||
|
m_expect.~E ();
|
||||||
|
else
|
||||||
|
m_error.~Error<U> ();
|
||||||
|
}
|
||||||
|
union
|
||||||
|
{
|
||||||
|
E m_expect;
|
||||||
|
Error<U> m_error;
|
||||||
|
};
|
||||||
|
bool m_init;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TODO implement operator == and operator != as friend or global */
|
||||||
|
|
||||||
|
|
||||||
|
// Helper for robustly executing the two-call pattern
|
||||||
|
template <typename T, typename F, typename... Ts>
|
||||||
|
auto get_vector_init (F&& f, T init, Ts&&... ts) -> Expected<std::vector<T>, VkResult>
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
std::vector<T> results;
|
||||||
|
VkResult err;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
err = f (ts..., &count, nullptr);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
return Error<VkResult>{ err, "" };
|
||||||
|
};
|
||||||
|
results.resize (count, init);
|
||||||
|
err = f (ts..., &count, results.data ());
|
||||||
|
} while (err == VK_INCOMPLETE);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
return Error<VkResult>{ err, "" };
|
||||||
|
};
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename F, typename... Ts>
|
||||||
|
auto get_vector (F&& f, Ts&&... ts) -> Expected<std::vector<T>, VkResult>
|
||||||
|
{
|
||||||
|
return get_vector_init (f, T (), ts...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename F, typename... Ts>
|
||||||
|
auto get_vector_noerror (F&& f, T init, Ts&&... ts) -> std::vector<T>
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
std::vector<T> results;
|
||||||
|
f (ts..., &count, nullptr);
|
||||||
|
results.resize (count, init);
|
||||||
|
f (ts..., &count, results.data ());
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
template <typename T, typename F, typename... Ts>
|
||||||
|
auto get_vector_noerror (F&& f, Ts&&... ts) -> std::vector<T>
|
||||||
|
{
|
||||||
|
return get_vector_noerror (f, T (), ts...);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult create_debug_utils_messenger (VkInstance instance,
|
||||||
|
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback,
|
||||||
|
VkDebugUtilsMessageSeverityFlagsEXT severity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkDebugUtilsMessengerEXT* pDebugMessenger);
|
||||||
|
|
||||||
|
void destroy_debug_utils_messenger (
|
||||||
|
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
|
static VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
|
void* pUserData);
|
||||||
|
|
||||||
|
bool check_layers_supported (std::vector<const char*> layer_names);
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s);
|
||||||
|
const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s);
|
||||||
|
|
||||||
|
|
||||||
|
struct Instance
|
||||||
|
{
|
||||||
|
VkInstance instance = VK_NULL_HANDLE;
|
||||||
|
VkAllocationCallbacks* allocator = VK_NULL_HANDLE;
|
||||||
|
VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
|
||||||
|
bool headless = false;
|
||||||
|
bool validation_enabled = false;
|
||||||
|
bool debug_callback_enabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
void destroy_instance (Instance instance); // release instance resources
|
||||||
|
|
||||||
|
class InstanceBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
detail::Expected<Instance, VkResult> build (); // use builder pattern
|
||||||
|
|
||||||
|
InstanceBuilder& set_app_name (std::string app_name);
|
||||||
|
InstanceBuilder& set_engine_name (std::string engine_name);
|
||||||
|
|
||||||
|
InstanceBuilder& set_app_version (uint32_t major, uint32_t minor, uint32_t patch);
|
||||||
|
InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch);
|
||||||
|
InstanceBuilder& set_api_version (uint32_t major, uint32_t minor, uint32_t patch);
|
||||||
|
|
||||||
|
InstanceBuilder& add_layer (std::string app_name);
|
||||||
|
InstanceBuilder& add_extension (std::string app_name);
|
||||||
|
|
||||||
|
InstanceBuilder& setup_validation_layers (bool enable_validation = true);
|
||||||
|
InstanceBuilder& set_headless (bool headless = false);
|
||||||
|
|
||||||
|
InstanceBuilder& set_default_debug_messenger ();
|
||||||
|
InstanceBuilder& set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback);
|
||||||
|
InstanceBuilder& set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity);
|
||||||
|
InstanceBuilder& add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity);
|
||||||
|
InstanceBuilder& set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type);
|
||||||
|
InstanceBuilder& add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type);
|
||||||
|
|
||||||
|
InstanceBuilder& add_validation_disable (VkValidationCheckEXT check);
|
||||||
|
InstanceBuilder& add_validation_feature_enable (VkValidationFeatureEnableEXT enable);
|
||||||
|
InstanceBuilder& add_validation_feature_disable (VkValidationFeatureDisableEXT disable);
|
||||||
|
|
||||||
|
InstanceBuilder& set_allocator_callback (VkAllocationCallbacks* allocator);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct InstanceInfo
|
||||||
|
{
|
||||||
|
// VkApplicationInfo
|
||||||
|
std::string app_name;
|
||||||
|
std::string engine_name;
|
||||||
|
uint32_t application_version = 0;
|
||||||
|
uint32_t engine_version = 0;
|
||||||
|
uint32_t api_version = VK_MAKE_VERSION (1, 0, 0);
|
||||||
|
|
||||||
|
// VkInstanceCreateInfo
|
||||||
|
std::vector<std::string> layers;
|
||||||
|
std::vector<std::string> extensions;
|
||||||
|
VkInstanceCreateFlags flags = 0;
|
||||||
|
std::vector<VkBaseOutStructure*> pNext_elements;
|
||||||
|
VkAllocationCallbacks* allocator = nullptr;
|
||||||
|
|
||||||
|
// debug callback
|
||||||
|
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback = nullptr;
|
||||||
|
VkDebugUtilsMessageSeverityFlagsEXT debug_message_severity =
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT debug_message_type =
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||||
|
|
||||||
|
// validation features
|
||||||
|
std::vector<VkValidationCheckEXT> disabled_validation_checks;
|
||||||
|
std::vector<VkValidationFeatureEnableEXT> enabled_validation_features;
|
||||||
|
std::vector<VkValidationFeatureDisableEXT> disabled_validation_features;
|
||||||
|
|
||||||
|
// booleans
|
||||||
|
bool ignore_non_critical_issues = true;
|
||||||
|
bool enable_validation_layers = false;
|
||||||
|
bool use_debug_messenger = false;
|
||||||
|
bool headless_context = false;
|
||||||
|
} info;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
struct SurfaceSupportDetails
|
||||||
|
{
|
||||||
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
|
std::vector<VkSurfaceFormatKHR> formats;
|
||||||
|
std::vector<VkPresentModeKHR> present_modes;
|
||||||
|
};
|
||||||
|
|
||||||
|
Expected<SurfaceSupportDetails, VkResult> query_surface_support_details (
|
||||||
|
VkPhysicalDevice phys_device, VkSurfaceKHR surface);
|
||||||
|
|
||||||
|
struct QueueFamilies
|
||||||
|
{
|
||||||
|
int graphics = -1;
|
||||||
|
int present = -1;
|
||||||
|
int transfer = -1;
|
||||||
|
int compute = -1;
|
||||||
|
int sparse = -1;
|
||||||
|
uint32_t count_graphics = 0;
|
||||||
|
uint32_t count_transfer = 0;
|
||||||
|
uint32_t count_compute = 0;
|
||||||
|
uint32_t count_sparse = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
VkFormat find_supported_format (VkPhysicalDevice physical_device,
|
||||||
|
const std::vector<VkFormat>& candidates,
|
||||||
|
VkImageTiling tiling,
|
||||||
|
VkFormatFeatureFlags features);
|
||||||
|
|
||||||
|
bool check_device_extension_support (VkPhysicalDevice device, std::vector<std::string> extensions);
|
||||||
|
|
||||||
|
detail::QueueFamilies find_queue_families (VkPhysicalDevice physDevice, VkSurfaceKHR windowSurface);
|
||||||
|
|
||||||
|
bool supports_features (VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested);
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// ---- Physical Device ---- //
|
||||||
|
|
||||||
|
struct PhysicalDevice
|
||||||
|
{
|
||||||
|
VkPhysicalDevice phys_device = VK_NULL_HANDLE;
|
||||||
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
VkPhysicalDeviceProperties physical_device_properties{};
|
||||||
|
VkPhysicalDeviceFeatures physical_device_features{};
|
||||||
|
VkPhysicalDeviceMemoryProperties memory_properties{};
|
||||||
|
|
||||||
|
detail::QueueFamilies queue_family_properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
void populate_physical_device_details (PhysicalDevice physical_device);
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
struct PhysicalDeviceSelector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PhysicalDeviceSelector (Instance instance);
|
||||||
|
|
||||||
|
detail::Expected<PhysicalDevice, VkResult> select ();
|
||||||
|
|
||||||
|
PhysicalDeviceSelector& set_surface (VkSurfaceKHR instance);
|
||||||
|
|
||||||
|
PhysicalDeviceSelector& prefer_discrete (bool prefer_discrete = true);
|
||||||
|
PhysicalDeviceSelector& prefer_integrated (bool prefer_integrated = true);
|
||||||
|
PhysicalDeviceSelector& allow_fallback (bool fallback = true);
|
||||||
|
|
||||||
|
PhysicalDeviceSelector& require_present (bool require = true);
|
||||||
|
PhysicalDeviceSelector& require_dedicated_transfer_queue ();
|
||||||
|
PhysicalDeviceSelector& require_dedicated_compute_queue ();
|
||||||
|
|
||||||
|
PhysicalDeviceSelector& required_device_memory_size (VkDeviceSize size);
|
||||||
|
PhysicalDeviceSelector& desired_device_memory_size (VkDeviceSize size);
|
||||||
|
|
||||||
|
PhysicalDeviceSelector& add_required_extension (std::string extension);
|
||||||
|
PhysicalDeviceSelector& add_desired_extension (std::string extension);
|
||||||
|
|
||||||
|
PhysicalDeviceSelector& set_desired_version (uint32_t major, uint32_t minor);
|
||||||
|
PhysicalDeviceSelector& set_minimum_version (uint32_t major = 1, uint32_t minor = 0);
|
||||||
|
|
||||||
|
PhysicalDeviceSelector& set_required_features (VkPhysicalDeviceFeatures features);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PhysicalDeviceInfo
|
||||||
|
{
|
||||||
|
VkInstance instance = VK_NULL_HANDLE;
|
||||||
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
|
bool headless = false;
|
||||||
|
} info;
|
||||||
|
|
||||||
|
struct SelectionCriteria
|
||||||
|
{
|
||||||
|
bool prefer_discrete = true;
|
||||||
|
bool prefer_integrated = false;
|
||||||
|
bool allow_fallback = true;
|
||||||
|
bool require_present = true;
|
||||||
|
bool require_dedicated_transfer_queue = false;
|
||||||
|
bool require_dedicated_compute_queue = false;
|
||||||
|
VkDeviceSize required_mem_size = 0;
|
||||||
|
VkDeviceSize desired_mem_size = 0;
|
||||||
|
|
||||||
|
std::vector<std::string> required_extensions;
|
||||||
|
std::vector<std::string> desired_extensions;
|
||||||
|
|
||||||
|
uint32_t required_version = VK_MAKE_VERSION (1, 0, 0);
|
||||||
|
uint32_t desired_version = VK_MAKE_VERSION (1, 0, 0);
|
||||||
|
|
||||||
|
VkPhysicalDeviceFeatures required_features{};
|
||||||
|
|
||||||
|
} criteria;
|
||||||
|
|
||||||
|
enum class Suitable
|
||||||
|
{
|
||||||
|
yes,
|
||||||
|
partial,
|
||||||
|
no
|
||||||
|
};
|
||||||
|
|
||||||
|
Suitable is_device_suitable (VkPhysicalDevice phys_device);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- Device ---- //
|
||||||
|
|
||||||
|
struct Device
|
||||||
|
{
|
||||||
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
|
VkAllocationCallbacks* allocator = VK_NULL_HANDLE;
|
||||||
|
PhysicalDevice physical_device;
|
||||||
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
|
};
|
||||||
|
|
||||||
|
void destroy_device (Device device);
|
||||||
|
|
||||||
|
class DeviceBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeviceBuilder (PhysicalDevice device);
|
||||||
|
detail::Expected<Device, VkResult> build ();
|
||||||
|
|
||||||
|
template <typename T> DeviceBuilder& add_pNext (T* structure);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct DeviceInfo
|
||||||
|
{
|
||||||
|
VkDeviceCreateFlags flags;
|
||||||
|
std::vector<VkBaseOutStructure*> pNext_chain;
|
||||||
|
VkAllocationCallbacks* allocator = VK_NULL_HANDLE;
|
||||||
|
PhysicalDevice physical_device;
|
||||||
|
std::vector<std::string> extensions;
|
||||||
|
} info;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- Queue ---- //
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
VkQueue get_queue (Device const& device, uint32_t family, uint32_t index = 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::Expected<VkQueue, VkResult> get_queue_present (Device const& device);
|
||||||
|
detail::Expected<VkQueue, VkResult> get_queue_graphics (Device const& device, uint32_t index = 0);
|
||||||
|
detail::Expected<VkQueue, VkResult> get_queue_compute (Device const& device, uint32_t index = 0);
|
||||||
|
detail::Expected<VkQueue, VkResult> get_queue_transfer (Device const& device, uint32_t index = 0);
|
||||||
|
detail::Expected<VkQueue, VkResult> get_queue_sparse (Device const& device, uint32_t index = 0);
|
||||||
|
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector<VkSurfaceFormatKHR> const& availableFormats);
|
||||||
|
VkPresentModeKHR choose_swap_present_mode (std::vector<VkPresentModeKHR> const& availablePresentModes);
|
||||||
|
VkExtent2D choose_swap_extent (
|
||||||
|
VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height);
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
struct Swapchain
|
||||||
|
{
|
||||||
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
|
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||||
|
VkAllocationCallbacks* allocator = VK_NULL_HANDLE;
|
||||||
|
std::vector<VkImage> images;
|
||||||
|
VkFormat image_format = VK_FORMAT_UNDEFINED;
|
||||||
|
VkExtent2D extent = { 0, 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
class SwapchainBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SwapchainBuilder (Device const& device);
|
||||||
|
|
||||||
|
detail::Expected<Swapchain, VkResult> build ();
|
||||||
|
detail::Expected<Swapchain, VkResult> recreate (Swapchain const& swapchain);
|
||||||
|
void destroy (Swapchain const& swapchain);
|
||||||
|
|
||||||
|
SwapchainBuilder& set_desired_format (VkFormat format);
|
||||||
|
SwapchainBuilder& set_fallback_format (VkFormat format);
|
||||||
|
|
||||||
|
SwapchainBuilder& set_desired_present_mode (VkPresentModeKHR present_mode);
|
||||||
|
SwapchainBuilder& set_fallback_present_mode (VkPresentModeKHR present_mode);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct SwapchainInfo
|
||||||
|
{
|
||||||
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
|
PhysicalDevice physical_device;
|
||||||
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
|
VkSwapchainKHR old_swapchain = VK_NULL_HANDLE;
|
||||||
|
VkFormat desired_format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
VkFormat fallback_format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
VkPresentModeKHR fallback_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
std::vector<VkPresentModeKHR> acceptable_present_modes;
|
||||||
|
uint32_t desired_width = 256;
|
||||||
|
uint32_t desired_height = 256;
|
||||||
|
} info;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vkb
|
@ -1,10 +1,15 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "VkBootstrap.h"
|
#include "VkBootstrap.h"
|
||||||
|
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
|
#include "catch2/catch.hpp"
|
||||||
|
|
||||||
GLFWwindow* create_window_glfw ()
|
GLFWwindow* create_window_glfw ()
|
||||||
{
|
{
|
||||||
glfwInit ();
|
glfwInit ();
|
||||||
@ -30,27 +35,34 @@ int test_happy_path ()
|
|||||||
{
|
{
|
||||||
auto window = create_window_glfw ();
|
auto window = create_window_glfw ();
|
||||||
|
|
||||||
vkbs::InstanceBuilder instance_builder;
|
vkb::InstanceBuilder instance_builder;
|
||||||
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
||||||
if (!instance_ret) return -1; // couldn't make instance
|
if (!instance_ret)
|
||||||
vkbs::Instance instance = instance_ret.value ();
|
{
|
||||||
|
std::cout << instance_ret.error ().msg << "\n";
|
||||||
|
return -1; // couldn't make instance
|
||||||
|
}
|
||||||
|
vkb::Instance instance = instance_ret.value ();
|
||||||
|
printf ("made instance\n");
|
||||||
|
|
||||||
auto surface = create_surface_glfw (instance.instance, window);
|
auto surface = create_surface_glfw (instance.instance, window);
|
||||||
|
|
||||||
vkbs::PhysicalDeviceSelector phys_device_selector (instance);
|
vkb::PhysicalDeviceSelector phys_device_selector (instance);
|
||||||
auto phys_device_ret = phys_device_selector.set_surface (surface).select ();
|
auto phys_device_ret = phys_device_selector.set_surface (surface).select ();
|
||||||
if (!phys_device_ret) return -2; // couldn't select physical device
|
if (!phys_device_ret) return -2; // couldn't select physical device
|
||||||
vkbs::PhysicalDevice physical_device = phys_device_ret.value ();
|
vkb::PhysicalDevice physical_device = phys_device_ret.value ();
|
||||||
|
printf ("made physical device\n");
|
||||||
|
|
||||||
vkbs::DeviceBuilder device_builder (physical_device);
|
vkb::DeviceBuilder device_builder (physical_device);
|
||||||
auto device_ret = device_builder.build ();
|
auto device_ret = device_builder.build ();
|
||||||
if (!device_ret) return -3; // couldn't create device
|
if (!device_ret) return -1; // couldn't create device
|
||||||
vkbs::Device device = device_ret.value ();
|
vkb::Device device = device_ret.value ();
|
||||||
|
printf ("made device\n");
|
||||||
|
|
||||||
// possible swapchain creation...
|
// possible swapchain creation...
|
||||||
|
|
||||||
vkbs::destroy_device (device);
|
vkb::destroy_device (device);
|
||||||
vkbs::destroy_instance (instance);
|
vkb::destroy_instance (instance);
|
||||||
destroy_window_glfw (window);
|
destroy_window_glfw (window);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -59,7 +71,7 @@ int test_happy_path ()
|
|||||||
int test_instance_basic ()
|
int test_instance_basic ()
|
||||||
{
|
{
|
||||||
|
|
||||||
vkbs::InstanceBuilder builder;
|
vkb::InstanceBuilder builder;
|
||||||
|
|
||||||
auto instance_ret =
|
auto instance_ret =
|
||||||
builder.setup_validation_layers ()
|
builder.setup_validation_layers ()
|
||||||
@ -68,8 +80,8 @@ int test_instance_basic ()
|
|||||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
void* pUserData) -> VkBool32 {
|
void* pUserData) -> VkBool32 {
|
||||||
auto ms = vkbs::DebugMessageSeverity (messageSeverity);
|
auto ms = vkb::DebugMessageSeverity (messageSeverity);
|
||||||
auto mt = vkbs::DebugMessageType (messageType);
|
auto mt = vkb::DebugMessageType (messageType);
|
||||||
printf ("[%s: %s](user defined)\n%s\n", ms, mt, pCallbackData->pMessage);
|
printf ("[%s: %s](user defined)\n%s\n", ms, mt, pCallbackData->pMessage);
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
})
|
})
|
||||||
@ -85,7 +97,7 @@ int test_instance_basic ()
|
|||||||
int test_instance_headless ()
|
int test_instance_headless ()
|
||||||
{
|
{
|
||||||
|
|
||||||
vkbs::InstanceBuilder builder;
|
vkb::InstanceBuilder builder;
|
||||||
|
|
||||||
auto instance_ret = builder.setup_validation_layers ()
|
auto instance_ret = builder.setup_validation_layers ()
|
||||||
.set_headless ()
|
.set_headless ()
|
||||||
@ -104,13 +116,13 @@ int test_instance_headless ()
|
|||||||
|
|
||||||
int test_physical_device_selection ()
|
int test_physical_device_selection ()
|
||||||
{
|
{
|
||||||
vkbs::InstanceBuilder instance_builder;
|
vkb::InstanceBuilder instance_builder;
|
||||||
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
||||||
auto instance = instance_ret.value ();
|
auto instance = instance_ret.value ();
|
||||||
auto window = create_window_glfw ();
|
auto window = create_window_glfw ();
|
||||||
auto surface = create_surface_glfw (instance.instance, window);
|
auto surface = create_surface_glfw (instance.instance, window);
|
||||||
|
|
||||||
vkbs::PhysicalDeviceSelector selector (instance);
|
vkb::PhysicalDeviceSelector selector (instance);
|
||||||
auto phys_dev_ret = selector.set_surface (surface)
|
auto phys_dev_ret = selector.set_surface (surface)
|
||||||
.add_desired_extension (VK_KHR_MULTIVIEW_EXTENSION_NAME)
|
.add_desired_extension (VK_KHR_MULTIVIEW_EXTENSION_NAME)
|
||||||
.add_required_extension (VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)
|
.add_required_extension (VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)
|
||||||
@ -121,24 +133,24 @@ int test_physical_device_selection ()
|
|||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
vkbs::destroy_instance (instance);
|
vkb::destroy_instance (instance);
|
||||||
destroy_window_glfw (window);
|
destroy_window_glfw (window);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_device_creation ()
|
int test_device_creation ()
|
||||||
{
|
{
|
||||||
vkbs::InstanceBuilder instance_builder;
|
vkb::InstanceBuilder instance_builder;
|
||||||
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
||||||
auto instance = instance_ret.value ();
|
auto instance = instance_ret.value ();
|
||||||
auto window = create_window_glfw ();
|
auto window = create_window_glfw ();
|
||||||
auto surface = create_surface_glfw (instance.instance, window);
|
auto surface = create_surface_glfw (instance.instance, window);
|
||||||
|
|
||||||
vkbs::PhysicalDeviceSelector selector (instance);
|
vkb::PhysicalDeviceSelector selector (instance);
|
||||||
auto phys_dev_ret = selector.set_surface (surface).select ();
|
auto phys_dev_ret = selector.set_surface (surface).select ();
|
||||||
auto phys_dev = phys_dev_ret.value ();
|
auto phys_dev = phys_dev_ret.value ();
|
||||||
|
|
||||||
vkbs::DeviceBuilder device_builder (phys_dev);
|
vkb::DeviceBuilder device_builder (phys_dev);
|
||||||
auto dev_ret = device_builder.build ();
|
auto dev_ret = device_builder.build ();
|
||||||
if (!dev_ret.has_value ())
|
if (!dev_ret.has_value ())
|
||||||
{
|
{
|
||||||
@ -146,8 +158,8 @@ int test_device_creation ()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
vkbs::destroy_device (dev_ret.value ());
|
vkb::destroy_device (dev_ret.value ());
|
||||||
vkbs::destroy_instance (instance);
|
vkb::destroy_instance (instance);
|
||||||
destroy_window_glfw (window);
|
destroy_window_glfw (window);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
11
tests/test.cpp
Normal file
11
tests/test.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include "VkBootstrap.h"
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_MAIN
|
Loading…
Reference in New Issue
Block a user