2020-01-31 22:23:22 +00:00
|
|
|
#include "VkBootstrap.h"
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
namespace vkb {
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
// Helper for robustly executing the two-call pattern
|
|
|
|
template <typename T, typename F, typename... Ts>
|
|
|
|
auto get_vector (F&& f, 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) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return err;
|
2020-02-06 22:46:14 +00:00
|
|
|
};
|
|
|
|
results.resize (count);
|
|
|
|
err = f (ts..., &count, results.data ());
|
|
|
|
} while (err == VK_INCOMPLETE);
|
2020-02-10 18:29:09 +00:00
|
|
|
if (err != VK_SUCCESS) {
|
|
|
|
return err;
|
2020-02-06 22:46:14 +00:00
|
|
|
};
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename F, typename... Ts>
|
|
|
|
auto get_vector_noerror (F&& f, Ts&&... ts) -> std::vector<T> {
|
|
|
|
uint32_t count = 0;
|
|
|
|
std::vector<T> results;
|
|
|
|
f (ts..., &count, nullptr);
|
|
|
|
results.resize (count);
|
|
|
|
f (ts..., &count, results.data ());
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
} // namespace detail
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s) {
|
|
|
|
switch (s) {
|
2020-01-31 22:23:22 +00:00
|
|
|
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";
|
|
|
|
}
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
const char* to_string_message_type (VkDebugUtilsMessageTypeFlagsEXT s) {
|
|
|
|
switch (s) {
|
2020-01-31 22:23:22 +00:00
|
|
|
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";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VkResult create_debug_utils_messenger (VkInstance instance,
|
|
|
|
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback,
|
|
|
|
VkDebugUtilsMessageSeverityFlagsEXT severity,
|
|
|
|
VkDebugUtilsMessageTypeFlagsEXT type,
|
2020-02-06 22:46:14 +00:00
|
|
|
VkDebugUtilsMessengerEXT* pDebugMessenger) {
|
2020-01-31 22:23:22 +00:00
|
|
|
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");
|
2020-02-06 22:46:14 +00:00
|
|
|
if (vkCreateDebugUtilsMessengerEXT_func != nullptr) {
|
2020-02-06 21:20:39 +00:00
|
|
|
return vkCreateDebugUtilsMessengerEXT_func (instance, &messengerCreateInfo, nullptr, pDebugMessenger);
|
2020-02-06 22:46:14 +00:00
|
|
|
} else {
|
2020-01-31 22:23:22 +00:00
|
|
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
void destroy_debug_utils_messenger (VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger) {
|
2020-01-31 22:23:22 +00:00
|
|
|
auto vkDestroyDebugUtilsMessengerEXT_func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr (
|
|
|
|
instance, "vkDestroyDebugUtilsMessengerEXT");
|
2020-02-06 22:46:14 +00:00
|
|
|
if (vkDestroyDebugUtilsMessengerEXT_func != nullptr) {
|
2020-02-06 21:20:39 +00:00
|
|
|
vkDestroyDebugUtilsMessengerEXT_func (instance, debugMessenger, nullptr);
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VkBool32 default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
|
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
|
|
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
2020-02-06 22:46:14 +00:00
|
|
|
void* pUserData) {
|
2020-02-04 03:34:46 +00:00
|
|
|
auto ms = to_string_message_severity (messageSeverity);
|
|
|
|
auto mt = to_string_message_type (messageType);
|
2020-01-31 22:23:22 +00:00
|
|
|
printf ("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage);
|
|
|
|
return VK_FALSE;
|
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
namespace detail {
|
|
|
|
bool check_layers_supported (std::vector<const char*> layer_names) {
|
2020-01-31 22:23:22 +00:00
|
|
|
auto available_layers = detail::get_vector<VkLayerProperties> (vkEnumerateInstanceLayerProperties);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (!available_layers.has_value ()) {
|
2020-01-31 22:23:22 +00:00
|
|
|
return false; // maybe report error?
|
|
|
|
}
|
|
|
|
bool all_found = true;
|
2020-02-06 22:46:14 +00:00
|
|
|
for (const auto& layer_name : layer_names) {
|
2020-01-31 22:23:22 +00:00
|
|
|
bool found = false;
|
2020-02-06 22:46:14 +00:00
|
|
|
for (const auto& layer_properties : available_layers.value ()) {
|
|
|
|
if (strcmp (layer_name, layer_properties.layerName) == 0) {
|
2020-01-31 22:23:22 +00:00
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) all_found = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return all_found;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
bool check_extensions_supported (std::vector<const char*> extension_names) {
|
|
|
|
auto available_extensions =
|
|
|
|
detail::get_vector<VkExtensionProperties> (vkEnumerateInstanceExtensionProperties, nullptr);
|
|
|
|
if (!available_extensions.has_value ()) {
|
|
|
|
return false; // maybe report error?
|
|
|
|
}
|
|
|
|
bool all_found = true;
|
|
|
|
for (const auto& extension_name : extension_names) {
|
|
|
|
bool found = false;
|
|
|
|
for (const auto& layer_properties : available_extensions.value ()) {
|
|
|
|
if (strcmp (extension_name, layer_properties.extensionName) == 0) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) all_found = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return all_found;
|
|
|
|
}
|
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
template <typename T>
|
2020-02-06 22:46:14 +00:00
|
|
|
void setup_pNext_chain (T& structure, std::vector<VkBaseOutStructure*>& structs) {
|
2020-01-31 22:23:22 +00:00
|
|
|
structure.pNext = nullptr;
|
|
|
|
if (structs.size () <= 0) return;
|
2020-02-06 22:46:14 +00:00
|
|
|
for (int i = 0; i < structs.size () - 1; i++) {
|
2020-01-31 22:23:22 +00:00
|
|
|
VkBaseOutStructure* cur = reinterpret_cast<VkBaseOutStructure*> (&structs[i]);
|
|
|
|
cur = reinterpret_cast<VkBaseOutStructure*> (&structs[i + 1]);
|
|
|
|
}
|
|
|
|
structure.pNext = &structs.at (0);
|
|
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
void destroy_instance (Instance instance) {
|
|
|
|
if (instance.instance != VK_NULL_HANDLE) {
|
2020-02-04 03:34:46 +00:00
|
|
|
if (instance.debug_messenger != nullptr)
|
2020-02-06 22:46:14 +00:00
|
|
|
destroy_debug_utils_messenger (instance.instance, instance.debug_messenger);
|
2020-02-06 21:20:39 +00:00
|
|
|
vkDestroyInstance (instance.instance, nullptr);
|
2020-02-04 03:34:46 +00:00
|
|
|
}
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build () {
|
2020-01-31 22:23:22 +00:00
|
|
|
|
|
|
|
VkApplicationInfo app_info = {};
|
|
|
|
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
|
|
app_info.pNext = nullptr;
|
2020-02-17 20:22:49 +00:00
|
|
|
app_info.pApplicationName = info.app_name != nullptr ? info.app_name : "";
|
2020-01-31 22:23:22 +00:00
|
|
|
app_info.applicationVersion = info.application_version;
|
2020-02-17 20:22:49 +00:00
|
|
|
app_info.pEngineName = info.engine_name != nullptr ? info.engine_name : "";
|
2020-01-31 22:23:22 +00:00
|
|
|
app_info.engineVersion = info.engine_version;
|
|
|
|
app_info.apiVersion = info.api_version;
|
|
|
|
|
|
|
|
std::vector<const char*> extensions;
|
|
|
|
for (auto& ext : info.extensions)
|
2020-02-12 00:51:03 +00:00
|
|
|
extensions.push_back (ext);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (info.debug_callback != nullptr) {
|
2020-02-12 00:51:03 +00:00
|
|
|
extensions.push_back (VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
if (!info.headless_context) {
|
2020-02-17 20:13:09 +00:00
|
|
|
extensions.push_back ("VK_KHR_surface");
|
2020-01-31 22:23:22 +00:00
|
|
|
#if defined(_WIN32)
|
2020-02-03 23:23:47 +00:00
|
|
|
extensions.push_back ("VK_KHR_win32_surface");
|
|
|
|
#elif defined(__ANDROID__)
|
2020-02-17 20:13:09 +00:00
|
|
|
extensions.push_back ("VK_KHR_android_surface");
|
2020-01-31 22:23:22 +00:00
|
|
|
#elif defined(_DIRECT2DISPLAY)
|
2020-02-17 20:13:09 +00:00
|
|
|
extensions.push_back ("VK_KHR_display");
|
2020-02-03 23:23:47 +00:00
|
|
|
#elif defined(__linux__)
|
|
|
|
extensions.push_back ("VK_KHR_xcb_surface");
|
|
|
|
extensions.push_back ("VK_KHR_xlib_surface");
|
|
|
|
extensions.push_back ("VK_KHR_wayland_surface");
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
extensions.push_back ("VK_KHR_metal_surface");
|
2020-01-31 22:23:22 +00:00
|
|
|
#endif
|
|
|
|
}
|
2020-02-11 01:01:58 +00:00
|
|
|
bool all_extensions_supported = detail::check_extensions_supported (extensions);
|
|
|
|
if (!all_extensions_supported) {
|
|
|
|
return detail::Error<InstanceError>{ InstanceError::requested_extensions_not_present };
|
|
|
|
}
|
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
std::vector<const char*> layers;
|
|
|
|
for (auto& layer : info.layers)
|
2020-02-12 00:51:03 +00:00
|
|
|
layers.push_back (layer);
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
if (info.enable_validation_layers) {
|
2020-01-31 22:23:22 +00:00
|
|
|
layers.push_back ("VK_LAYER_KHRONOS_validation");
|
|
|
|
}
|
|
|
|
bool all_layers_supported = detail::check_layers_supported (layers);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (!all_layers_supported) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<InstanceError>{ InstanceError::requested_layers_not_present };
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
|
2020-02-06 22:46:14 +00:00
|
|
|
if (info.use_debug_messenger) {
|
2020-01-31 22:23:22 +00:00
|
|
|
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{};
|
2020-02-06 22:46:14 +00:00
|
|
|
if (info.enabled_validation_features.size () != 0 || info.disabled_validation_features.size ()) {
|
2020-01-31 22:23:22 +00:00
|
|
|
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{};
|
2020-02-06 22:46:14 +00:00
|
|
|
if (info.disabled_validation_checks.size () != 0) {
|
2020-01-31 22:23:22 +00:00
|
|
|
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);
|
2020-02-10 18:29:09 +00:00
|
|
|
if (res != VK_SUCCESS)
|
|
|
|
return detail::Error<InstanceError>{ InstanceError::failed_create_instance, res };
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
if (info.use_debug_messenger) {
|
|
|
|
res = create_debug_utils_messenger (instance.instance,
|
2020-01-31 22:23:22 +00:00
|
|
|
info.debug_callback,
|
|
|
|
info.debug_message_severity,
|
|
|
|
info.debug_message_type,
|
|
|
|
&instance.debug_messenger);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<InstanceError>{ InstanceError::failed_create_debug_messenger, res };
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
if (info.headless_context) {
|
2020-01-31 22:23:22 +00:00
|
|
|
instance.headless = true;
|
|
|
|
}
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2020-02-12 00:51:03 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_app_name (const char* app_name) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.app_name = app_name;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-12 00:51:03 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_engine_name (const char* engine_name) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.engine_name = engine_name;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_app_version (uint32_t major, uint32_t minor, uint32_t patch) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.application_version = VK_MAKE_VERSION (major, minor, patch);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_engine_version (uint32_t major, uint32_t minor, uint32_t patch) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.engine_version = VK_MAKE_VERSION (major, minor, patch);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_api_version (uint32_t major, uint32_t minor, uint32_t patch) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.api_version = VK_MAKE_VERSION (major, minor, patch);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-12 00:51:03 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_layer (const char* layer_name) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.layers.push_back (layer_name);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-12 00:51:03 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_extension (const char* extension_name) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.extensions.push_back (extension_name);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::setup_validation_layers (bool enable_validation) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.enable_validation_layers = enable_validation;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_default_debug_messenger () {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.use_debug_messenger = true;
|
2020-02-06 22:46:14 +00:00
|
|
|
info.debug_callback = default_debug_callback;
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.use_debug_messenger = true;
|
|
|
|
info.debug_callback = callback;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_headless (bool headless) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.headless_context = headless;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.debug_message_severity = severity;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.debug_message_severity = info.debug_message_severity | severity;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.debug_message_type = type;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.debug_message_type = info.debug_message_type | type;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_validation_disable (VkValidationCheckEXT check) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.disabled_validation_checks.push_back (check);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_validation_feature_enable (VkValidationFeatureEnableEXT enable) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.enabled_validation_features.push_back (enable);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_validation_feature_disable (VkValidationFeatureDisableEXT disable) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.disabled_validation_features.push_back (disable);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-02-17 20:13:09 +00:00
|
|
|
// ---- Physical Device ---- //
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
struct SurfaceSupportDetails {
|
|
|
|
VkSurfaceCapabilitiesKHR capabilities;
|
|
|
|
std::vector<VkSurfaceFormatKHR> formats;
|
|
|
|
std::vector<VkPresentModeKHR> present_modes;
|
|
|
|
};
|
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
enum class SurfaceSupportError {
|
|
|
|
surface_handle_null,
|
|
|
|
failed_get_surface_capabilities,
|
|
|
|
failed_enumerate_surface_formats,
|
|
|
|
failed_enumerate_present_modes
|
|
|
|
};
|
|
|
|
|
|
|
|
Expected<SurfaceSupportDetails, detail::Error<SurfaceSupportError>> query_surface_support_details (
|
2020-02-06 22:46:14 +00:00
|
|
|
VkPhysicalDevice phys_device, VkSurfaceKHR surface) {
|
2020-01-30 08:15:10 +00:00
|
|
|
if (surface == VK_NULL_HANDLE)
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::surface_handle_null };
|
2020-01-30 08:15:10 +00:00
|
|
|
|
|
|
|
VkSurfaceCapabilitiesKHR capabilities;
|
|
|
|
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_get_surface_capabilities, res };
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
|
|
|
auto formats = detail::get_vector<VkSurfaceFormatKHR> (
|
|
|
|
vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
|
|
|
|
if (!formats.has_value ())
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_enumerate_surface_formats,
|
|
|
|
formats.error () };
|
2020-01-30 08:15:10 +00:00
|
|
|
auto present_modes = detail::get_vector<VkPresentModeKHR> (
|
|
|
|
vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface);
|
|
|
|
if (!present_modes.has_value ())
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_enumerate_present_modes,
|
|
|
|
formats.error () };
|
2020-01-30 08:15:10 +00:00
|
|
|
return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () };
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Given a list of formats, return a format supported by the hardware, else return VK_FORMAT_UNDEFINED
|
2020-02-06 22:46:14 +00:00
|
|
|
VkFormat find_supported_format (VkPhysicalDevice physical_device,
|
|
|
|
const std::vector<VkFormat>& candidates,
|
|
|
|
VkImageTiling tiling,
|
|
|
|
VkFormatFeatureFlags features) {
|
|
|
|
for (VkFormat format : candidates) {
|
2020-01-30 08:15:10 +00:00
|
|
|
VkFormatProperties props;
|
|
|
|
vkGetPhysicalDeviceFormatProperties (physical_device, format, &props);
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) {
|
2020-01-30 08:15:10 +00:00
|
|
|
return format;
|
2020-02-06 22:46:14 +00:00
|
|
|
} else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) {
|
2020-01-30 08:15:10 +00:00
|
|
|
return format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return VK_FORMAT_UNDEFINED;
|
|
|
|
}
|
|
|
|
|
2020-02-12 00:51:03 +00:00
|
|
|
std::vector<const char*> check_device_extension_support (
|
|
|
|
VkPhysicalDevice device, std::vector<const char*> desired_extensions) {
|
2020-01-30 08:15:10 +00:00
|
|
|
auto available_extensions =
|
|
|
|
detail::get_vector<VkExtensionProperties> (vkEnumerateDeviceExtensionProperties, device, nullptr);
|
2020-02-03 23:23:47 +00:00
|
|
|
if (!available_extensions.has_value ()) return {};
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-12 00:51:03 +00:00
|
|
|
std::vector<const char*> extensions_to_enable;
|
2020-02-06 22:46:14 +00:00
|
|
|
for (const auto& extension : available_extensions.value ()) {
|
|
|
|
for (auto& req_ext : desired_extensions) {
|
2020-02-03 23:23:47 +00:00
|
|
|
if (req_ext == extension.extensionName) extensions_to_enable.push_back (req_ext);
|
2020-01-30 08:15:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-02-03 23:23:47 +00:00
|
|
|
return extensions_to_enable;
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
bool supports_features (VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested) {
|
2020-01-30 08:15:10 +00:00
|
|
|
// clang-format off
|
2020-02-04 03:34:46 +00:00
|
|
|
if (requested.robustBufferAccess && !supported.robustBufferAccess) return false;
|
|
|
|
if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32) return false;
|
|
|
|
if (requested.imageCubeArray && !supported.imageCubeArray) return false;
|
|
|
|
if (requested.independentBlend && !supported.independentBlend) return false;
|
|
|
|
if (requested.geometryShader && !supported.geometryShader) return false;
|
|
|
|
if (requested.tessellationShader && !supported.tessellationShader) return false;
|
|
|
|
if (requested.sampleRateShading && !supported.sampleRateShading) return false;
|
|
|
|
if (requested.dualSrcBlend && !supported.dualSrcBlend) return false;
|
|
|
|
if (requested.logicOp && !supported.logicOp) return false;
|
|
|
|
if (requested.multiDrawIndirect && !supported.multiDrawIndirect) return false;
|
|
|
|
if (requested.drawIndirectFirstInstance && !supported.drawIndirectFirstInstance) return false;
|
|
|
|
if (requested.depthClamp && !supported.depthClamp) return false;
|
|
|
|
if (requested.depthBiasClamp && !supported.depthBiasClamp) return false;
|
|
|
|
if (requested.fillModeNonSolid && !supported.fillModeNonSolid) return false;
|
|
|
|
if (requested.depthBounds && !supported.depthBounds) return false;
|
|
|
|
if (requested.wideLines && !supported.wideLines) return false;
|
|
|
|
if (requested.largePoints && !supported.largePoints) return false;
|
|
|
|
if (requested.alphaToOne && !supported.alphaToOne) return false;
|
|
|
|
if (requested.multiViewport && !supported.multiViewport) return false;
|
|
|
|
if (requested.samplerAnisotropy && !supported.samplerAnisotropy) return false;
|
|
|
|
if (requested.textureCompressionETC2 && !supported.textureCompressionETC2) return false;
|
|
|
|
if (requested.textureCompressionASTC_LDR && !supported.textureCompressionASTC_LDR) return false;
|
|
|
|
if (requested.textureCompressionBC && !supported.textureCompressionBC) return false;
|
|
|
|
if (requested.occlusionQueryPrecise && !supported.occlusionQueryPrecise) return false;
|
|
|
|
if (requested.pipelineStatisticsQuery && !supported.pipelineStatisticsQuery) return false;
|
2020-01-30 08:15:10 +00:00
|
|
|
if (requested.vertexPipelineStoresAndAtomics && !supported.vertexPipelineStoresAndAtomics) return false;
|
|
|
|
if (requested.fragmentStoresAndAtomics && !supported.fragmentStoresAndAtomics) return false;
|
|
|
|
if (requested.shaderTessellationAndGeometryPointSize && !supported.shaderTessellationAndGeometryPointSize) return false;
|
|
|
|
if (requested.shaderImageGatherExtended && !supported.shaderImageGatherExtended) return false;
|
|
|
|
if (requested.shaderStorageImageExtendedFormats && !supported.shaderStorageImageExtendedFormats) return false;
|
|
|
|
if (requested.shaderStorageImageMultisample && !supported.shaderStorageImageMultisample) return false;
|
|
|
|
if (requested.shaderStorageImageReadWithoutFormat && !supported.shaderStorageImageReadWithoutFormat) return false;
|
|
|
|
if (requested.shaderStorageImageWriteWithoutFormat && !supported.shaderStorageImageWriteWithoutFormat) return false;
|
|
|
|
if (requested.shaderUniformBufferArrayDynamicIndexing && !supported.shaderUniformBufferArrayDynamicIndexing) return false;
|
|
|
|
if (requested.shaderSampledImageArrayDynamicIndexing && !supported.shaderSampledImageArrayDynamicIndexing) return false;
|
|
|
|
if (requested.shaderStorageBufferArrayDynamicIndexing && !supported.shaderStorageBufferArrayDynamicIndexing) return false;
|
|
|
|
if (requested.shaderStorageImageArrayDynamicIndexing && !supported.shaderStorageImageArrayDynamicIndexing) return false;
|
|
|
|
if (requested.shaderClipDistance && !supported.shaderClipDistance) return false;
|
|
|
|
if (requested.shaderCullDistance && !supported.shaderCullDistance) return false;
|
|
|
|
if (requested.shaderFloat64 && !supported.shaderFloat64) return false;
|
|
|
|
if (requested.shaderInt64 && !supported.shaderInt64) return false;
|
|
|
|
if (requested.shaderInt16 && !supported.shaderInt16) return false;
|
|
|
|
if (requested.shaderResourceResidency && !supported.shaderResourceResidency) return false;
|
|
|
|
if (requested.shaderResourceMinLod && !supported.shaderResourceMinLod) return false;
|
|
|
|
if (requested.sparseBinding && !supported.sparseBinding) return false;
|
|
|
|
if (requested.sparseResidencyBuffer && !supported.sparseResidencyBuffer) return false;
|
|
|
|
if (requested.sparseResidencyImage2D && !supported.sparseResidencyImage2D) return false;
|
|
|
|
if (requested.sparseResidencyImage3D && !supported.sparseResidencyImage3D) return false;
|
|
|
|
if (requested.sparseResidency2Samples && !supported.sparseResidency2Samples) return false;
|
|
|
|
if (requested.sparseResidency4Samples && !supported.sparseResidency4Samples) return false;
|
|
|
|
if (requested.sparseResidency8Samples && !supported.sparseResidency8Samples) return false;
|
|
|
|
if (requested.sparseResidency16Samples && !supported.sparseResidency16Samples) return false;
|
|
|
|
if (requested.sparseResidencyAliased && !supported.sparseResidencyAliased) return false;
|
|
|
|
if (requested.variableMultisampleRate && !supported.variableMultisampleRate) return false;
|
|
|
|
if (requested.inheritedQueries && !supported.inheritedQueries) return false;
|
|
|
|
// clang-format on
|
|
|
|
return true;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
} // namespace detail
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-08 00:34:05 +00:00
|
|
|
int get_graphics_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
|
|
|
|
for (int i = 0; i < families.size (); i++) {
|
|
|
|
if (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
int get_distinct_compute_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
|
2020-02-17 20:13:09 +00:00
|
|
|
int compute = -1;
|
2020-02-08 00:34:05 +00:00
|
|
|
for (int i = 0; i < families.size (); i++) {
|
|
|
|
if ((families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) &&
|
2020-02-17 20:13:09 +00:00
|
|
|
((families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) {
|
|
|
|
if ((families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) == 0) {
|
|
|
|
return i;
|
|
|
|
} else {
|
|
|
|
compute = i;
|
|
|
|
}
|
|
|
|
}
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
2020-02-17 20:13:09 +00:00
|
|
|
return compute;
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
|
|
|
int get_distinct_transfer_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
|
2020-02-17 20:13:09 +00:00
|
|
|
int transfer = -1;
|
2020-02-08 00:34:05 +00:00
|
|
|
for (int i = 0; i < families.size (); i++) {
|
|
|
|
if ((families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) &&
|
2020-02-17 20:13:09 +00:00
|
|
|
((families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) {
|
|
|
|
if ((families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0) {
|
|
|
|
return i;
|
|
|
|
} else {
|
|
|
|
transfer = i;
|
|
|
|
}
|
|
|
|
}
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
int get_present_queue_index (VkPhysicalDevice const phys_device,
|
|
|
|
VkSurfaceKHR const surface,
|
|
|
|
std::vector<VkQueueFamilyProperties> const& families) {
|
|
|
|
for (int i = 0; i < families.size (); i++) {
|
2020-02-06 22:46:14 +00:00
|
|
|
VkBool32 presentSupport = false;
|
|
|
|
if (surface != VK_NULL_HANDLE) {
|
|
|
|
VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR (phys_device, i, surface, &presentSupport);
|
|
|
|
}
|
2020-02-08 00:34:05 +00:00
|
|
|
if (presentSupport == true) return i;
|
2020-02-06 22:46:14 +00:00
|
|
|
}
|
2020-02-08 00:34:05 +00:00
|
|
|
return -1;
|
2020-02-06 22:46:14 +00:00
|
|
|
}
|
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details (
|
|
|
|
VkPhysicalDevice phys_device) {
|
|
|
|
PhysicalDeviceSelector::PhysicalDeviceDesc desc{};
|
|
|
|
desc.phys_device = phys_device;
|
2020-02-08 00:34:05 +00:00
|
|
|
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties> (
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties, phys_device);
|
2020-02-11 01:01:58 +00:00
|
|
|
desc.queue_families = queue_families;
|
|
|
|
|
|
|
|
vkGetPhysicalDeviceProperties (phys_device, &desc.device_properties);
|
|
|
|
vkGetPhysicalDeviceFeatures (phys_device, &desc.device_features);
|
|
|
|
vkGetPhysicalDeviceMemoryProperties (phys_device, &desc.mem_properties);
|
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
|
|
|
PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable (PhysicalDeviceDesc pd) {
|
|
|
|
Suitable suitable = Suitable::yes;
|
|
|
|
|
|
|
|
bool dedicated_compute = get_distinct_compute_queue_index (pd.queue_families);
|
|
|
|
bool dedicated_transfer = get_distinct_transfer_queue_index (pd.queue_families);
|
|
|
|
bool present_queue = get_present_queue_index (pd.phys_device, system_info.surface, pd.queue_families);
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-08 00:34:05 +00:00
|
|
|
if (criteria.require_dedicated_compute_queue && !dedicated_compute) suitable = Suitable::no;
|
|
|
|
if (criteria.require_dedicated_transfer_queue && !dedicated_transfer) suitable = Suitable::no;
|
|
|
|
if (criteria.require_present && !present_queue) suitable = Suitable::no;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-03 23:23:47 +00:00
|
|
|
auto required_extensions_supported =
|
2020-02-11 01:01:58 +00:00
|
|
|
detail::check_device_extension_support (pd.phys_device, criteria.required_extensions);
|
2020-02-03 23:23:47 +00:00
|
|
|
if (required_extensions_supported.size () != criteria.required_extensions.size ())
|
|
|
|
suitable = Suitable::no;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-03 23:23:47 +00:00
|
|
|
auto desired_extensions_supported =
|
2020-02-11 01:01:58 +00:00
|
|
|
detail::check_device_extension_support (pd.phys_device, criteria.desired_extensions);
|
2020-02-03 23:23:47 +00:00
|
|
|
if (desired_extensions_supported.size () != criteria.desired_extensions.size ())
|
|
|
|
suitable = Suitable::partial;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
bool swapChainAdequate = false;
|
2020-02-11 01:01:58 +00:00
|
|
|
if (!system_info.headless) {
|
|
|
|
auto swapChainSupport_ret =
|
|
|
|
detail::query_surface_support_details (pd.phys_device, system_info.surface);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (swapChainSupport_ret.has_value ()) {
|
2020-01-30 08:15:10 +00:00
|
|
|
auto swapchain_support = swapChainSupport_ret.value ();
|
|
|
|
swapChainAdequate =
|
|
|
|
!swapchain_support.formats.empty () && !swapchain_support.present_modes.empty ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (criteria.require_present && !swapChainAdequate) suitable = Suitable::no;
|
|
|
|
|
2020-02-06 23:56:50 +00:00
|
|
|
if ((criteria.preferred_type == PreferredDeviceType::discrete &&
|
2020-02-11 01:01:58 +00:00
|
|
|
pd.device_properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) ||
|
2020-02-06 23:56:50 +00:00
|
|
|
(criteria.preferred_type == PreferredDeviceType::integrated &&
|
2020-02-11 01:01:58 +00:00
|
|
|
pd.device_properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) ||
|
2020-02-06 23:56:50 +00:00
|
|
|
(criteria.preferred_type == PreferredDeviceType::virtual_gpu &&
|
2020-02-11 01:01:58 +00:00
|
|
|
pd.device_properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)) {
|
2020-01-30 08:15:10 +00:00
|
|
|
if (criteria.allow_fallback)
|
|
|
|
suitable = Suitable::partial;
|
|
|
|
else
|
|
|
|
suitable = Suitable::no;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
if (criteria.required_version < pd.device_properties.apiVersion) suitable = Suitable::no;
|
|
|
|
if (criteria.desired_version < pd.device_properties.apiVersion) suitable = Suitable::partial;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
bool required_features_supported =
|
2020-02-11 01:01:58 +00:00
|
|
|
detail::supports_features (pd.device_features, criteria.required_features);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (!required_features_supported) suitable = Suitable::no;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
bool has_required_memory = false;
|
|
|
|
bool has_preferred_memory = false;
|
|
|
|
for (int i = 0; i < pd.mem_properties.memoryHeapCount; i++) {
|
|
|
|
if (pd.mem_properties.memoryHeaps[i].flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
|
|
|
|
if (pd.mem_properties.memoryHeaps[i].size > criteria.required_mem_size) {
|
|
|
|
has_required_memory = true;
|
|
|
|
}
|
|
|
|
if (pd.mem_properties.memoryHeaps[i].size > criteria.desired_mem_size) {
|
|
|
|
has_preferred_memory = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!has_required_memory) suitable = Suitable::no;
|
|
|
|
if (!has_preferred_memory) suitable = Suitable::partial;
|
|
|
|
|
2020-01-30 08:15:10 +00:00
|
|
|
return suitable;
|
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector::PhysicalDeviceSelector (Instance const& instance) {
|
2020-02-11 01:01:58 +00:00
|
|
|
system_info.instance = instance.instance;
|
|
|
|
system_info.headless = instance.headless;
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.require_present = !instance.headless;
|
|
|
|
}
|
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<PhysicalDevice, detail::Error<PhysicalDeviceError>> PhysicalDeviceSelector::select () {
|
2020-02-11 01:01:58 +00:00
|
|
|
auto physical_devices =
|
|
|
|
detail::get_vector<VkPhysicalDevice> (vkEnumeratePhysicalDevices, system_info.instance);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (!physical_devices.has_value ()) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::failed_enumerate_physical_devices,
|
|
|
|
physical_devices.error () };
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
2020-02-06 23:56:50 +00:00
|
|
|
if (physical_devices.value ().size () == 0) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::no_physical_devices_found };
|
2020-02-06 23:56:50 +00:00
|
|
|
}
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
std::vector<PhysicalDeviceDesc> phys_device_descriptions;
|
|
|
|
for (auto& phys_device : physical_devices.value ()) {
|
|
|
|
phys_device_descriptions.push_back (populate_device_details (phys_device));
|
|
|
|
}
|
|
|
|
|
|
|
|
PhysicalDeviceDesc selected_device{};
|
|
|
|
|
2020-02-06 23:56:50 +00:00
|
|
|
if (criteria.use_first_gpu_unconditionally) {
|
2020-02-11 01:01:58 +00:00
|
|
|
selected_device = phys_device_descriptions.at (0);
|
2020-02-06 23:56:50 +00:00
|
|
|
} else {
|
2020-02-11 01:01:58 +00:00
|
|
|
for (const auto& device : phys_device_descriptions) {
|
2020-02-06 23:56:50 +00:00
|
|
|
auto suitable = is_device_suitable (device);
|
|
|
|
if (suitable == Suitable::yes) {
|
2020-02-11 01:01:58 +00:00
|
|
|
selected_device = device;
|
2020-02-06 23:56:50 +00:00
|
|
|
break;
|
|
|
|
} else if (suitable == Suitable::partial) {
|
2020-02-11 01:01:58 +00:00
|
|
|
selected_device = device;
|
2020-02-06 23:56:50 +00:00
|
|
|
}
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
if (selected_device.phys_device == VK_NULL_HANDLE) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::no_suitable_device };
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
2020-02-11 01:01:58 +00:00
|
|
|
PhysicalDevice out_device{};
|
|
|
|
out_device.phys_device = selected_device.phys_device;
|
|
|
|
out_device.surface = system_info.surface;
|
|
|
|
out_device.features = criteria.required_features;
|
|
|
|
out_device.queue_families = selected_device.queue_families;
|
2020-02-03 23:23:47 +00:00
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
out_device.extensions_to_enable.insert (out_device.extensions_to_enable.end (),
|
2020-02-03 23:23:47 +00:00
|
|
|
criteria.required_extensions.begin (),
|
|
|
|
criteria.required_extensions.end ());
|
|
|
|
auto desired_extensions_supported =
|
2020-02-11 01:01:58 +00:00
|
|
|
detail::check_device_extension_support (out_device.phys_device, criteria.desired_extensions);
|
|
|
|
out_device.extensions_to_enable.insert (out_device.extensions_to_enable.end (),
|
2020-02-03 23:23:47 +00:00
|
|
|
desired_extensions_supported.begin (),
|
|
|
|
desired_extensions_supported.end ());
|
2020-02-11 01:01:58 +00:00
|
|
|
return out_device;
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_surface (VkSurfaceKHR surface) {
|
2020-02-11 01:01:58 +00:00
|
|
|
system_info.surface = surface;
|
|
|
|
system_info.headless = false;
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 23:56:50 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::prefer_gpu_device_type (PreferredDeviceType type) {
|
|
|
|
criteria.preferred_type = type;
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 23:56:50 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::allow_fallback_gpu (bool fallback) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.allow_fallback = fallback;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::require_present (bool require) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.require_present = require;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::require_dedicated_transfer_queue () {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.require_dedicated_transfer_queue = true;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::require_dedicated_compute_queue () {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.require_dedicated_compute_queue = true;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::required_device_memory_size (VkDeviceSize size) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.required_mem_size = size;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::desired_device_memory_size (VkDeviceSize size) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.desired_mem_size = size;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-12 00:51:03 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::add_required_extension (const char* extension) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.required_extensions.push_back (extension);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-12 00:51:03 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::add_required_extensions (std::vector<const char*> extensions) {
|
2020-02-06 23:56:50 +00:00
|
|
|
criteria.required_extensions.insert (
|
|
|
|
criteria.required_extensions.end (), extensions.begin (), extensions.end ());
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-12 00:51:03 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::add_desired_extension (const char* extension) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.desired_extensions.push_back (extension);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-12 00:51:03 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::add_desired_extensions (std::vector<const char*> extensions) {
|
2020-02-06 23:56:50 +00:00
|
|
|
criteria.desired_extensions.insert (
|
|
|
|
criteria.desired_extensions.end (), extensions.begin (), extensions.end ());
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_minimum_version (uint32_t major, uint32_t minor) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.required_version = VK_MAKE_VERSION (major, minor, 0);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_desired_version (uint32_t major, uint32_t minor) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.desired_version = VK_MAKE_VERSION (major, minor, 0);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features (VkPhysicalDeviceFeatures features) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.required_features = features;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 23:56:50 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::select_first_device_unconditionally (bool unconditionally) {
|
|
|
|
criteria.use_first_gpu_unconditionally = unconditionally;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-01-30 08:15:10 +00:00
|
|
|
|
|
|
|
// ---- Device ---- //
|
|
|
|
|
2020-02-06 21:20:39 +00:00
|
|
|
void destroy_device (Device device) { vkDestroyDevice (device.device, nullptr); }
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
DeviceBuilder::DeviceBuilder (PhysicalDevice phys_device) {
|
2020-02-03 23:23:47 +00:00
|
|
|
info.physical_device = phys_device;
|
|
|
|
info.extensions = phys_device.extensions_to_enable;
|
2020-02-11 01:01:58 +00:00
|
|
|
info.queue_families = phys_device.queue_families;
|
2020-02-03 23:23:47 +00:00
|
|
|
}
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<Device, detail::Error<DeviceError>> DeviceBuilder::build () {
|
2020-02-08 00:34:05 +00:00
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
std::vector<CustomQueueDescription> queue_descriptions;
|
|
|
|
queue_descriptions.insert (
|
|
|
|
queue_descriptions.end (), info.queue_descriptions.begin (), info.queue_descriptions.end ());
|
|
|
|
|
|
|
|
if (queue_descriptions.size () == 0) {
|
|
|
|
int graphics = get_graphics_queue_index (info.queue_families);
|
|
|
|
if (graphics >= 0) {
|
2020-02-17 20:29:22 +00:00
|
|
|
queue_descriptions.push_back ({ static_cast<uint32_t> (graphics), 1, std::vector<float>{ 1.0f } });
|
2020-02-11 01:01:58 +00:00
|
|
|
}
|
|
|
|
if (info.request_compute_queue) {
|
|
|
|
int compute = get_distinct_compute_queue_index (info.queue_families);
|
|
|
|
if (compute >= 0) {
|
2020-02-17 20:29:22 +00:00
|
|
|
queue_descriptions.push_back (
|
|
|
|
{ static_cast<uint32_t> (compute), 1, std::vector<float>{ 1.0f } });
|
2020-02-11 01:01:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (info.request_transfer_queue) {
|
|
|
|
int transfer = get_distinct_transfer_queue_index (info.queue_families);
|
|
|
|
if (transfer >= 0) {
|
2020-02-17 20:29:22 +00:00
|
|
|
queue_descriptions.push_back (
|
|
|
|
{ static_cast<uint32_t> (transfer), 1, std::vector<float>{ 1.0f } });
|
2020-02-11 01:01:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-30 08:15:10 +00:00
|
|
|
|
|
|
|
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
2020-02-11 01:01:58 +00:00
|
|
|
for (auto& desc : queue_descriptions) {
|
2020-01-30 08:15:10 +00:00
|
|
|
VkDeviceQueueCreateInfo queue_create_info = {};
|
|
|
|
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
2020-02-11 01:01:58 +00:00
|
|
|
queue_create_info.queueFamilyIndex = desc.index;
|
|
|
|
queue_create_info.queueCount = desc.count;
|
|
|
|
queue_create_info.pQueuePriorities = desc.priorities.data ();
|
2020-01-30 08:15:10 +00:00
|
|
|
queueCreateInfos.push_back (queue_create_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<const char*> extensions;
|
|
|
|
for (auto& ext : info.extensions)
|
2020-02-12 00:51:03 +00:00
|
|
|
extensions.push_back (ext);
|
2020-02-03 23:23:47 +00:00
|
|
|
if (info.physical_device.surface != VK_NULL_HANDLE)
|
|
|
|
extensions.push_back ({ VK_KHR_SWAPCHAIN_EXTENSION_NAME });
|
2020-01-30 08:15:10 +00:00
|
|
|
|
|
|
|
VkDeviceCreateInfo device_create_info = {};
|
|
|
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
2020-01-31 22:23:22 +00:00
|
|
|
detail::setup_pNext_chain (device_create_info, info.pNext_chain);
|
2020-01-30 08:15:10 +00:00
|
|
|
device_create_info.flags = info.flags;
|
|
|
|
device_create_info.queueCreateInfoCount = static_cast<uint32_t> (queueCreateInfos.size ());
|
|
|
|
device_create_info.pQueueCreateInfos = queueCreateInfos.data ();
|
|
|
|
device_create_info.enabledExtensionCount = static_cast<uint32_t> (extensions.size ());
|
|
|
|
device_create_info.ppEnabledExtensionNames = extensions.data ();
|
2020-02-06 22:46:14 +00:00
|
|
|
device_create_info.pEnabledFeatures = &info.physical_device.features;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
|
|
|
Device device;
|
|
|
|
VkResult res =
|
|
|
|
vkCreateDevice (info.physical_device.phys_device, &device_create_info, nullptr, &device.device);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<DeviceError>{ DeviceError::failed_create_device, res };
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
2020-02-03 23:23:47 +00:00
|
|
|
device.physical_device = info.physical_device;
|
|
|
|
device.surface = info.physical_device.surface;
|
2020-02-11 01:01:58 +00:00
|
|
|
device.queue_families = info.queue_families;
|
2020-01-30 08:15:10 +00:00
|
|
|
return device;
|
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
template <typename T> DeviceBuilder& DeviceBuilder::add_pNext (T* structure) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.pNext_chain.push_back (reinterpret_cast<VkBaseOutStructure*> (structure));
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 23:56:50 +00:00
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
DeviceBuilder& DeviceBuilder::request_dedicated_compute_queue (bool compute) {
|
|
|
|
info.request_compute_queue = compute;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
DeviceBuilder& DeviceBuilder::request_dedicated_transfer_queue (bool transfer) {
|
|
|
|
info.request_transfer_queue = transfer;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
DeviceBuilder& DeviceBuilder::custom_queue_setup (std::vector<CustomQueueDescription> queue_descriptions) {
|
|
|
|
info.queue_descriptions = queue_descriptions;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-17 20:13:09 +00:00
|
|
|
// ---- Queues ---- //
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_present_queue_index (Device const& device) {
|
|
|
|
int present = get_present_queue_index (
|
|
|
|
device.physical_device.phys_device, device.surface, device.queue_families);
|
|
|
|
if (present < 0) return detail::Error<QueueError>{ QueueError::present_unavailable };
|
|
|
|
return static_cast<uint32_t> (present);
|
|
|
|
}
|
|
|
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_graphics_queue_index (Device const& device) {
|
|
|
|
int graphics = get_graphics_queue_index (device.queue_families);
|
|
|
|
if (graphics < 0) return detail::Error<QueueError>{ QueueError::invalid_queue_family_index };
|
|
|
|
return static_cast<uint32_t> (graphics);
|
|
|
|
}
|
|
|
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_compute_queue_index (Device const& device) {
|
|
|
|
int compute = get_distinct_compute_queue_index (device.queue_families);
|
|
|
|
if (compute < 0) return detail::Error<QueueError>{ QueueError::compute_unavailable };
|
|
|
|
return static_cast<uint32_t> (compute);
|
|
|
|
}
|
|
|
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_transfer_queue_index (Device const& device) {
|
|
|
|
int transfer = get_distinct_transfer_queue_index (device.queue_families);
|
|
|
|
if (transfer < 0) return detail::Error<QueueError>{ QueueError::transfer_unavailable };
|
|
|
|
return static_cast<uint32_t> (transfer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-08 00:34:05 +00:00
|
|
|
VkQueue get_queue (VkDevice device, int32_t family) {
|
|
|
|
VkQueue out_queue;
|
|
|
|
vkGetDeviceQueue (device, family, 0, &out_queue);
|
|
|
|
return out_queue;
|
2020-02-03 23:23:47 +00:00
|
|
|
}
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_present_queue (Device const& device) {
|
|
|
|
int present = get_present_queue_index (
|
|
|
|
device.physical_device.phys_device, device.surface, device.queue_families);
|
2020-02-17 20:13:09 +00:00
|
|
|
if (present < 0) {
|
|
|
|
return detail::Error<QueueError>{ QueueError::present_unavailable };
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
2020-02-17 20:13:09 +00:00
|
|
|
return get_queue (device.device, present);
|
2020-02-03 23:23:47 +00:00
|
|
|
}
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_graphics_queue (Device const& device) {
|
|
|
|
int graphics = get_graphics_queue_index (device.queue_families);
|
2020-02-17 20:13:09 +00:00
|
|
|
if (graphics < 0) {
|
|
|
|
return detail::Error<QueueError>{ QueueError::invalid_queue_family_index };
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
2020-02-17 20:13:09 +00:00
|
|
|
return get_queue (device.device, graphics);
|
2020-02-03 23:23:47 +00:00
|
|
|
}
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_compute_queue (Device const& device) {
|
|
|
|
int compute = get_distinct_compute_queue_index (device.queue_families);
|
2020-02-17 20:13:09 +00:00
|
|
|
if (compute < 0) {
|
|
|
|
return detail::Error<QueueError>{ QueueError::compute_unavailable };
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
2020-02-17 20:13:09 +00:00
|
|
|
return get_queue (device.device, compute);
|
2020-02-03 23:23:47 +00:00
|
|
|
}
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_transfer_queue (Device const& device) {
|
|
|
|
int transfer = get_distinct_transfer_queue_index (device.queue_families);
|
2020-02-17 20:13:09 +00:00
|
|
|
if (transfer < 0) {
|
|
|
|
return detail::Error<QueueError>{ QueueError::transfer_unavailable };
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
2020-02-17 20:13:09 +00:00
|
|
|
return get_queue (device.device, transfer);
|
2020-02-03 23:23:47 +00:00
|
|
|
}
|
|
|
|
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
namespace detail {
|
2020-02-03 23:23:47 +00:00
|
|
|
VkSurfaceFormatKHR find_surface_format (std::vector<VkSurfaceFormatKHR> const& available_formats,
|
2020-02-06 22:46:14 +00:00
|
|
|
std::vector<VkSurfaceFormatKHR> const& desired_formats) {
|
|
|
|
for (auto const& desired_format : desired_formats) {
|
|
|
|
for (auto const& available_format : available_formats) {
|
2020-02-03 23:23:47 +00:00
|
|
|
// finds the first format that is desired and available
|
|
|
|
if (desired_format.format == available_format.format &&
|
2020-02-06 22:46:14 +00:00
|
|
|
desired_format.colorSpace == available_format.colorSpace) {
|
2020-02-03 23:23:47 +00:00
|
|
|
return desired_format;
|
|
|
|
}
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-03 23:23:47 +00:00
|
|
|
// use the first available one if any desired formats aren't found
|
|
|
|
return available_formats[0];
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
2020-02-03 23:23:47 +00:00
|
|
|
VkPresentModeKHR find_present_mode (std::vector<VkPresentModeKHR> const& available_resent_modes,
|
2020-02-06 22:46:14 +00:00
|
|
|
std::vector<VkPresentModeKHR> const& desired_present_modes) {
|
|
|
|
for (auto const& desired_pm : desired_present_modes) {
|
|
|
|
for (auto const& available_pm : available_resent_modes) {
|
2020-02-03 23:23:47 +00:00
|
|
|
// finds the first present mode that is desired and available
|
|
|
|
if (desired_pm == available_pm) return desired_pm;
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-03 23:23:47 +00:00
|
|
|
// only present mode required, use as a fallback
|
2020-01-31 22:23:22 +00:00
|
|
|
return VK_PRESENT_MODE_FIFO_KHR;
|
|
|
|
}
|
|
|
|
|
2020-02-17 20:17:09 +00:00
|
|
|
template <typename T> T minimum (T a, T b) { return a < b ? a : b; }
|
|
|
|
template <typename T> T maximum (T a, T b) { return a > b ? a : b; }
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
VkExtent2D find_extent (
|
|
|
|
VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height) {
|
|
|
|
if (capabilities.currentExtent.width != UINT32_MAX) {
|
2020-01-31 22:23:22 +00:00
|
|
|
return capabilities.currentExtent;
|
2020-02-06 22:46:14 +00:00
|
|
|
} else {
|
2020-01-31 22:23:22 +00:00
|
|
|
const int WIDTH = 800;
|
|
|
|
const int HEIGHT = 600;
|
|
|
|
VkExtent2D actualExtent = { WIDTH, HEIGHT };
|
|
|
|
|
2020-02-17 20:17:09 +00:00
|
|
|
actualExtent.width = maximum (capabilities.minImageExtent.width,
|
|
|
|
minimum (capabilities.maxImageExtent.width, actualExtent.width));
|
|
|
|
actualExtent.height = maximum (capabilities.minImageExtent.height,
|
|
|
|
minimum (capabilities.maxImageExtent.height, actualExtent.height));
|
2020-01-31 22:23:22 +00:00
|
|
|
|
|
|
|
return actualExtent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
SwapchainBuilder::SwapchainBuilder (Device const& device) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.device = device.device;
|
2020-02-06 21:20:39 +00:00
|
|
|
info.physical_device = device.physical_device.phys_device;
|
2020-01-31 22:23:22 +00:00
|
|
|
info.surface = device.surface;
|
2020-02-10 18:29:09 +00:00
|
|
|
int present = get_present_queue_index (
|
|
|
|
device.physical_device.phys_device, device.surface, device.queue_families);
|
|
|
|
int graphics = get_graphics_queue_index (device.queue_families);
|
|
|
|
|
|
|
|
info.graphics_queue_index = graphics;
|
|
|
|
info.present_queue_index = present;
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
SwapchainBuilder::SwapchainBuilder (VkPhysicalDevice const physical_device,
|
|
|
|
VkDevice const device,
|
|
|
|
VkSurfaceKHR const surface,
|
|
|
|
uint32_t graphics_queue_index,
|
|
|
|
uint32_t present_queue_index) {
|
2020-02-06 21:20:39 +00:00
|
|
|
info.physical_device = physical_device;
|
|
|
|
info.device = device;
|
|
|
|
info.surface = surface;
|
2020-02-10 18:29:09 +00:00
|
|
|
info.graphics_queue_index = graphics_queue_index;
|
|
|
|
info.present_queue_index = present_queue_index;
|
2020-02-06 21:20:39 +00:00
|
|
|
}
|
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::build () {
|
2020-02-04 03:34:46 +00:00
|
|
|
if (info.desired_formats.size () == 0) use_default_format_selection ();
|
|
|
|
if (info.desired_present_modes.size () == 0) use_default_present_mode_selection ();
|
|
|
|
|
2020-02-06 21:20:39 +00:00
|
|
|
auto surface_support = detail::query_surface_support_details (info.physical_device, info.surface);
|
2020-02-10 18:29:09 +00:00
|
|
|
if (!surface_support.has_value ())
|
|
|
|
return detail::Error<SwapchainError>{ SwapchainError::failed_query_surface_support_details,
|
|
|
|
surface_support.error ().vk_result };
|
2020-02-03 23:23:47 +00:00
|
|
|
VkSurfaceFormatKHR surface_format =
|
|
|
|
detail::find_surface_format (surface_support.value ().formats, info.desired_formats);
|
|
|
|
VkPresentModeKHR present_mode =
|
|
|
|
detail::find_present_mode (surface_support.value ().present_modes, info.desired_present_modes);
|
|
|
|
VkExtent2D extent = detail::find_extent (
|
2020-01-31 22:23:22 +00:00
|
|
|
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 &&
|
2020-02-06 22:46:14 +00:00
|
|
|
imageCount > surface_support.value ().capabilities.maxImageCount) {
|
2020-01-31 22:23:22 +00:00
|
|
|
imageCount = surface_support.value ().capabilities.maxImageCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkSwapchainCreateInfoKHR swapchain_create_info = {};
|
|
|
|
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
2020-02-06 22:46:14 +00:00
|
|
|
detail::setup_pNext_chain (swapchain_create_info, info.pNext_elements);
|
2020-01-31 22:23:22 +00:00
|
|
|
swapchain_create_info.surface = info.surface;
|
|
|
|
swapchain_create_info.minImageCount = imageCount;
|
2020-02-03 23:23:47 +00:00
|
|
|
swapchain_create_info.imageFormat = surface_format.format;
|
|
|
|
swapchain_create_info.imageColorSpace = surface_format.colorSpace;
|
2020-01-31 22:23:22 +00:00
|
|
|
swapchain_create_info.imageExtent = extent;
|
|
|
|
swapchain_create_info.imageArrayLayers = 1;
|
|
|
|
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
uint32_t queue_family_indices[] = { info.graphics_queue_index, info.present_queue_index };
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
if (info.graphics_queue_index != info.present_queue_index) {
|
2020-01-31 22:23:22 +00:00
|
|
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
|
|
swapchain_create_info.queueFamilyIndexCount = 2;
|
2020-02-06 22:46:14 +00:00
|
|
|
swapchain_create_info.pQueueFamilyIndices = queue_family_indices;
|
|
|
|
} else {
|
2020-01-31 22:23:22 +00:00
|
|
|
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;
|
2020-02-03 23:23:47 +00:00
|
|
|
swapchain_create_info.presentMode = present_mode;
|
2020-01-31 22:23:22 +00:00
|
|
|
swapchain_create_info.clipped = VK_TRUE;
|
|
|
|
swapchain_create_info.oldSwapchain = info.old_swapchain;
|
2020-02-06 22:46:14 +00:00
|
|
|
Swapchain swapchain{};
|
2020-01-31 22:23:22 +00:00
|
|
|
VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<SwapchainError>{ SwapchainError::failed_create_swapchain, res };
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
2020-02-04 03:34:46 +00:00
|
|
|
swapchain.device = info.device;
|
2020-02-03 23:23:47 +00:00
|
|
|
swapchain.image_format = surface_format.format;
|
2020-01-31 22:23:22 +00:00
|
|
|
swapchain.extent = extent;
|
|
|
|
|
2020-02-04 03:34:46 +00:00
|
|
|
auto images = get_swapchain_images (swapchain);
|
|
|
|
swapchain.image_count = images.value ().size ();
|
2020-01-31 22:23:22 +00:00
|
|
|
return swapchain;
|
2020-02-10 18:29:09 +00:00
|
|
|
} // namespace vkb
|
|
|
|
detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::recreate (Swapchain const& swapchain) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.old_swapchain = swapchain.swapchain;
|
|
|
|
return build ();
|
|
|
|
}
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<std::vector<VkImage>, detail::Error<SwapchainError>> get_swapchain_images (
|
|
|
|
Swapchain const& swapchain) {
|
2020-02-04 03:34:46 +00:00
|
|
|
auto swapchain_images =
|
|
|
|
detail::get_vector<VkImage> (vkGetSwapchainImagesKHR, swapchain.device, swapchain.swapchain);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (!swapchain_images) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<SwapchainError>{ SwapchainError::failed_get_swapchain_images,
|
|
|
|
swapchain_images.error () };
|
2020-02-04 03:34:46 +00:00
|
|
|
}
|
|
|
|
return swapchain_images.value ();
|
|
|
|
}
|
|
|
|
|
2020-02-10 18:29:09 +00:00
|
|
|
detail::Expected<std::vector<VkImageView>, detail::Error<SwapchainError>>
|
|
|
|
get_swapchain_image_views (Swapchain const& swapchain, std::vector<VkImage> const& images) {
|
2020-02-06 22:46:14 +00:00
|
|
|
std::vector<VkImageView> views{ swapchain.image_count };
|
2020-02-04 03:34:46 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
for (size_t i = 0; i < swapchain.image_count; i++) {
|
2020-02-04 03:34:46 +00:00
|
|
|
VkImageViewCreateInfo createInfo = {};
|
|
|
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
|
|
createInfo.image = images[i];
|
|
|
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
createInfo.format = swapchain.image_format;
|
|
|
|
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
createInfo.subresourceRange.baseMipLevel = 0;
|
|
|
|
createInfo.subresourceRange.levelCount = 1;
|
|
|
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
|
|
|
createInfo.subresourceRange.layerCount = 1;
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
VkResult res = vkCreateImageView (swapchain.device, &createInfo, nullptr, &views[i]);
|
|
|
|
if (res != VK_SUCCESS)
|
2020-02-10 18:29:09 +00:00
|
|
|
return detail::Error<SwapchainError>{ SwapchainError::failed_create_swapchain_image_views, res };
|
2020-02-04 03:34:46 +00:00
|
|
|
}
|
|
|
|
return views;
|
|
|
|
}
|
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
void destroy_swapchain (Swapchain const& swapchain) {
|
2020-02-04 03:34:46 +00:00
|
|
|
if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE)
|
2020-02-06 21:20:39 +00:00
|
|
|
vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, nullptr);
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_desired_format (VkSurfaceFormatKHR format) {
|
2020-02-03 23:23:47 +00:00
|
|
|
info.desired_formats.insert (info.desired_formats.begin (), format);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::add_fallback_format (VkSurfaceFormatKHR format) {
|
2020-02-03 23:23:47 +00:00
|
|
|
info.desired_formats.push_back (format);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::use_default_format_selection () {
|
2020-02-03 23:23:47 +00:00
|
|
|
info.desired_formats.push_back ({ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR });
|
|
|
|
info.desired_formats.push_back ({ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR });
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_desired_present_mode (VkPresentModeKHR present_mode) {
|
2020-02-03 23:23:47 +00:00
|
|
|
info.desired_present_modes.insert (info.desired_present_modes.begin (), present_mode);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::add_fallback_present_mode (VkPresentModeKHR present_mode) {
|
2020-02-03 23:23:47 +00:00
|
|
|
info.desired_present_modes.push_back (present_mode);
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::use_default_present_mode_selection () {
|
2020-02-03 23:23:47 +00:00
|
|
|
info.desired_present_modes.push_back (VK_PRESENT_MODE_MAILBOX_KHR);
|
|
|
|
info.desired_present_modes.push_back (VK_PRESENT_MODE_FIFO_KHR);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
} // namespace vkb
|