2020-06-10 19:39:14 +00:00
|
|
|
/*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
|
|
* documentation files (the “Software”), to deal in the Software without restriction, including without
|
|
|
|
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
|
|
* of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
|
|
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*
|
|
|
|
* Copyright © 2020 Charles Giessen (charles@lunarg.com)
|
|
|
|
*/
|
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
#include "VkBootstrap.h"
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-06-17 23:13:39 +00:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <fcntl.h>
|
2021-02-18 17:31:23 +00:00
|
|
|
#ifndef NOMINMAX
|
2020-06-17 23:13:39 +00:00
|
|
|
#define NOMINMAX
|
2021-02-18 17:31:23 +00:00
|
|
|
#endif
|
2020-06-17 23:13:39 +00:00
|
|
|
#include <windows.h>
|
|
|
|
#endif // _WIN32
|
|
|
|
|
|
|
|
#if defined(__linux__) || defined(__APPLE__)
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <mutex>
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
namespace vkb {
|
|
|
|
|
|
|
|
namespace detail {
|
2020-03-08 04:57:49 +00:00
|
|
|
|
2020-06-17 23:13:39 +00:00
|
|
|
class VulkanFunctions {
|
|
|
|
private:
|
|
|
|
std::mutex init_mutex;
|
|
|
|
struct VulkanLibrary {
|
|
|
|
#if defined(__linux__) || defined(__APPLE__)
|
|
|
|
void* library;
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
HMODULE library;
|
|
|
|
#endif
|
|
|
|
PFN_vkGetInstanceProcAddr ptr_vkGetInstanceProcAddr = VK_NULL_HANDLE;
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
VulkanLibrary() {
|
2020-06-17 23:13:39 +00:00
|
|
|
#if defined(__linux__)
|
2021-02-18 18:43:20 +00:00
|
|
|
library = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL);
|
|
|
|
if (!library) library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
2020-06-17 23:13:39 +00:00
|
|
|
#elif defined(__APPLE__)
|
2021-02-18 18:43:20 +00:00
|
|
|
library = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL);
|
|
|
|
if (!library) library = dlopen("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL);
|
2020-06-17 23:13:39 +00:00
|
|
|
#elif defined(_WIN32)
|
2021-02-18 18:43:20 +00:00
|
|
|
library = LoadLibrary(TEXT("vulkan-1.dll"));
|
2020-06-17 23:13:39 +00:00
|
|
|
#else
|
2021-02-18 18:43:20 +00:00
|
|
|
assert(false && "Unsupported platform");
|
2020-06-17 23:13:39 +00:00
|
|
|
#endif
|
|
|
|
if (!library) return;
|
2021-02-18 18:43:20 +00:00
|
|
|
load_func(ptr_vkGetInstanceProcAddr, "vkGetInstanceProcAddr");
|
2020-06-17 23:13:39 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
template <typename T> void load_func(T& func_dest, const char* func_name) {
|
2020-06-17 23:13:39 +00:00
|
|
|
#if defined(__linux__) || defined(__APPLE__)
|
2021-02-18 18:43:20 +00:00
|
|
|
func_dest = reinterpret_cast<T>(dlsym(library, func_name));
|
2020-06-17 23:13:39 +00:00
|
|
|
#elif defined(_WIN32)
|
2021-02-18 18:43:20 +00:00
|
|
|
func_dest = reinterpret_cast<T>(GetProcAddress(library, func_name));
|
2020-06-17 23:13:39 +00:00
|
|
|
#endif
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
void close() {
|
2020-06-17 23:13:39 +00:00
|
|
|
#if defined(__linux__) || defined(__APPLE__)
|
2021-02-18 18:43:20 +00:00
|
|
|
dlclose(library);
|
2020-06-17 23:13:39 +00:00
|
|
|
#elif defined(_WIN32)
|
2021-02-18 18:43:20 +00:00
|
|
|
FreeLibrary(library);
|
2020-06-17 23:13:39 +00:00
|
|
|
#endif
|
|
|
|
library = 0;
|
|
|
|
}
|
|
|
|
};
|
2021-02-18 18:43:20 +00:00
|
|
|
VulkanLibrary& get_vulkan_library() {
|
2020-06-17 23:13:39 +00:00
|
|
|
static VulkanLibrary lib;
|
|
|
|
return lib;
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
bool load_vulkan(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr) {
|
2020-06-17 23:13:39 +00:00
|
|
|
if (fp_vkGetInstanceProcAddr != nullptr) {
|
|
|
|
ptr_vkGetInstanceProcAddr = fp_vkGetInstanceProcAddr;
|
|
|
|
return true;
|
|
|
|
} else {
|
2021-02-18 18:43:20 +00:00
|
|
|
auto& lib = get_vulkan_library();
|
2020-06-17 23:13:39 +00:00
|
|
|
ptr_vkGetInstanceProcAddr = lib.ptr_vkGetInstanceProcAddr;
|
|
|
|
return lib.library != nullptr && lib.ptr_vkGetInstanceProcAddr != VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
template <typename T> void get_proc_addr(T& out_ptr, const char* func_name) {
|
|
|
|
out_ptr = reinterpret_cast<T>(ptr_vkGetInstanceProcAddr(instance, func_name));
|
2020-06-17 23:13:39 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
void init_pre_instance_funcs() {
|
|
|
|
get_proc_addr(fp_vkEnumerateInstanceExtensionProperties, "vkEnumerateInstanceExtensionProperties");
|
|
|
|
get_proc_addr(fp_vkEnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties");
|
|
|
|
get_proc_addr(fp_vkEnumerateInstanceVersion, "vkEnumerateInstanceVersion");
|
|
|
|
get_proc_addr(fp_vkCreateInstance, "vkCreateInstance");
|
2020-06-17 23:13:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
PFN_vkGetInstanceProcAddr ptr_vkGetInstanceProcAddr = nullptr;
|
|
|
|
VkInstance instance = nullptr;
|
|
|
|
|
|
|
|
PFN_vkEnumerateInstanceExtensionProperties fp_vkEnumerateInstanceExtensionProperties = nullptr;
|
|
|
|
PFN_vkEnumerateInstanceLayerProperties fp_vkEnumerateInstanceLayerProperties = nullptr;
|
|
|
|
PFN_vkEnumerateInstanceVersion fp_vkEnumerateInstanceVersion = nullptr;
|
|
|
|
PFN_vkCreateInstance fp_vkCreateInstance = nullptr;
|
|
|
|
PFN_vkDestroyInstance fp_vkDestroyInstance = nullptr;
|
|
|
|
|
|
|
|
PFN_vkEnumeratePhysicalDevices fp_vkEnumeratePhysicalDevices = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceFeatures fp_vkGetPhysicalDeviceFeatures = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceFeatures2 fp_vkGetPhysicalDeviceFeatures2 = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceFormatProperties fp_vkGetPhysicalDeviceFormatProperties = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceImageFormatProperties fp_vkGetPhysicalDeviceImageFormatProperties = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceProperties fp_vkGetPhysicalDeviceProperties = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceProperties2 fp_vkGetPhysicalDeviceProperties2 = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties fp_vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties2 fp_vkGetPhysicalDeviceQueueFamilyProperties2 = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceMemoryProperties fp_vkGetPhysicalDeviceMemoryProperties = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceFormatProperties2 fp_vkGetPhysicalDeviceFormatProperties2 = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceMemoryProperties2 fp_vkGetPhysicalDeviceMemoryProperties2 = nullptr;
|
|
|
|
|
|
|
|
PFN_vkCreateDevice fp_vkCreateDevice = nullptr;
|
|
|
|
PFN_vkDestroyDevice fp_vkDestroyDevice = nullptr;
|
|
|
|
PFN_vkEnumerateDeviceExtensionProperties fp_vkEnumerateDeviceExtensionProperties = nullptr;
|
|
|
|
PFN_vkGetDeviceQueue fp_vkGetDeviceQueue = nullptr;
|
|
|
|
|
|
|
|
PFN_vkCreateImageView fp_vkCreateImageView = nullptr;
|
|
|
|
PFN_vkDestroyImageView fp_vkDestroyImageView = nullptr;
|
|
|
|
|
|
|
|
PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fp_vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fp_vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fp_vkGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
|
|
|
|
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fp_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
|
|
|
|
PFN_vkCreateSwapchainKHR fp_vkCreateSwapchainKHR = nullptr;
|
|
|
|
PFN_vkDestroySwapchainKHR fp_vkDestroySwapchainKHR = nullptr;
|
|
|
|
PFN_vkGetSwapchainImagesKHR fp_vkGetSwapchainImagesKHR = nullptr;
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
bool init_vulkan_funcs(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr) {
|
|
|
|
std::lock_guard<std::mutex> lg(init_mutex);
|
|
|
|
if (!load_vulkan(fp_vkGetInstanceProcAddr)) return false;
|
|
|
|
init_pre_instance_funcs();
|
2020-06-17 23:13:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
template <typename T> void get_inst_proc_addr(T& out_ptr, const char* func_name) {
|
|
|
|
std::lock_guard<std::mutex> lg(init_mutex);
|
|
|
|
get_proc_addr(out_ptr, func_name);
|
2020-06-17 23:13:39 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
void init_instance_funcs(VkInstance inst) {
|
|
|
|
std::lock_guard<std::mutex> lg(init_mutex);
|
2020-06-17 23:13:39 +00:00
|
|
|
|
|
|
|
instance = inst;
|
2021-02-18 18:43:20 +00:00
|
|
|
get_proc_addr(fp_vkDestroyInstance, "vkDestroyInstance");
|
|
|
|
get_proc_addr(fp_vkEnumeratePhysicalDevices, "vkEnumeratePhysicalDevices");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceFeatures, "vkGetPhysicalDeviceFeatures");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceFeatures2, "vkGetPhysicalDeviceFeatures2");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceFormatProperties, "vkGetPhysicalDeviceFormatProperties");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceImageFormatProperties, "vkGetPhysicalDeviceImageFormatProperties");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceProperties2, "vkGetPhysicalDeviceProperties2");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceQueueFamilyProperties, "vkGetPhysicalDeviceQueueFamilyProperties");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceQueueFamilyProperties2, "vkGetPhysicalDeviceQueueFamilyProperties2");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceFormatProperties2, "vkGetPhysicalDeviceFormatProperties2");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2");
|
|
|
|
|
|
|
|
get_proc_addr(fp_vkCreateDevice, "vkCreateDevice");
|
|
|
|
get_proc_addr(fp_vkDestroyDevice, "vkDestroyDevice");
|
|
|
|
get_proc_addr(fp_vkEnumerateDeviceExtensionProperties, "vkEnumerateDeviceExtensionProperties");
|
|
|
|
get_proc_addr(fp_vkGetDeviceQueue, "vkGetDeviceQueue");
|
|
|
|
|
|
|
|
get_proc_addr(fp_vkCreateImageView, "vkCreateImageView");
|
|
|
|
get_proc_addr(fp_vkDestroyImageView, "vkDestroyImageView");
|
|
|
|
|
|
|
|
get_proc_addr(fp_vkDestroySurfaceKHR, "vkDestroySurfaceKHR");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceSurfaceSupportKHR, "vkGetPhysicalDeviceSurfaceSupportKHR");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceSurfaceFormatsKHR, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceSurfacePresentModesKHR, "vkGetPhysicalDeviceSurfacePresentModesKHR");
|
|
|
|
get_proc_addr(fp_vkGetPhysicalDeviceSurfaceCapabilitiesKHR, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
|
|
|
|
get_proc_addr(fp_vkCreateSwapchainKHR, "vkCreateSwapchainKHR");
|
|
|
|
get_proc_addr(fp_vkDestroySwapchainKHR, "vkDestroySwapchainKHR");
|
|
|
|
get_proc_addr(fp_vkGetSwapchainImagesKHR, "vkGetSwapchainImagesKHR");
|
2020-06-17 23:13:39 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
VulkanFunctions& vulkan_functions() {
|
2020-09-26 18:15:40 +00:00
|
|
|
static VulkanFunctions v;
|
|
|
|
return v;
|
|
|
|
}
|
2020-03-08 04:57:49 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
// Helper for robustly executing the two-call pattern
|
|
|
|
template <typename T, typename F, typename... Ts>
|
2021-02-18 18:43:20 +00:00
|
|
|
auto get_vector(std::vector<T>& out, F&& f, Ts&&... ts) -> VkResult {
|
2020-02-06 22:46:14 +00:00
|
|
|
uint32_t count = 0;
|
|
|
|
VkResult err;
|
|
|
|
do {
|
2021-02-18 18:43:20 +00:00
|
|
|
err = f(ts..., &count, nullptr);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (err) {
|
2020-02-10 18:29:09 +00:00
|
|
|
return err;
|
2020-02-06 22:46:14 +00:00
|
|
|
};
|
2021-02-18 18:43:20 +00:00
|
|
|
out.resize(count);
|
|
|
|
err = f(ts..., &count, out.data());
|
|
|
|
out.resize(count);
|
2020-02-06 22:46:14 +00:00
|
|
|
} while (err == VK_INCOMPLETE);
|
2020-05-17 13:31:02 +00:00
|
|
|
return err;
|
2020-02-06 22:46:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename F, typename... Ts>
|
2021-02-18 18:43:20 +00:00
|
|
|
auto get_vector_noerror(F&& f, Ts&&... ts) -> std::vector<T> {
|
2020-02-06 22:46:14 +00:00
|
|
|
uint32_t count = 0;
|
|
|
|
std::vector<T> results;
|
2021-02-18 18:43:20 +00:00
|
|
|
f(ts..., &count, nullptr);
|
|
|
|
results.resize(count);
|
|
|
|
f(ts..., &count, results.data());
|
|
|
|
results.resize(count);
|
2020-02-06 22:46:14 +00:00
|
|
|
return results;
|
|
|
|
}
|
|
|
|
} // namespace detail
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* to_string_message_severity(VkDebugUtilsMessageSeverityFlagBitsEXT s) {
|
2020-02-06 22:46:14 +00:00
|
|
|
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";
|
|
|
|
}
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* to_string_message_type(VkDebugUtilsMessageTypeFlagsEXT s) {
|
2020-03-07 09:11:32 +00:00
|
|
|
if (s == 7) return "General | Validation | Performance";
|
|
|
|
if (s == 6) return "Validation | Performance";
|
|
|
|
if (s == 5) return "General | Performance";
|
|
|
|
if (s == 4 /*VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT*/) return "Performance";
|
|
|
|
if (s == 3) return "General | Validation";
|
|
|
|
if (s == 2 /*VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT*/) return "Validation";
|
|
|
|
if (s == 1 /*VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT*/) return "General";
|
|
|
|
return "Unknown";
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
VkResult create_debug_utils_messenger(VkInstance instance,
|
2020-01-31 22:23:22 +00:00
|
|
|
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback,
|
|
|
|
VkDebugUtilsMessageSeverityFlagsEXT severity,
|
|
|
|
VkDebugUtilsMessageTypeFlagsEXT type,
|
2020-03-07 22:33:17 +00:00
|
|
|
VkDebugUtilsMessengerEXT* pDebugMessenger,
|
|
|
|
VkAllocationCallbacks* allocation_callbacks) {
|
2020-03-08 04:57:49 +00:00
|
|
|
|
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;
|
|
|
|
|
2020-03-08 04:57:49 +00:00
|
|
|
PFN_vkCreateDebugUtilsMessengerEXT createMessengerFunc;
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::vulkan_functions().get_inst_proc_addr(createMessengerFunc, "vkCreateDebugUtilsMessengerEXT");
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2020-03-08 04:57:49 +00:00
|
|
|
if (createMessengerFunc != nullptr) {
|
2021-02-18 18:43:20 +00:00
|
|
|
return createMessengerFunc(instance, &messengerCreateInfo, allocation_callbacks, pDebugMessenger);
|
2020-02-06 22:46:14 +00:00
|
|
|
} else {
|
2020-01-31 22:23:22 +00:00
|
|
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
void destroy_debug_utils_messenger(
|
2020-03-07 22:33:17 +00:00
|
|
|
VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, VkAllocationCallbacks* allocation_callbacks) {
|
2020-06-17 23:13:39 +00:00
|
|
|
|
2020-03-08 04:57:49 +00:00
|
|
|
PFN_vkDestroyDebugUtilsMessengerEXT deleteMessengerFunc;
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::vulkan_functions().get_inst_proc_addr(deleteMessengerFunc, "vkDestroyDebugUtilsMessengerEXT");
|
2020-06-17 23:13:39 +00:00
|
|
|
|
2020-03-08 04:57:49 +00:00
|
|
|
if (deleteMessengerFunc != nullptr) {
|
2021-02-18 18:43:20 +00:00
|
|
|
deleteMessengerFunc(instance, debugMessenger, allocation_callbacks);
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
2020-01-31 22:23:22 +00:00
|
|
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
|
|
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
2020-03-15 01:57:40 +00:00
|
|
|
void*) {
|
2021-02-18 18:43:20 +00:00
|
|
|
auto ms = to_string_message_severity(messageSeverity);
|
|
|
|
auto mt = to_string_message_type(messageType);
|
|
|
|
printf("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage);
|
2020-03-08 05:58:23 +00:00
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
return VK_FALSE;
|
|
|
|
}
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
namespace detail {
|
2021-02-18 18:43:20 +00:00
|
|
|
bool check_layer_supported(std::vector<VkLayerProperties> const& available_layers, const char* layer_name) {
|
2020-02-18 22:18:08 +00:00
|
|
|
if (!layer_name) return false;
|
|
|
|
for (const auto& layer_properties : available_layers) {
|
2021-02-18 18:43:20 +00:00
|
|
|
if (strcmp(layer_name, layer_properties.layerName) == 0) {
|
2020-02-18 22:18:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
2020-02-18 22:18:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
bool check_layers_supported(std::vector<VkLayerProperties> const& available_layers,
|
2020-05-19 05:50:24 +00:00
|
|
|
std::vector<const char*> const& layer_names) {
|
2020-01-31 22:23:22 +00:00
|
|
|
bool all_found = true;
|
2020-02-06 22:46:14 +00:00
|
|
|
for (const auto& layer_name : layer_names) {
|
2021-02-18 18:43:20 +00:00
|
|
|
bool found = check_layer_supported(available_layers, layer_name);
|
2020-01-31 22:23:22 +00:00
|
|
|
if (!found) all_found = false;
|
|
|
|
}
|
|
|
|
return all_found;
|
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
bool check_extension_supported(
|
2020-05-19 05:50:24 +00:00
|
|
|
std::vector<VkExtensionProperties> const& available_extensions, const char* extension_name) {
|
2020-02-18 22:18:08 +00:00
|
|
|
if (!extension_name) return false;
|
2020-05-19 05:50:24 +00:00
|
|
|
for (const auto& extension_properties : available_extensions) {
|
2021-02-18 18:43:20 +00:00
|
|
|
if (strcmp(extension_name, extension_properties.extensionName) == 0) {
|
2020-02-18 22:18:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
2020-02-11 01:01:58 +00:00
|
|
|
}
|
2020-02-18 22:18:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
bool check_extensions_supported(std::vector<VkExtensionProperties> const& available_extensions,
|
2020-05-19 05:50:24 +00:00
|
|
|
std::vector<const char*> const& extension_names) {
|
2020-02-11 01:01:58 +00:00
|
|
|
bool all_found = true;
|
|
|
|
for (const auto& extension_name : extension_names) {
|
2021-02-18 18:43:20 +00:00
|
|
|
bool found = check_extension_supported(available_extensions, extension_name);
|
2020-02-11 01:01:58 +00:00
|
|
|
if (!found) all_found = false;
|
|
|
|
}
|
|
|
|
return all_found;
|
|
|
|
}
|
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
template <typename T>
|
2021-02-18 18:43:20 +00:00
|
|
|
void setup_pNext_chain(T& structure, std::vector<VkBaseOutStructure*> const& structs) {
|
2020-01-31 22:23:22 +00:00
|
|
|
structure.pNext = nullptr;
|
2021-02-18 18:43:20 +00:00
|
|
|
if (structs.size() <= 0) return;
|
|
|
|
for (size_t i = 0; i < structs.size() - 1; i++) {
|
|
|
|
structs.at(i)->pNext = structs.at(i + 1);
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
structure.pNext = structs.at(0);
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
2020-02-18 22:18:08 +00:00
|
|
|
const char* validation_layer_name = "VK_LAYER_KHRONOS_validation";
|
|
|
|
|
2020-05-17 13:31:02 +00:00
|
|
|
struct InstanceErrorCategory : std::error_category {
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* name() const noexcept override { return "vkb_instance"; }
|
|
|
|
std::string message(int err) const override {
|
|
|
|
return to_string(static_cast<InstanceError>(err));
|
2020-05-17 13:31:02 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
const InstanceErrorCategory instance_error_category;
|
|
|
|
|
|
|
|
struct PhysicalDeviceErrorCategory : std::error_category {
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* name() const noexcept override { return "vkb_physical_device"; }
|
|
|
|
std::string message(int err) const override {
|
|
|
|
return to_string(static_cast<PhysicalDeviceError>(err));
|
2020-05-17 13:31:02 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
const PhysicalDeviceErrorCategory physical_device_error_category;
|
|
|
|
|
|
|
|
struct QueueErrorCategory : std::error_category {
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* name() const noexcept override { return "vkb_queue"; }
|
|
|
|
std::string message(int err) const override { return to_string(static_cast<QueueError>(err)); }
|
2020-05-17 13:31:02 +00:00
|
|
|
};
|
|
|
|
const QueueErrorCategory queue_error_category;
|
|
|
|
|
|
|
|
struct DeviceErrorCategory : std::error_category {
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* name() const noexcept override { return "vkb_device"; }
|
|
|
|
std::string message(int err) const override { return to_string(static_cast<DeviceError>(err)); }
|
2020-05-17 13:31:02 +00:00
|
|
|
};
|
|
|
|
const DeviceErrorCategory device_error_category;
|
|
|
|
|
|
|
|
struct SwapchainErrorCategory : std::error_category {
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* name() const noexcept override { return "vbk_swapchain"; }
|
|
|
|
std::string message(int err) const override {
|
|
|
|
return to_string(static_cast<SwapchainError>(err));
|
2020-05-17 13:31:02 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
const SwapchainErrorCategory swapchain_error_category;
|
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
} // namespace detail
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
std::error_code make_error_code(InstanceError instance_error) {
|
|
|
|
return { static_cast<int>(instance_error), detail::instance_error_category };
|
2020-05-17 13:31:02 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
std::error_code make_error_code(PhysicalDeviceError physical_device_error) {
|
|
|
|
return { static_cast<int>(physical_device_error), detail::physical_device_error_category };
|
2020-05-17 13:31:02 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
std::error_code make_error_code(QueueError queue_error) {
|
|
|
|
return { static_cast<int>(queue_error), detail::queue_error_category };
|
2020-05-17 13:31:02 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
std::error_code make_error_code(DeviceError device_error) {
|
|
|
|
return { static_cast<int>(device_error), detail::device_error_category };
|
2020-05-17 13:31:02 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
std::error_code make_error_code(SwapchainError swapchain_error) {
|
|
|
|
return { static_cast<int>(swapchain_error), detail::swapchain_error_category };
|
2020-05-17 13:31:02 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* to_string(InstanceError err) {
|
2020-03-08 00:19:58 +00:00
|
|
|
switch (err) {
|
2020-03-09 21:10:11 +00:00
|
|
|
case InstanceError::vulkan_unavailable:
|
|
|
|
return "vulkan_unavailable";
|
|
|
|
case InstanceError::vulkan_version_unavailable:
|
|
|
|
return "vulkan_version_unavailable";
|
|
|
|
case InstanceError::vulkan_version_1_1_unavailable:
|
|
|
|
return "vulkan_version_1_1_unavailable";
|
|
|
|
case InstanceError::vulkan_version_1_2_unavailable:
|
|
|
|
return "vulkan_version_1_2_unavailable";
|
2020-03-08 00:19:58 +00:00
|
|
|
case InstanceError::failed_create_debug_messenger:
|
|
|
|
return "failed_create_debug_messenger";
|
|
|
|
case InstanceError::failed_create_instance:
|
|
|
|
return "failed_create_instance";
|
|
|
|
case InstanceError::requested_layers_not_present:
|
|
|
|
return "requested_layers_not_present";
|
|
|
|
case InstanceError::requested_extensions_not_present:
|
|
|
|
return "requested_extensions_not_present";
|
2020-05-26 19:33:40 +00:00
|
|
|
case InstanceError::windowing_extensions_not_present:
|
|
|
|
return "windowing_extensions_not_present";
|
2020-03-08 00:19:58 +00:00
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* to_string(PhysicalDeviceError err) {
|
2020-03-08 00:19:58 +00:00
|
|
|
switch (err) {
|
2020-03-10 03:53:10 +00:00
|
|
|
case PhysicalDeviceError::no_surface_provided:
|
|
|
|
return "no_surface_provided";
|
2020-03-08 00:19:58 +00:00
|
|
|
case PhysicalDeviceError::failed_enumerate_physical_devices:
|
|
|
|
return "failed_enumerate_physical_devices";
|
|
|
|
case PhysicalDeviceError::no_physical_devices_found:
|
|
|
|
return "no_physical_devices_found";
|
|
|
|
case PhysicalDeviceError::no_suitable_device:
|
|
|
|
return "no_suitable_device";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* to_string(QueueError err) {
|
2020-03-08 00:19:58 +00:00
|
|
|
switch (err) {
|
|
|
|
case QueueError::present_unavailable:
|
|
|
|
return "present_unavailable";
|
|
|
|
case QueueError::graphics_unavailable:
|
|
|
|
return "graphics_unavailable";
|
|
|
|
case QueueError::compute_unavailable:
|
|
|
|
return "compute_unavailable";
|
|
|
|
case QueueError::transfer_unavailable:
|
|
|
|
return "transfer_unavailable";
|
|
|
|
case QueueError::queue_index_out_of_range:
|
|
|
|
return "queue_index_out_of_range";
|
|
|
|
case QueueError::invalid_queue_family_index:
|
|
|
|
return "invalid_queue_family_index";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* to_string(DeviceError err) {
|
2020-03-08 00:19:58 +00:00
|
|
|
switch (err) {
|
|
|
|
case DeviceError::failed_create_device:
|
|
|
|
return "failed_create_device";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* to_string(SwapchainError err) {
|
2020-03-08 00:19:58 +00:00
|
|
|
switch (err) {
|
2020-04-19 23:59:32 +00:00
|
|
|
case SwapchainError::surface_handle_not_provided:
|
|
|
|
return "surface_handle_not_provided";
|
2020-03-08 00:19:58 +00:00
|
|
|
case SwapchainError::failed_query_surface_support_details:
|
|
|
|
return "failed_query_surface_support_details";
|
|
|
|
case SwapchainError::failed_create_swapchain:
|
|
|
|
return "failed_create_swapchain";
|
|
|
|
case SwapchainError::failed_get_swapchain_images:
|
|
|
|
return "failed_get_swapchain_images";
|
|
|
|
case SwapchainError::failed_create_swapchain_image_views:
|
|
|
|
return "failed_create_swapchain_image_views";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<SystemInfo> SystemInfo::get_system_info() {
|
|
|
|
if (!detail::vulkan_functions().init_vulkan_funcs(nullptr)) {
|
|
|
|
return make_error_code(InstanceError::vulkan_unavailable);
|
2020-06-17 23:13:39 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
return SystemInfo();
|
2020-06-17 23:13:39 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<SystemInfo> SystemInfo::get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr) {
|
2020-06-17 23:13:39 +00:00
|
|
|
// Using externally provided function pointers, assume the loader is available
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::vulkan_functions().init_vulkan_funcs(fp_vkGetInstanceProcAddr);
|
|
|
|
return SystemInfo();
|
2020-06-17 23:13:39 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
SystemInfo::SystemInfo() {
|
|
|
|
auto available_layers_ret = detail::get_vector<VkLayerProperties>(
|
|
|
|
this->available_layers, detail::vulkan_functions().fp_vkEnumerateInstanceLayerProperties);
|
2020-05-17 13:31:02 +00:00
|
|
|
if (available_layers_ret != VK_SUCCESS) {
|
2021-02-18 18:43:20 +00:00
|
|
|
this->available_layers.clear();
|
2020-03-07 08:44:34 +00:00
|
|
|
}
|
2020-05-17 13:31:02 +00:00
|
|
|
|
2020-03-07 08:44:34 +00:00
|
|
|
for (auto& layer : this->available_layers)
|
2021-02-18 18:43:20 +00:00
|
|
|
if (strcmp(layer.layerName, detail::validation_layer_name) == 0)
|
2020-03-07 22:08:00 +00:00
|
|
|
validation_layers_available = true;
|
2020-05-19 05:50:24 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
auto available_extensions_ret = detail::get_vector<VkExtensionProperties>(
|
|
|
|
this->available_extensions, detail::vulkan_functions().fp_vkEnumerateInstanceExtensionProperties, nullptr);
|
2020-05-19 05:50:24 +00:00
|
|
|
if (available_extensions_ret != VK_SUCCESS) {
|
2021-02-18 18:43:20 +00:00
|
|
|
this->available_extensions.clear();
|
2020-05-19 05:50:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& ext : this->available_extensions)
|
2021-02-18 18:43:20 +00:00
|
|
|
if (strcmp(ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
|
2020-05-19 05:50:24 +00:00
|
|
|
debug_utils_available = true;
|
|
|
|
|
|
|
|
for (auto& layer : this->available_layers) {
|
|
|
|
std::vector<VkExtensionProperties> layer_extensions;
|
2021-02-18 18:43:20 +00:00
|
|
|
auto layer_extensions_ret = detail::get_vector<VkExtensionProperties>(layer_extensions,
|
|
|
|
detail::vulkan_functions().fp_vkEnumerateInstanceExtensionProperties,
|
2020-09-26 18:15:40 +00:00
|
|
|
layer.layerName);
|
2020-05-19 05:50:24 +00:00
|
|
|
if (layer_extensions_ret != VK_SUCCESS) {
|
|
|
|
for (auto& ext : layer_extensions)
|
2021-02-18 18:43:20 +00:00
|
|
|
if (strcmp(ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
|
2020-05-19 05:50:24 +00:00
|
|
|
debug_utils_available = true;
|
|
|
|
}
|
|
|
|
}
|
2020-03-07 08:44:34 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
bool SystemInfo::is_extension_available(const char* extension_name) const {
|
2020-03-07 08:44:34 +00:00
|
|
|
if (!extension_name) return false;
|
2021-02-18 18:43:20 +00:00
|
|
|
return detail::check_extension_supported(available_extensions, extension_name);
|
2020-03-07 08:44:34 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
bool SystemInfo::is_layer_available(const char* layer_name) const {
|
2020-03-07 08:44:34 +00:00
|
|
|
if (!layer_name) return false;
|
2021-02-18 18:43:20 +00:00
|
|
|
return detail::check_layer_supported(available_layers, layer_name);
|
2020-03-07 08:44:34 +00:00
|
|
|
}
|
2020-03-07 09:41:52 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
void destroy_instance(Instance instance) {
|
2020-03-07 08:44:34 +00:00
|
|
|
if (instance.instance != VK_NULL_HANDLE) {
|
2020-12-17 07:42:48 +00:00
|
|
|
if (instance.debug_messenger != VK_NULL_HANDLE)
|
2021-02-18 18:43:20 +00:00
|
|
|
destroy_debug_utils_messenger(instance.instance, instance.debug_messenger, instance.allocation_callbacks);
|
|
|
|
detail::vulkan_functions().fp_vkDestroyInstance(instance.instance, instance.allocation_callbacks);
|
2020-02-18 22:18:08 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder::InstanceBuilder(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr) {
|
2020-06-17 23:13:39 +00:00
|
|
|
info.fp_vkGetInstanceProcAddr = fp_vkGetInstanceProcAddr;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder::InstanceBuilder() {}
|
2020-03-07 08:44:34 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<Instance> InstanceBuilder::build() const {
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
auto sys_info_ret = SystemInfo::get_system_info();
|
|
|
|
if (!sys_info_ret) return sys_info_ret.error();
|
|
|
|
auto system = sys_info_ret.value();
|
2020-06-17 23:13:39 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
uint32_t api_version = VK_MAKE_VERSION(1, 0, 0);
|
2020-03-09 21:10:11 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
if (info.required_api_version > VK_MAKE_VERSION(1, 0, 0) ||
|
|
|
|
info.desired_api_version > VK_MAKE_VERSION(1, 0, 0)) {
|
2020-06-17 23:13:39 +00:00
|
|
|
PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::vulkan_functions().fp_vkEnumerateInstanceVersion;
|
2020-03-09 21:10:11 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
uint32_t queried_api_version = VK_MAKE_VERSION(1, 0, 0);
|
2020-03-09 21:10:11 +00:00
|
|
|
if (pfn_vkEnumerateInstanceVersion != nullptr) {
|
2021-02-18 18:43:20 +00:00
|
|
|
VkResult res = pfn_vkEnumerateInstanceVersion(&queried_api_version);
|
2020-03-09 21:10:11 +00:00
|
|
|
// Should always return VK_SUCCESS
|
|
|
|
if (res != VK_SUCCESS && info.required_api_version > 0)
|
2021-02-18 18:43:20 +00:00
|
|
|
return make_error_code(InstanceError::vulkan_version_unavailable);
|
2020-03-09 21:10:11 +00:00
|
|
|
}
|
|
|
|
if (pfn_vkEnumerateInstanceVersion == nullptr || queried_api_version < info.required_api_version) {
|
2021-02-18 18:43:20 +00:00
|
|
|
if (VK_VERSION_MINOR(info.required_api_version) == 2)
|
|
|
|
return make_error_code(InstanceError::vulkan_version_1_2_unavailable);
|
|
|
|
else if (VK_VERSION_MINOR(info.required_api_version))
|
|
|
|
return make_error_code(InstanceError::vulkan_version_1_1_unavailable);
|
2020-03-09 21:10:11 +00:00
|
|
|
else
|
2021-02-18 18:43:20 +00:00
|
|
|
return make_error_code(InstanceError::vulkan_version_unavailable);
|
2020-03-09 21:10:11 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
if (info.required_api_version > VK_MAKE_VERSION(1, 0, 0)) {
|
2020-03-09 21:10:11 +00:00
|
|
|
api_version = info.required_api_version;
|
2021-02-18 18:43:20 +00:00
|
|
|
} else if (info.desired_api_version > VK_MAKE_VERSION(1, 0, 0)) {
|
2020-03-09 21:10:11 +00:00
|
|
|
if (queried_api_version >= info.desired_api_version)
|
|
|
|
api_version = info.desired_api_version;
|
|
|
|
else
|
|
|
|
api_version = queried_api_version;
|
2020-03-08 07:14:36 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-09 21:10:11 +00:00
|
|
|
|
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;
|
2020-03-09 21:10:11 +00:00
|
|
|
app_info.apiVersion = api_version;
|
2020-01-31 22:23:22 +00:00
|
|
|
|
|
|
|
std::vector<const char*> extensions;
|
|
|
|
for (auto& ext : info.extensions)
|
2021-02-18 18:43:20 +00:00
|
|
|
extensions.push_back(ext);
|
2020-05-19 16:44:40 +00:00
|
|
|
if (info.debug_callback != nullptr && system.debug_utils_available) {
|
2021-02-18 18:43:20 +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) {
|
2021-02-18 18:43:20 +00:00
|
|
|
auto check_add_window_ext = [&](const char* name) -> bool {
|
|
|
|
if (!detail::check_extension_supported(system.available_extensions, name)) return false;
|
|
|
|
extensions.push_back(name);
|
2020-05-26 19:33:40 +00:00
|
|
|
return true;
|
2020-05-19 16:44:40 +00:00
|
|
|
};
|
2021-02-18 18:43:20 +00:00
|
|
|
bool khr_surface_added = check_add_window_ext("VK_KHR_surface");
|
2020-01-31 22:23:22 +00:00
|
|
|
#if defined(_WIN32)
|
2021-02-18 18:43:20 +00:00
|
|
|
bool added_window_exts = check_add_window_ext("VK_KHR_win32_surface");
|
2020-02-03 23:23:47 +00:00
|
|
|
#elif defined(__ANDROID__)
|
2021-02-18 18:43:20 +00:00
|
|
|
bool added_window_exts = check_add_window_ext("VK_KHR_android_surface");
|
2020-01-31 22:23:22 +00:00
|
|
|
#elif defined(_DIRECT2DISPLAY)
|
2021-02-18 18:43:20 +00:00
|
|
|
bool added_window_exts = check_add_window_ext("VK_KHR_display");
|
2020-02-03 23:23:47 +00:00
|
|
|
#elif defined(__linux__)
|
2020-12-17 07:42:48 +00:00
|
|
|
// make sure all three calls to check_add_window_ext, don't allow short circuiting
|
2021-02-18 18:43:20 +00:00
|
|
|
bool added_window_exts = check_add_window_ext("VK_KHR_xcb_surface");
|
|
|
|
added_window_exts = check_add_window_ext("VK_KHR_xlib_surface") || added_window_exts;
|
|
|
|
added_window_exts = check_add_window_ext("VK_KHR_wayland_surface") || added_window_exts;
|
2020-02-03 23:23:47 +00:00
|
|
|
#elif defined(__APPLE__)
|
2021-02-18 18:43:20 +00:00
|
|
|
bool added_window_exts = check_add_window_ext("VK_EXT_metal_surface");
|
2020-01-31 22:23:22 +00:00
|
|
|
#endif
|
2020-05-26 19:33:40 +00:00
|
|
|
if (!khr_surface_added || !added_window_exts)
|
2021-02-18 18:43:20 +00:00
|
|
|
return make_error_code(InstanceError::windowing_extensions_not_present);
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
bool all_extensions_supported = detail::check_extensions_supported(system.available_extensions, extensions);
|
2020-02-11 01:01:58 +00:00
|
|
|
if (!all_extensions_supported) {
|
2021-02-18 18:43:20 +00:00
|
|
|
return make_error_code(InstanceError::requested_extensions_not_present);
|
2020-02-11 01:01:58 +00:00
|
|
|
}
|
|
|
|
|
2020-01-31 22:23:22 +00:00
|
|
|
std::vector<const char*> layers;
|
|
|
|
for (auto& layer : info.layers)
|
2021-02-18 18:43:20 +00:00
|
|
|
layers.push_back(layer);
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2020-06-17 23:13:39 +00:00
|
|
|
if (info.enable_validation_layers || (info.request_validation_layers && system.validation_layers_available)) {
|
2021-02-18 18:43:20 +00:00
|
|
|
layers.push_back(detail::validation_layer_name);
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
bool all_layers_supported = detail::check_layers_supported(system.available_layers, layers);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (!all_layers_supported) {
|
2021-02-18 18:43:20 +00:00
|
|
|
return make_error_code(InstanceError::requested_layers_not_present);
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
2020-03-08 05:21:27 +00:00
|
|
|
std::vector<VkBaseOutStructure*> pNext_chain;
|
|
|
|
|
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;
|
2021-02-18 18:43:20 +00:00
|
|
|
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&messengerCreateInfo));
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VkValidationFeaturesEXT features{};
|
2021-02-18 18:43:20 +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;
|
2020-03-08 05:58:23 +00:00
|
|
|
features.enabledValidationFeatureCount =
|
2021-02-18 18:43:20 +00:00
|
|
|
static_cast<uint32_t>(info.enabled_validation_features.size());
|
|
|
|
features.pEnabledValidationFeatures = info.enabled_validation_features.data();
|
2020-03-08 05:58:23 +00:00
|
|
|
features.disabledValidationFeatureCount =
|
2021-02-18 18:43:20 +00:00
|
|
|
static_cast<uint32_t>(info.disabled_validation_features.size());
|
|
|
|
features.pDisabledValidationFeatures = info.disabled_validation_features.data();
|
|
|
|
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&features));
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VkValidationFlagsEXT checks{};
|
2021-02-18 18:43:20 +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;
|
2021-02-18 18:43:20 +00:00
|
|
|
checks.disabledValidationCheckCount = static_cast<uint32_t>(info.disabled_validation_checks.size());
|
|
|
|
checks.pDisabledValidationChecks = info.disabled_validation_checks.data();
|
|
|
|
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&checks));
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VkInstanceCreateInfo instance_create_info = {};
|
|
|
|
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::setup_pNext_chain(instance_create_info, pNext_chain);
|
2020-01-31 22:23:22 +00:00
|
|
|
instance_create_info.flags = info.flags;
|
|
|
|
instance_create_info.pApplicationInfo = &app_info;
|
2021-02-18 18:43:20 +00:00
|
|
|
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();
|
2020-01-31 22:23:22 +00:00
|
|
|
|
|
|
|
Instance instance;
|
2021-02-18 18:43:20 +00:00
|
|
|
VkResult res = detail::vulkan_functions().fp_vkCreateInstance(
|
2020-06-17 23:13:39 +00:00
|
|
|
&instance_create_info, info.allocation_callbacks, &instance.instance);
|
2020-02-10 18:29:09 +00:00
|
|
|
if (res != VK_SUCCESS)
|
2021-02-18 18:43:20 +00:00
|
|
|
return detail::Result<Instance>(InstanceError::failed_create_instance, res);
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::vulkan_functions().init_instance_funcs(instance.instance);
|
2020-06-17 23:13:39 +00:00
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
if (info.use_debug_messenger) {
|
2021-02-18 18:43:20 +00:00
|
|
|
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,
|
2020-03-07 22:33:17 +00:00
|
|
|
&instance.debug_messenger,
|
|
|
|
info.allocation_callbacks);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
2021-02-18 18:43:20 +00:00
|
|
|
return detail::Result<Instance>(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;
|
|
|
|
}
|
2020-03-07 22:33:17 +00:00
|
|
|
instance.allocation_callbacks = info.allocation_callbacks;
|
2020-03-09 21:10:11 +00:00
|
|
|
instance.instance_version = api_version;
|
2021-02-18 18:43:20 +00:00
|
|
|
instance.fp_vkGetInstanceProcAddr = detail::vulkan_functions().ptr_vkGetInstanceProcAddr;
|
2020-01-31 22:23:22 +00:00
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_app_name(const char* app_name) {
|
2020-02-18 22:18:08 +00:00
|
|
|
if (!app_name) return *this;
|
2020-01-31 22:23:22 +00:00
|
|
|
info.app_name = app_name;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_engine_name(const char* engine_name) {
|
2020-02-18 22:18:08 +00:00
|
|
|
if (!engine_name) return *this;
|
2020-01-31 22:23:22 +00:00
|
|
|
info.engine_name = engine_name;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_app_version(uint32_t major, uint32_t minor, uint32_t patch) {
|
|
|
|
info.application_version = VK_MAKE_VERSION(major, minor, patch);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_engine_version(uint32_t major, uint32_t minor, uint32_t patch) {
|
|
|
|
info.engine_version = VK_MAKE_VERSION(major, minor, patch);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::require_api_version(uint32_t major, uint32_t minor, uint32_t patch) {
|
|
|
|
info.required_api_version = VK_MAKE_VERSION(major, minor, patch);
|
2020-03-09 21:10:11 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::desire_api_version(uint32_t major, uint32_t minor, uint32_t patch) {
|
|
|
|
info.desired_api_version = VK_MAKE_VERSION(major, minor, patch);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::enable_layer(const char* layer_name) {
|
2020-02-18 22:18:08 +00:00
|
|
|
if (!layer_name) return *this;
|
2021-02-18 18:43:20 +00:00
|
|
|
info.layers.push_back(layer_name);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::enable_extension(const char* extension_name) {
|
2020-03-07 08:44:34 +00:00
|
|
|
if (!extension_name) return *this;
|
2021-02-18 18:43:20 +00:00
|
|
|
info.extensions.push_back(extension_name);
|
2020-03-07 08:44:34 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::enable_validation_layers(bool enable_validation) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.enable_validation_layers = enable_validation;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::request_validation_layers(bool enable_validation) {
|
2020-06-17 23:13:39 +00:00
|
|
|
info.request_validation_layers = enable_validation;
|
2020-02-19 02:12:31 +00:00
|
|
|
return *this;
|
2020-02-18 22:18:08 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::use_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;
|
|
|
|
}
|
2021-02-18 18:43:20 +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;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_headless(bool headless) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.headless_context = headless;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +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;
|
|
|
|
}
|
2021-02-18 18:43:20 +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;
|
|
|
|
}
|
2021-02-18 18:43:20 +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;
|
|
|
|
}
|
2021-02-18 18:43:20 +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;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_validation_disable(VkValidationCheckEXT check) {
|
|
|
|
info.disabled_validation_checks.push_back(check);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_validation_feature_enable(VkValidationFeatureEnableEXT enable) {
|
|
|
|
info.enabled_validation_features.push_back(enable);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::add_validation_feature_disable(VkValidationFeatureDisableEXT disable) {
|
|
|
|
info.disabled_validation_features.push_back(disable);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
InstanceBuilder& InstanceBuilder::set_allocation_callbacks(VkAllocationCallbacks* callbacks) {
|
2020-03-07 22:33:17 +00:00
|
|
|
info.allocation_callbacks = callbacks;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
void destroy_debug_messenger(VkInstance const instance, VkDebugUtilsMessengerEXT const messenger);
|
2020-10-21 21:32:10 +00:00
|
|
|
|
|
|
|
|
2020-02-17 20:13:09 +00:00
|
|
|
// ---- Physical Device ---- //
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
namespace detail {
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
std::vector<const char*> check_device_extension_support(
|
2020-02-12 00:51:03 +00:00
|
|
|
VkPhysicalDevice device, std::vector<const char*> desired_extensions) {
|
2020-05-17 13:31:02 +00:00
|
|
|
std::vector<VkExtensionProperties> available_extensions;
|
2021-02-18 18:43:20 +00:00
|
|
|
auto available_extensions_ret = detail::get_vector<VkExtensionProperties>(
|
|
|
|
available_extensions, detail::vulkan_functions().fp_vkEnumerateDeviceExtensionProperties, device, nullptr);
|
2020-05-17 13:31:02 +00:00
|
|
|
if (available_extensions_ret != VK_SUCCESS) 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-05-17 13:31:02 +00:00
|
|
|
for (const auto& extension : available_extensions) {
|
2020-02-06 22:46:14 +00:00
|
|
|
for (auto& req_ext : desired_extensions) {
|
2021-02-18 18:43:20 +00:00
|
|
|
if (strcmp(req_ext, extension.extensionName) == 0) {
|
|
|
|
extensions_to_enable.push_back(req_ext);
|
2020-03-12 03:19:31 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-03 23:23:47 +00:00
|
|
|
return extensions_to_enable;
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
|
|
|
|
2021-03-26 23:34:10 +00:00
|
|
|
// clang-format off
|
2021-02-18 18:43:20 +00:00
|
|
|
bool supports_features(VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested) {
|
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;
|
|
|
|
return true;
|
|
|
|
}
|
2021-03-26 23:34:10 +00:00
|
|
|
#if defined(VK_API_VERSION_1_2)
|
|
|
|
bool supports_features_11(VkPhysicalDeviceVulkan11Features supported, VkPhysicalDeviceVulkan11Features requested){
|
|
|
|
if (requested.storageBuffer16BitAccess && !supported.storageBuffer16BitAccess) return false;
|
|
|
|
if (requested.uniformAndStorageBuffer16BitAccess && !supported.uniformAndStorageBuffer16BitAccess) return false;
|
|
|
|
if (requested.storagePushConstant16 && !supported.storagePushConstant16) return false;
|
|
|
|
if (requested.storageInputOutput16 && !supported.storageInputOutput16) return false;
|
|
|
|
if (requested.multiview && !supported.multiview) return false;
|
|
|
|
if (requested.multiviewGeometryShader && !supported.multiviewGeometryShader) return false;
|
|
|
|
if (requested.multiviewTessellationShader && !supported.multiviewTessellationShader) return false;
|
|
|
|
if (requested.variablePointersStorageBuffer && !supported.variablePointersStorageBuffer) return false;
|
|
|
|
if (requested.variablePointers && !supported.variablePointers) return false;
|
|
|
|
if (requested.protectedMemory && !supported.protectedMemory) return false;
|
|
|
|
if (requested.samplerYcbcrConversion && !supported.samplerYcbcrConversion) return false;
|
|
|
|
if (requested.shaderDrawParameters && !supported.shaderDrawParameters) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool supports_features_12(VkPhysicalDeviceVulkan12Features supported, VkPhysicalDeviceVulkan12Features requested){
|
|
|
|
if(requested.samplerMirrorClampToEdge && !supported.samplerMirrorClampToEdge) return false;
|
|
|
|
if(requested.drawIndirectCount && !supported.drawIndirectCount) return false;
|
|
|
|
if(requested.storageBuffer8BitAccess && !supported.storageBuffer8BitAccess) return false;
|
|
|
|
if(requested.uniformAndStorageBuffer8BitAccess && !supported.uniformAndStorageBuffer8BitAccess) return false;
|
|
|
|
if(requested.storagePushConstant8 && !supported.storagePushConstant8) return false;
|
|
|
|
if(requested.shaderBufferInt64Atomics && !supported.shaderBufferInt64Atomics) return false;
|
|
|
|
if(requested.shaderSharedInt64Atomics && !supported.shaderSharedInt64Atomics) return false;
|
|
|
|
if(requested.shaderFloat16 && !supported.shaderFloat16) return false;
|
|
|
|
if(requested.shaderInt8 && !supported.shaderInt8) return false;
|
|
|
|
if(requested.descriptorIndexing && !supported.descriptorIndexing) return false;
|
|
|
|
if(requested.shaderInputAttachmentArrayDynamicIndexing && !supported.shaderInputAttachmentArrayDynamicIndexing) return false;
|
|
|
|
if(requested.shaderUniformTexelBufferArrayDynamicIndexing && !supported.shaderUniformTexelBufferArrayDynamicIndexing) return false;
|
|
|
|
if(requested.shaderStorageTexelBufferArrayDynamicIndexing && !supported.shaderStorageTexelBufferArrayDynamicIndexing) return false;
|
|
|
|
if(requested.shaderUniformBufferArrayNonUniformIndexing && !supported.shaderUniformBufferArrayNonUniformIndexing) return false;
|
|
|
|
if(requested.shaderSampledImageArrayNonUniformIndexing && !supported.shaderSampledImageArrayNonUniformIndexing) return false;
|
|
|
|
if(requested.shaderStorageBufferArrayNonUniformIndexing && !supported.shaderStorageBufferArrayNonUniformIndexing) return false;
|
|
|
|
if(requested.shaderStorageImageArrayNonUniformIndexing && !supported.shaderStorageImageArrayNonUniformIndexing) return false;
|
|
|
|
if(requested.shaderInputAttachmentArrayNonUniformIndexing && !supported.shaderInputAttachmentArrayNonUniformIndexing) return false;
|
|
|
|
if(requested.shaderUniformTexelBufferArrayNonUniformIndexing && !supported.shaderUniformTexelBufferArrayNonUniformIndexing) return false;
|
|
|
|
if(requested.shaderStorageTexelBufferArrayNonUniformIndexing && !supported.shaderStorageTexelBufferArrayNonUniformIndexing) return false;
|
|
|
|
if(requested.descriptorBindingUniformBufferUpdateAfterBind && !supported.descriptorBindingUniformBufferUpdateAfterBind) return false;
|
|
|
|
if(requested.descriptorBindingSampledImageUpdateAfterBind && !supported.descriptorBindingSampledImageUpdateAfterBind) return false;
|
|
|
|
if(requested.descriptorBindingStorageImageUpdateAfterBind && !supported.descriptorBindingStorageImageUpdateAfterBind) return false;
|
|
|
|
if(requested.descriptorBindingStorageBufferUpdateAfterBind && !supported.descriptorBindingStorageBufferUpdateAfterBind) return false;
|
|
|
|
if(requested.descriptorBindingUniformTexelBufferUpdateAfterBind && !supported.descriptorBindingUniformTexelBufferUpdateAfterBind) return false;
|
|
|
|
if(requested.descriptorBindingStorageTexelBufferUpdateAfterBind && !supported.descriptorBindingStorageTexelBufferUpdateAfterBind) return false;
|
|
|
|
if(requested.descriptorBindingUpdateUnusedWhilePending && !supported.descriptorBindingUpdateUnusedWhilePending) return false;
|
|
|
|
if(requested.descriptorBindingPartiallyBound && !supported.descriptorBindingPartiallyBound) return false;
|
|
|
|
if(requested.descriptorBindingVariableDescriptorCount && !supported.descriptorBindingVariableDescriptorCount) return false;
|
|
|
|
if(requested.runtimeDescriptorArray && !supported.runtimeDescriptorArray) return false;
|
|
|
|
if(requested.samplerFilterMinmax && !supported.samplerFilterMinmax) return false;
|
|
|
|
if(requested.scalarBlockLayout && !supported.scalarBlockLayout) return false;
|
|
|
|
if(requested.imagelessFramebuffer && !supported.imagelessFramebuffer) return false;
|
|
|
|
if(requested.uniformBufferStandardLayout && !supported.uniformBufferStandardLayout) return false;
|
|
|
|
if(requested.shaderSubgroupExtendedTypes && !supported.shaderSubgroupExtendedTypes) return false;
|
|
|
|
if(requested.separateDepthStencilLayouts && !supported.separateDepthStencilLayouts) return false;
|
|
|
|
if(requested.hostQueryReset && !supported.hostQueryReset) return false;
|
|
|
|
if(requested.timelineSemaphore && !supported.timelineSemaphore) return false;
|
|
|
|
if(requested.bufferDeviceAddress && !supported.bufferDeviceAddress) return false;
|
|
|
|
if(requested.bufferDeviceAddressCaptureReplay && !supported.bufferDeviceAddressCaptureReplay) return false;
|
|
|
|
if(requested.bufferDeviceAddressMultiDevice && !supported.bufferDeviceAddressMultiDevice) return false;
|
|
|
|
if(requested.vulkanMemoryModel && !supported.vulkanMemoryModel) return false;
|
|
|
|
if(requested.vulkanMemoryModelDeviceScope && !supported.vulkanMemoryModelDeviceScope) return false;
|
|
|
|
if(requested.vulkanMemoryModelAvailabilityVisibilityChains && !supported.vulkanMemoryModelAvailabilityVisibilityChains) return false;
|
|
|
|
if(requested.shaderOutputViewportIndex && !supported.shaderOutputViewportIndex) return false;
|
|
|
|
if(requested.shaderOutputLayer && !supported.shaderOutputLayer) return false;
|
|
|
|
if(requested.subgroupBroadcastDynamicId && !supported.subgroupBroadcastDynamicId) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// clang-format on
|
2021-02-18 18:25:06 +00:00
|
|
|
// finds the first queue which supports graphics operations. returns QUEUE_INDEX_MAX_VALUE if none is found
|
2021-02-18 18:43:20 +00:00
|
|
|
uint32_t get_graphics_queue_index(std::vector<VkQueueFamilyProperties> const& families) {
|
|
|
|
for (uint32_t i = 0; i < static_cast<uint32_t>(families.size()); i++) {
|
2021-02-18 18:25:06 +00:00
|
|
|
if (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) return i;
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
return QUEUE_INDEX_MAX_VALUE;
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
2020-03-07 23:02:18 +00:00
|
|
|
// finds a compute queue which is separate from the graphics queue and tries to find one without
|
2021-02-18 18:25:06 +00:00
|
|
|
// transfer support returns QUEUE_INDEX_MAX_VALUE if none is found
|
2021-02-18 18:43:20 +00:00
|
|
|
uint32_t get_separate_compute_queue_index(std::vector<VkQueueFamilyProperties> const& families) {
|
2021-02-18 18:25:06 +00:00
|
|
|
uint32_t compute = QUEUE_INDEX_MAX_VALUE;
|
2021-02-18 18:43:20 +00:00
|
|
|
for (uint32_t i = 0; i < static_cast<uint32_t>(families.size()); i++) {
|
2020-02-08 00:34:05 +00:00
|
|
|
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) {
|
2021-02-18 18:25:06 +00:00
|
|
|
return i;
|
2020-02-17 20:13:09 +00:00
|
|
|
} else {
|
2021-02-18 18:25:06 +00:00
|
|
|
compute = i;
|
2020-02-17 20:13:09 +00:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
}
|
2020-03-07 23:02:18 +00:00
|
|
|
// finds a transfer queue which is separate from the graphics queue and tries to find one without
|
2021-02-18 18:25:06 +00:00
|
|
|
// compute support returns QUEUE_INDEX_MAX_VALUE if none is found
|
2021-02-18 18:43:20 +00:00
|
|
|
uint32_t get_separate_transfer_queue_index(std::vector<VkQueueFamilyProperties> const& families) {
|
2021-02-18 18:25:06 +00:00
|
|
|
uint32_t transfer = QUEUE_INDEX_MAX_VALUE;
|
2021-02-18 18:43:20 +00:00
|
|
|
for (uint32_t i = 0; i < static_cast<uint32_t>(families.size()); i++) {
|
2020-02-08 00:34:05 +00:00
|
|
|
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) {
|
2021-02-18 18:25:06 +00:00
|
|
|
return i;
|
2020-02-17 20:13:09 +00:00
|
|
|
} else {
|
2021-02-18 18:25:06 +00:00
|
|
|
transfer = i;
|
2020-02-17 20:13:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
2020-02-18 22:18:08 +00:00
|
|
|
return transfer;
|
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
// finds the first queue which supports only compute (not graphics or transfer). returns QUEUE_INDEX_MAX_VALUE if none is found
|
2021-02-18 18:43:20 +00:00
|
|
|
uint32_t get_dedicated_compute_queue_index(std::vector<VkQueueFamilyProperties> const& families) {
|
|
|
|
for (uint32_t i = 0; i < static_cast<uint32_t>(families.size()); i++) {
|
2020-02-18 22:18:08 +00:00
|
|
|
if ((families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) &&
|
|
|
|
(families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 &&
|
|
|
|
(families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) == 0)
|
2021-02-18 18:25:06 +00:00
|
|
|
return i;
|
2020-02-18 22:18:08 +00:00
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
return QUEUE_INDEX_MAX_VALUE;
|
2020-02-18 22:18:08 +00:00
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
// finds the first queue which supports only transfer (not graphics or compute). returns QUEUE_INDEX_MAX_VALUE if none is found
|
2021-02-18 18:43:20 +00:00
|
|
|
uint32_t get_dedicated_transfer_queue_index(std::vector<VkQueueFamilyProperties> const& families) {
|
|
|
|
for (uint32_t i = 0; i < static_cast<uint32_t>(families.size()); i++) {
|
2020-02-18 22:18:08 +00:00
|
|
|
if ((families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) &&
|
|
|
|
(families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 &&
|
|
|
|
(families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0)
|
2021-02-18 18:25:06 +00:00
|
|
|
return i;
|
2020-02-18 22:18:08 +00:00
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
return QUEUE_INDEX_MAX_VALUE;
|
2020-02-08 00:34:05 +00:00
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
// finds the first queue which supports presenting. returns QUEUE_INDEX_MAX_VALUE if none is found
|
2021-02-18 18:43:20 +00:00
|
|
|
uint32_t get_present_queue_index(VkPhysicalDevice const phys_device,
|
2020-02-08 00:34:05 +00:00
|
|
|
VkSurfaceKHR const surface,
|
|
|
|
std::vector<VkQueueFamilyProperties> const& families) {
|
2021-02-18 18:43:20 +00:00
|
|
|
for (uint32_t i = 0; i < static_cast<uint32_t>(families.size()); i++) {
|
2020-02-06 22:46:14 +00:00
|
|
|
VkBool32 presentSupport = false;
|
|
|
|
if (surface != VK_NULL_HANDLE) {
|
2021-02-18 18:43:20 +00:00
|
|
|
VkResult res = detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceSupportKHR(
|
2021-02-18 18:25:06 +00:00
|
|
|
phys_device, i, surface, &presentSupport);
|
|
|
|
if (res != VK_SUCCESS)
|
|
|
|
return QUEUE_INDEX_MAX_VALUE; // TODO: determine if this should fail another way
|
2020-02-06 22:46:14 +00:00
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
if (presentSupport == VK_TRUE) return i;
|
2020-02-06 22:46:14 +00:00
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
return QUEUE_INDEX_MAX_VALUE;
|
2020-02-06 22:46:14 +00:00
|
|
|
}
|
2020-02-19 02:45:22 +00:00
|
|
|
} // namespace detail
|
2020-02-06 22:46:14 +00:00
|
|
|
|
2020-03-07 09:41:52 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details(
|
2021-03-26 23:34:10 +00:00
|
|
|
uint32_t instance_version, VkPhysicalDevice phys_device) const {
|
2020-02-11 01:01:58 +00:00
|
|
|
PhysicalDeviceSelector::PhysicalDeviceDesc desc{};
|
|
|
|
desc.phys_device = phys_device;
|
2021-02-18 18:43:20 +00:00
|
|
|
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties>(
|
|
|
|
detail::vulkan_functions().fp_vkGetPhysicalDeviceQueueFamilyProperties, phys_device);
|
2020-02-11 01:01:58 +00:00
|
|
|
desc.queue_families = queue_families;
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::vulkan_functions().fp_vkGetPhysicalDeviceProperties(phys_device, &desc.device_properties);
|
|
|
|
detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures(phys_device, &desc.device_features);
|
|
|
|
detail::vulkan_functions().fp_vkGetPhysicalDeviceMemoryProperties(phys_device, &desc.mem_properties);
|
2021-03-26 23:34:10 +00:00
|
|
|
|
|
|
|
#if defined(VK_API_VERSION_1_1)
|
|
|
|
desc.device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
|
|
|
|
|
|
|
#if defined(VK_API_VERSION_1_2)
|
|
|
|
desc.device_features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
|
|
|
|
desc.device_features_12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
|
|
|
desc.device_features2.pNext = &desc.device_features_11;
|
|
|
|
desc.device_features_11.pNext = &desc.device_features_12;
|
|
|
|
#endif
|
|
|
|
if (instance_version >= VK_API_VERSION_1_1) {
|
|
|
|
detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2(phys_device, &desc.device_features2);
|
|
|
|
}
|
|
|
|
#endif
|
2020-02-11 01:01:58 +00:00
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable(PhysicalDeviceDesc pd) const {
|
2020-02-11 01:01:58 +00:00
|
|
|
Suitable suitable = Suitable::yes;
|
|
|
|
|
2020-03-12 03:19:31 +00:00
|
|
|
if (criteria.required_version > pd.device_properties.apiVersion) return Suitable::no;
|
2020-03-09 21:10:11 +00:00
|
|
|
if (criteria.desired_version > pd.device_properties.apiVersion) suitable = Suitable::partial;
|
|
|
|
|
2021-02-18 18:25:06 +00:00
|
|
|
bool dedicated_compute =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::get_dedicated_compute_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE;
|
2021-02-18 18:25:06 +00:00
|
|
|
bool dedicated_transfer =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::get_dedicated_transfer_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE;
|
2021-02-18 18:25:06 +00:00
|
|
|
bool separate_compute =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::get_separate_compute_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE;
|
2021-02-18 18:25:06 +00:00
|
|
|
bool separate_transfer =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::get_separate_transfer_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE;
|
2020-02-19 02:45:22 +00:00
|
|
|
|
|
|
|
bool present_queue =
|
2021-03-26 23:34:10 +00:00
|
|
|
detail::get_present_queue_index(pd.phys_device, instance_info.surface, pd.queue_families) !=
|
2021-02-18 18:25:06 +00:00
|
|
|
detail::QUEUE_INDEX_MAX_VALUE;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-03-09 21:10:11 +00:00
|
|
|
if (criteria.require_dedicated_compute_queue && !dedicated_compute) return Suitable::no;
|
|
|
|
if (criteria.require_dedicated_transfer_queue && !dedicated_transfer) return Suitable::no;
|
|
|
|
if (criteria.require_separate_compute_queue && !separate_compute) return Suitable::no;
|
|
|
|
if (criteria.require_separate_transfer_queue && !separate_transfer) return Suitable::no;
|
2020-04-19 06:52:31 +00:00
|
|
|
if (criteria.require_present && !present_queue && !criteria.defer_surface_initialization)
|
|
|
|
return Suitable::no;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-03 23:23:47 +00:00
|
|
|
auto required_extensions_supported =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::check_device_extension_support(pd.phys_device, criteria.required_extensions);
|
|
|
|
if (required_extensions_supported.size() != criteria.required_extensions.size())
|
2020-03-09 21:10:11 +00:00
|
|
|
return Suitable::no;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2020-02-03 23:23:47 +00:00
|
|
|
auto desired_extensions_supported =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::check_device_extension_support(pd.phys_device, criteria.desired_extensions);
|
|
|
|
if (desired_extensions_supported.size() != criteria.desired_extensions.size())
|
2020-02-03 23:23:47 +00:00
|
|
|
suitable = Suitable::partial;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
bool swapChainAdequate = false;
|
2020-03-08 06:26:46 +00:00
|
|
|
if (criteria.defer_surface_initialization) {
|
|
|
|
swapChainAdequate = true;
|
2021-03-26 23:34:10 +00:00
|
|
|
} else if (!instance_info.headless) {
|
2020-05-17 13:31:02 +00:00
|
|
|
std::vector<VkSurfaceFormatKHR> formats;
|
|
|
|
std::vector<VkPresentModeKHR> present_modes;
|
2020-03-08 06:26:46 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
auto formats_ret = detail::get_vector<VkSurfaceFormatKHR>(formats,
|
|
|
|
detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceFormatsKHR,
|
2020-06-17 23:13:39 +00:00
|
|
|
pd.phys_device,
|
2021-03-26 23:34:10 +00:00
|
|
|
instance_info.surface);
|
2021-02-18 18:43:20 +00:00
|
|
|
auto present_modes_ret = detail::get_vector<VkPresentModeKHR>(present_modes,
|
|
|
|
detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfacePresentModesKHR,
|
2020-06-17 23:13:39 +00:00
|
|
|
pd.phys_device,
|
2021-03-26 23:34:10 +00:00
|
|
|
instance_info.surface);
|
2020-03-08 06:26:46 +00:00
|
|
|
|
2020-05-17 13:31:02 +00:00
|
|
|
if (formats_ret == VK_SUCCESS && present_modes_ret == VK_SUCCESS) {
|
2021-02-18 18:43:20 +00:00
|
|
|
swapChainAdequate = !formats.empty() && !present_modes.empty();
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-09 21:10:11 +00:00
|
|
|
if (criteria.require_present && !swapChainAdequate) return Suitable::no;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
if (pd.device_properties.deviceType != static_cast<VkPhysicalDeviceType>(criteria.preferred_type)) {
|
2020-03-07 22:44:47 +00:00
|
|
|
if (criteria.allow_any_type)
|
2020-01-30 08:15:10 +00:00
|
|
|
suitable = Suitable::partial;
|
|
|
|
else
|
2020-03-09 21:10:11 +00:00
|
|
|
return Suitable::no;
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
2020-02-06 22:46:14 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
bool required_features_supported = detail::supports_features(pd.device_features, criteria.required_features);
|
2020-03-09 21:10:11 +00:00
|
|
|
if (!required_features_supported) return Suitable::no;
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2021-03-26 23:34:10 +00:00
|
|
|
#if defined(VK_API_VERSION_1_2)
|
|
|
|
if (instance_info.version >= VK_API_VERSION_1_2) {
|
|
|
|
bool required_features_11_supported =
|
|
|
|
detail::supports_features_11(pd.device_features_11, criteria.required_features_11);
|
|
|
|
if (!required_features_11_supported) return Suitable::no;
|
|
|
|
|
|
|
|
bool required_features_12_supported =
|
|
|
|
detail::supports_features_12(pd.device_features_12, criteria.required_features_12);
|
|
|
|
if (!required_features_12_supported) return Suitable::no;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
bool has_required_memory = false;
|
|
|
|
bool has_preferred_memory = false;
|
2020-03-08 05:58:23 +00:00
|
|
|
for (uint32_t i = 0; i < pd.mem_properties.memoryHeapCount; i++) {
|
2020-02-11 01:01:58 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-09 21:10:11 +00:00
|
|
|
if (!has_required_memory) return Suitable::no;
|
2020-02-11 01:01:58 +00:00
|
|
|
if (!has_preferred_memory) suitable = Suitable::partial;
|
|
|
|
|
2020-01-30 08:15:10 +00:00
|
|
|
return suitable;
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector::PhysicalDeviceSelector(Instance const& instance) {
|
2021-03-26 23:34:10 +00:00
|
|
|
instance_info.instance = instance.instance;
|
|
|
|
instance_info.headless = instance.headless;
|
|
|
|
instance_info.version = instance.instance_version;
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.require_present = !instance.headless;
|
2020-03-08 07:59:58 +00:00
|
|
|
criteria.required_version = instance.instance_version;
|
2020-03-09 21:10:11 +00:00
|
|
|
criteria.desired_version = instance.instance_version;
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<PhysicalDevice> PhysicalDeviceSelector::select() const {
|
2021-03-26 23:34:10 +00:00
|
|
|
if (!instance_info.headless && !criteria.defer_surface_initialization) {
|
|
|
|
if (instance_info.surface == VK_NULL_HANDLE)
|
2020-05-17 13:31:02 +00:00
|
|
|
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::no_surface_provided };
|
2020-03-10 03:53:10 +00:00
|
|
|
}
|
|
|
|
|
2020-05-17 13:31:02 +00:00
|
|
|
|
|
|
|
std::vector<VkPhysicalDevice> physical_devices;
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
auto physical_devices_ret = detail::get_vector<VkPhysicalDevice>(
|
2021-03-26 23:34:10 +00:00
|
|
|
physical_devices, detail::vulkan_functions().fp_vkEnumeratePhysicalDevices, instance_info.instance);
|
2020-05-17 13:31:02 +00:00
|
|
|
if (physical_devices_ret != VK_SUCCESS) {
|
|
|
|
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::failed_enumerate_physical_devices,
|
|
|
|
physical_devices_ret };
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
if (physical_devices.size() == 0) {
|
2020-05-17 13:31:02 +00:00
|
|
|
return detail::Result<PhysicalDevice>{ 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;
|
2020-05-17 13:31:02 +00:00
|
|
|
for (auto& phys_device : physical_devices) {
|
2021-03-26 23:34:10 +00:00
|
|
|
phys_device_descriptions.push_back(populate_device_details(instance_info.version, phys_device));
|
2020-02-11 01:01:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PhysicalDeviceDesc selected_device{};
|
|
|
|
|
2020-02-06 23:56:50 +00:00
|
|
|
if (criteria.use_first_gpu_unconditionally) {
|
2021-02-18 18:43:20 +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) {
|
2021-02-18 18:43:20 +00:00
|
|
|
auto suitable = is_device_suitable(device);
|
2020-02-06 23:56:50 +00:00
|
|
|
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-05-17 13:31:02 +00:00
|
|
|
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::no_suitable_device };
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
2020-02-11 01:01:58 +00:00
|
|
|
PhysicalDevice out_device{};
|
2020-03-10 03:53:10 +00:00
|
|
|
out_device.physical_device = selected_device.phys_device;
|
2021-03-26 23:34:10 +00:00
|
|
|
out_device.surface = instance_info.surface;
|
2020-02-11 01:01:58 +00:00
|
|
|
out_device.features = criteria.required_features;
|
2020-03-10 03:53:10 +00:00
|
|
|
out_device.properties = selected_device.device_properties;
|
|
|
|
out_device.memory_properties = selected_device.mem_properties;
|
2020-02-11 01:01:58 +00:00
|
|
|
out_device.queue_families = selected_device.queue_families;
|
2020-04-19 06:52:31 +00:00
|
|
|
out_device.defer_surface_initialization = criteria.defer_surface_initialization;
|
2020-02-03 23:23:47 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
out_device.extensions_to_enable.insert(out_device.extensions_to_enable.end(),
|
|
|
|
criteria.required_extensions.begin(),
|
|
|
|
criteria.required_extensions.end());
|
2020-02-03 23:23:47 +00:00
|
|
|
auto desired_extensions_supported =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::check_device_extension_support(out_device.physical_device, criteria.desired_extensions);
|
|
|
|
out_device.extensions_to_enable.insert(out_device.extensions_to_enable.end(),
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_surface(VkSurfaceKHR surface) {
|
2021-03-26 23:34:10 +00:00
|
|
|
instance_info.surface = surface;
|
|
|
|
instance_info.headless = false;
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::prefer_gpu_device_type(PreferredDeviceType type) {
|
2020-02-06 23:56:50 +00:00
|
|
|
criteria.preferred_type = type;
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::allow_any_gpu_device_type(bool allow_any_type) {
|
2020-03-07 22:44:47 +00:00
|
|
|
criteria.allow_any_type = allow_any_type;
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::require_present(bool require) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.require_present = require;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::require_dedicated_transfer_queue() {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.require_dedicated_transfer_queue = true;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::require_dedicated_compute_queue() {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.require_dedicated_compute_queue = true;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::require_separate_transfer_queue() {
|
2020-03-07 23:02:18 +00:00
|
|
|
criteria.require_separate_transfer_queue = true;
|
2020-02-19 02:45:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::require_separate_compute_queue() {
|
2020-03-07 23:02:18 +00:00
|
|
|
criteria.require_separate_compute_queue = true;
|
2020-02-19 02:45:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +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;
|
|
|
|
}
|
2021-02-18 18:43:20 +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;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::add_required_extension(const char* extension) {
|
|
|
|
criteria.required_extensions.push_back(extension);
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::add_required_extensions(std::vector<const char*> extensions) {
|
|
|
|
criteria.required_extensions.insert(
|
|
|
|
criteria.required_extensions.end(), extensions.begin(), extensions.end());
|
2020-02-06 23:56:50 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::add_desired_extension(const char* extension) {
|
|
|
|
criteria.desired_extensions.push_back(extension);
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::add_desired_extensions(std::vector<const char*> extensions) {
|
|
|
|
criteria.desired_extensions.insert(
|
|
|
|
criteria.desired_extensions.end(), extensions.begin(), extensions.end());
|
2020-02-06 23:56:50 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_minimum_version(uint32_t major, uint32_t minor) {
|
|
|
|
criteria.required_version = VK_MAKE_VERSION(major, minor, 0);
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_desired_version(uint32_t major, uint32_t minor) {
|
|
|
|
criteria.desired_version = VK_MAKE_VERSION(major, minor, 0);
|
2020-01-30 08:15:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-03-26 23:34:10 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features(VkPhysicalDeviceFeatures const& features) {
|
2020-01-30 08:15:10 +00:00
|
|
|
criteria.required_features = features;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-03-26 23:34:10 +00:00
|
|
|
#if defined(VK_API_VERSION_1_2)
|
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_11(
|
|
|
|
VkPhysicalDeviceVulkan11Features const& features_11) {
|
|
|
|
criteria.required_features_11 = features_11;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_12(
|
|
|
|
VkPhysicalDeviceVulkan12Features const& features_12) {
|
|
|
|
criteria.required_features_12 = features_12;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
#endif
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::defer_surface_initialization() {
|
2020-03-08 06:26:46 +00:00
|
|
|
criteria.defer_surface_initialization = true;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
PhysicalDeviceSelector& PhysicalDeviceSelector::select_first_device_unconditionally(bool unconditionally) {
|
2020-02-06 23:56:50 +00:00
|
|
|
criteria.use_first_gpu_unconditionally = unconditionally;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
bool PhysicalDevice::has_dedicated_compute_queue() const {
|
|
|
|
return detail::get_dedicated_compute_queue_index(queue_families) != detail::QUEUE_INDEX_MAX_VALUE;
|
2020-03-08 00:02:01 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
bool PhysicalDevice::has_separate_compute_queue() const {
|
|
|
|
return detail::get_separate_compute_queue_index(queue_families) != detail::QUEUE_INDEX_MAX_VALUE;
|
2020-03-08 00:02:01 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
bool PhysicalDevice::has_dedicated_transfer_queue() const {
|
|
|
|
return detail::get_dedicated_transfer_queue_index(queue_families) != detail::QUEUE_INDEX_MAX_VALUE;
|
2020-03-08 00:02:01 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
bool PhysicalDevice::has_separate_transfer_queue() const {
|
|
|
|
return detail::get_separate_transfer_queue_index(queue_families) != detail::QUEUE_INDEX_MAX_VALUE;
|
2020-03-08 00:02:01 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
std::vector<VkQueueFamilyProperties> PhysicalDevice::get_queue_families() const {
|
2020-04-19 03:24:59 +00:00
|
|
|
return queue_families;
|
|
|
|
}
|
2020-03-08 00:02:01 +00:00
|
|
|
|
|
|
|
// ---- Queues ---- //
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<uint32_t> Device::get_queue_index(QueueType type) const {
|
2021-02-18 18:25:06 +00:00
|
|
|
uint32_t index = detail::QUEUE_INDEX_MAX_VALUE;
|
2020-03-08 00:19:58 +00:00
|
|
|
switch (type) {
|
|
|
|
case QueueType::present:
|
2021-02-18 18:43:20 +00:00
|
|
|
index = detail::get_present_queue_index(physical_device.physical_device, surface, queue_families);
|
2021-02-18 18:25:06 +00:00
|
|
|
if (index == detail::QUEUE_INDEX_MAX_VALUE)
|
|
|
|
return detail::Result<uint32_t>{ QueueError::present_unavailable };
|
2020-03-08 00:19:58 +00:00
|
|
|
break;
|
|
|
|
case QueueType::graphics:
|
2021-02-18 18:43:20 +00:00
|
|
|
index = detail::get_graphics_queue_index(queue_families);
|
2021-02-18 18:25:06 +00:00
|
|
|
if (index == detail::QUEUE_INDEX_MAX_VALUE)
|
|
|
|
return detail::Result<uint32_t>{ QueueError::graphics_unavailable };
|
2020-03-08 00:19:58 +00:00
|
|
|
break;
|
|
|
|
case QueueType::compute:
|
2021-02-18 18:43:20 +00:00
|
|
|
index = detail::get_separate_compute_queue_index(queue_families);
|
2021-02-18 18:25:06 +00:00
|
|
|
if (index == detail::QUEUE_INDEX_MAX_VALUE)
|
|
|
|
return detail::Result<uint32_t>{ QueueError::compute_unavailable };
|
2020-03-08 00:19:58 +00:00
|
|
|
break;
|
|
|
|
case QueueType::transfer:
|
2021-02-18 18:43:20 +00:00
|
|
|
index = detail::get_separate_transfer_queue_index(queue_families);
|
2021-02-18 18:25:06 +00:00
|
|
|
if (index == detail::QUEUE_INDEX_MAX_VALUE)
|
|
|
|
return detail::Result<uint32_t>{ QueueError::transfer_unavailable };
|
2020-03-08 00:19:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
2020-05-17 13:31:02 +00:00
|
|
|
return detail::Result<uint32_t>{ QueueError::invalid_queue_family_index };
|
2020-03-08 00:02:01 +00:00
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
return index;
|
2020-03-08 05:21:27 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<uint32_t> Device::get_dedicated_queue_index(QueueType type) const {
|
2021-02-18 18:25:06 +00:00
|
|
|
uint32_t index = detail::QUEUE_INDEX_MAX_VALUE;
|
2020-03-08 00:19:58 +00:00
|
|
|
switch (type) {
|
|
|
|
case QueueType::compute:
|
2021-02-18 18:43:20 +00:00
|
|
|
index = detail::get_dedicated_compute_queue_index(queue_families);
|
2021-02-18 18:25:06 +00:00
|
|
|
if (index == detail::QUEUE_INDEX_MAX_VALUE)
|
|
|
|
return detail::Result<uint32_t>{ QueueError::compute_unavailable };
|
2020-03-08 00:19:58 +00:00
|
|
|
break;
|
|
|
|
case QueueType::transfer:
|
2021-02-18 18:43:20 +00:00
|
|
|
index = detail::get_dedicated_transfer_queue_index(queue_families);
|
2021-02-18 18:25:06 +00:00
|
|
|
if (index == detail::QUEUE_INDEX_MAX_VALUE)
|
|
|
|
return detail::Result<uint32_t>{ QueueError::transfer_unavailable };
|
2020-03-08 00:19:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
2020-05-17 13:31:02 +00:00
|
|
|
return detail::Result<uint32_t>{ QueueError::invalid_queue_family_index };
|
2020-03-08 00:02:01 +00:00
|
|
|
}
|
2021-02-18 18:25:06 +00:00
|
|
|
return index;
|
2020-03-08 00:02:01 +00:00
|
|
|
}
|
|
|
|
namespace detail {
|
2021-02-18 18:43:20 +00:00
|
|
|
VkQueue get_queue(VkDevice device, uint32_t family) {
|
2020-03-08 00:02:01 +00:00
|
|
|
VkQueue out_queue;
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::vulkan_functions().fp_vkGetDeviceQueue(device, family, 0, &out_queue);
|
2020-03-08 00:02:01 +00:00
|
|
|
return out_queue;
|
|
|
|
}
|
|
|
|
} // namespace detail
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<VkQueue> Device::get_queue(QueueType type) const {
|
|
|
|
auto index = get_queue_index(type);
|
|
|
|
if (!index.has_value()) return { index.error() };
|
|
|
|
return detail::get_queue(device, index.value());
|
2020-03-08 00:02:01 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<VkQueue> Device::get_dedicated_queue(QueueType type) const {
|
|
|
|
auto index = get_dedicated_queue_index(type);
|
|
|
|
if (!index.has_value()) return { index.error() };
|
|
|
|
return detail::get_queue(device, index.value());
|
2020-03-08 00:02:01 +00:00
|
|
|
}
|
|
|
|
|
2020-01-30 08:15:10 +00:00
|
|
|
// ---- Device ---- //
|
2020-03-08 00:02:01 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
CustomQueueDescription::CustomQueueDescription(uint32_t index, uint32_t count, std::vector<float> priorities)
|
|
|
|
: index(index), count(count), priorities(priorities) {
|
|
|
|
assert(count == priorities.size());
|
2020-04-19 03:24:59 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
void destroy_device(Device device) {
|
|
|
|
detail::vulkan_functions().fp_vkDestroyDevice(device.device, device.allocation_callbacks);
|
2020-03-07 22:33:17 +00:00
|
|
|
}
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2021-03-26 23:34:10 +00:00
|
|
|
DeviceBuilder::DeviceBuilder(PhysicalDevice phys_device) { physical_device = phys_device; }
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<Device> DeviceBuilder::build() const {
|
2020-02-08 00:34:05 +00:00
|
|
|
|
2020-02-11 01:01:58 +00:00
|
|
|
std::vector<CustomQueueDescription> queue_descriptions;
|
2021-02-18 18:43:20 +00:00
|
|
|
queue_descriptions.insert(
|
|
|
|
queue_descriptions.end(), info.queue_descriptions.begin(), info.queue_descriptions.end());
|
2020-02-11 01:01:58 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
if (queue_descriptions.size() == 0) {
|
2021-03-26 23:34:10 +00:00
|
|
|
for (uint32_t i = 0; i < physical_device.queue_families.size(); i++) {
|
2021-02-18 18:43:20 +00:00
|
|
|
queue_descriptions.push_back(CustomQueueDescription{ i, 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;
|
2021-02-18 18:43:20 +00:00
|
|
|
queue_create_info.pQueuePriorities = desc.priorities.data();
|
|
|
|
queueCreateInfos.push_back(queue_create_info);
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
|
|
|
|
2021-03-26 23:34:10 +00:00
|
|
|
std::vector<const char*> extensions = physical_device.extensions_to_enable;
|
|
|
|
if (physical_device.surface != VK_NULL_HANDLE || physical_device.defer_surface_initialization)
|
2021-02-18 18:43:20 +00:00
|
|
|
extensions.push_back({ VK_KHR_SWAPCHAIN_EXTENSION_NAME });
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2021-03-26 23:34:10 +00:00
|
|
|
std::vector<VkBaseOutStructure*> pNext_chain = info.pNext_chain;
|
|
|
|
|
|
|
|
// check if certain structs were added in the pNext chain by the user
|
2020-04-19 03:24:59 +00:00
|
|
|
bool has_phys_dev_features_2 = false;
|
2021-03-26 23:34:10 +00:00
|
|
|
bool has_phys_dev_vulkan_features_11 = false;
|
|
|
|
bool has_phys_dev_vulkan_features_12 = false;
|
|
|
|
for (auto& pNext_struct : pNext_chain) {
|
2020-04-19 03:24:59 +00:00
|
|
|
if (pNext_struct->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2) {
|
|
|
|
has_phys_dev_features_2 = true;
|
|
|
|
}
|
2021-03-26 23:34:10 +00:00
|
|
|
if (pNext_struct->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES) {
|
|
|
|
has_phys_dev_vulkan_features_11 = true;
|
|
|
|
}
|
|
|
|
if (pNext_struct->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES) {
|
|
|
|
has_phys_dev_vulkan_features_12 = true;
|
|
|
|
}
|
2020-04-19 03:24:59 +00:00
|
|
|
}
|
|
|
|
|
2021-03-26 23:34:10 +00:00
|
|
|
// Add the correct structs to the pNext chain if api is 1.1/1.2 and aren't already present
|
|
|
|
// This is to guard against users who were already doing that
|
|
|
|
#if defined(VK_API_VERSION_1_1)
|
|
|
|
VkPhysicalDeviceFeatures2 local_features2{};
|
|
|
|
if (physical_device.instance_version >= VK_MAKE_VERSION(1, 1, 0) && !has_phys_dev_features_2) {
|
|
|
|
local_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
|
|
|
local_features2.features = physical_device.features;
|
|
|
|
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&local_features2));
|
|
|
|
has_phys_dev_features_2 = true;
|
|
|
|
}
|
|
|
|
#if defined(VK_API_VERSION_1_2)
|
|
|
|
VkPhysicalDeviceVulkan11Features local_features_11 = physical_device.features_11;
|
|
|
|
VkPhysicalDeviceVulkan12Features local_features_12 = physical_device.features_12;
|
|
|
|
if (physical_device.instance_version >= VK_MAKE_VERSION(1, 2, 0)) {
|
|
|
|
if (!has_phys_dev_vulkan_features_11) {
|
|
|
|
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&local_features_11));
|
|
|
|
has_phys_dev_vulkan_features_11 = true;
|
|
|
|
}
|
|
|
|
if (!has_phys_dev_vulkan_features_12) {
|
|
|
|
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&local_features_12));
|
|
|
|
has_phys_dev_vulkan_features_12 = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2020-01-30 08:15:10 +00:00
|
|
|
VkDeviceCreateInfo device_create_info = {};
|
|
|
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
2021-03-26 23:34:10 +00:00
|
|
|
detail::setup_pNext_chain(device_create_info, pNext_chain);
|
2020-01-30 08:15:10 +00:00
|
|
|
device_create_info.flags = info.flags;
|
2021-02-18 18:43:20 +00:00
|
|
|
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();
|
2021-03-26 23:34:10 +00:00
|
|
|
// VUID-VkDeviceCreateInfo-pNext-00373 - don't add pEnabledFeatures if the phys_dev_features_2 is present
|
2020-04-19 03:24:59 +00:00
|
|
|
if (!has_phys_dev_features_2) {
|
2021-03-26 23:34:10 +00:00
|
|
|
device_create_info.pEnabledFeatures = &physical_device.features;
|
2020-04-19 03:24:59 +00:00
|
|
|
}
|
2020-01-30 08:15:10 +00:00
|
|
|
|
2021-03-26 23:34:10 +00:00
|
|
|
|
2020-01-30 08:15:10 +00:00
|
|
|
Device device;
|
2021-03-26 23:34:10 +00:00
|
|
|
VkResult res = detail::vulkan_functions().fp_vkCreateDevice(
|
|
|
|
physical_device.physical_device, &device_create_info, info.allocation_callbacks, &device.device);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
2020-05-17 13:31:02 +00:00
|
|
|
return { DeviceError::failed_create_device, res };
|
2020-01-30 08:15:10 +00:00
|
|
|
}
|
2021-03-26 23:34:10 +00:00
|
|
|
device.physical_device = physical_device;
|
|
|
|
device.surface = physical_device.surface;
|
|
|
|
device.queue_families = physical_device.queue_families;
|
2020-03-07 22:33:17 +00:00
|
|
|
device.allocation_callbacks = info.allocation_callbacks;
|
2020-01-30 08:15:10 +00:00
|
|
|
return device;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
DeviceBuilder& DeviceBuilder::custom_queue_setup(std::vector<CustomQueueDescription> queue_descriptions) {
|
2020-02-11 01:01:58 +00:00
|
|
|
info.queue_descriptions = queue_descriptions;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
DeviceBuilder& DeviceBuilder::set_allocation_callbacks(VkAllocationCallbacks* callbacks) {
|
2020-03-07 22:33:17 +00:00
|
|
|
info.allocation_callbacks = callbacks;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-02-11 01:01:58 +00:00
|
|
|
|
2020-04-19 03:24:59 +00:00
|
|
|
// ---- Swapchain ---- //
|
|
|
|
|
2020-02-06 22:46:14 +00:00
|
|
|
namespace detail {
|
2020-03-08 06:26:46 +00:00
|
|
|
struct SurfaceSupportDetails {
|
|
|
|
VkSurfaceCapabilitiesKHR capabilities;
|
|
|
|
std::vector<VkSurfaceFormatKHR> formats;
|
|
|
|
std::vector<VkPresentModeKHR> present_modes;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class SurfaceSupportError {
|
|
|
|
surface_handle_null,
|
|
|
|
failed_get_surface_capabilities,
|
|
|
|
failed_enumerate_surface_formats,
|
|
|
|
failed_enumerate_present_modes
|
|
|
|
};
|
|
|
|
|
2020-05-17 13:31:02 +00:00
|
|
|
struct SurfaceSupportErrorCategory : std::error_category {
|
2021-02-18 18:43:20 +00:00
|
|
|
const char* name() const noexcept override { return "vbk_surface_support"; }
|
|
|
|
std::string message(int err) const override {
|
|
|
|
switch (static_cast<SurfaceSupportError>(err)) {
|
2020-05-17 13:31:02 +00:00
|
|
|
case SurfaceSupportError::surface_handle_null:
|
|
|
|
return "surface_handle_null";
|
|
|
|
case SurfaceSupportError::failed_get_surface_capabilities:
|
|
|
|
return "failed_get_surface_capabilities";
|
|
|
|
case SurfaceSupportError::failed_enumerate_surface_formats:
|
|
|
|
return "failed_enumerate_surface_formats";
|
|
|
|
case SurfaceSupportError::failed_enumerate_present_modes:
|
|
|
|
return "failed_enumerate_present_modes";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const SurfaceSupportErrorCategory surface_support_error_category;
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
std::error_code make_error_code(SurfaceSupportError surface_support_error) {
|
|
|
|
return { static_cast<int>(surface_support_error), detail::surface_support_error_category };
|
2020-05-17 13:31:02 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
Result<SurfaceSupportDetails> query_surface_support_details(VkPhysicalDevice phys_device, VkSurfaceKHR surface) {
|
|
|
|
if (surface == VK_NULL_HANDLE) return make_error_code(SurfaceSupportError::surface_handle_null);
|
2020-03-08 06:26:46 +00:00
|
|
|
|
|
|
|
VkSurfaceCapabilitiesKHR capabilities;
|
2021-02-18 18:43:20 +00:00
|
|
|
VkResult res = detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
2020-06-17 23:13:39 +00:00
|
|
|
phys_device, surface, &capabilities);
|
2020-03-08 06:26:46 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
2021-02-18 18:43:20 +00:00
|
|
|
return { make_error_code(SurfaceSupportError::failed_get_surface_capabilities), res };
|
2020-03-08 06:26:46 +00:00
|
|
|
}
|
2020-05-17 13:31:02 +00:00
|
|
|
|
|
|
|
std::vector<VkSurfaceFormatKHR> formats;
|
|
|
|
std::vector<VkPresentModeKHR> present_modes;
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
auto formats_ret = detail::get_vector<VkSurfaceFormatKHR>(
|
|
|
|
formats, detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
|
2020-05-17 13:31:02 +00:00
|
|
|
if (formats_ret != VK_SUCCESS)
|
2021-02-18 18:43:20 +00:00
|
|
|
return { make_error_code(SurfaceSupportError::failed_enumerate_surface_formats), formats_ret };
|
|
|
|
auto present_modes_ret = detail::get_vector<VkPresentModeKHR>(
|
|
|
|
present_modes, detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface);
|
2020-05-17 13:31:02 +00:00
|
|
|
if (present_modes_ret != VK_SUCCESS)
|
2021-02-18 18:43:20 +00:00
|
|
|
return { make_error_code(SurfaceSupportError::failed_enumerate_present_modes), present_modes_ret };
|
2020-06-08 20:28:32 +00:00
|
|
|
|
2020-05-17 13:31:02 +00:00
|
|
|
return SurfaceSupportDetails{ capabilities, formats, present_modes };
|
2020-03-08 06:26:46 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +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
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +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;
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +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-17 20:17:09 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
VkExtent2D find_extent(VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height) {
|
2020-02-06 22:46:14 +00:00
|
|
|
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-03-08 05:58:23 +00:00
|
|
|
VkExtent2D actualExtent = { desired_width, desired_height };
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2021-02-18 18:43:20 +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
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
void destroy_swapchain(Swapchain const& swapchain) {
|
2020-06-08 21:40:33 +00:00
|
|
|
if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE) {
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::vulkan_functions().fp_vkDestroySwapchainKHR(
|
2020-06-17 23:13:39 +00:00
|
|
|
swapchain.device, swapchain.swapchain, swapchain.allocation_callbacks);
|
2020-06-08 21:40:33 +00:00
|
|
|
}
|
2020-06-08 20:28:32 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder::SwapchainBuilder(Device const& device) {
|
2020-01-31 22:23:22 +00:00
|
|
|
info.device = device.device;
|
2020-03-10 03:53:10 +00:00
|
|
|
info.physical_device = device.physical_device.physical_device;
|
2020-01-31 22:23:22 +00:00
|
|
|
info.surface = device.surface;
|
2021-02-18 18:43:20 +00:00
|
|
|
auto present = device.get_queue_index(QueueType::present);
|
|
|
|
auto graphics = device.get_queue_index(QueueType::graphics);
|
2020-03-08 00:02:01 +00:00
|
|
|
// TODO: handle error of queue's not available
|
2021-02-18 18:43:20 +00:00
|
|
|
info.graphics_queue_index = present.value();
|
|
|
|
info.present_queue_index = graphics.value();
|
2021-02-18 17:46:05 +00:00
|
|
|
info.allocation_callbacks = device.allocation_callbacks;
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder::SwapchainBuilder(Device const& device, VkSurfaceKHR const surface) {
|
2020-04-19 23:59:32 +00:00
|
|
|
info.device = device.device;
|
|
|
|
info.physical_device = device.physical_device.physical_device;
|
|
|
|
info.surface = surface;
|
|
|
|
Device temp_device = device;
|
|
|
|
temp_device.surface = surface;
|
2021-02-18 18:43:20 +00:00
|
|
|
auto present = temp_device.get_queue_index(QueueType::present);
|
|
|
|
auto graphics = temp_device.get_queue_index(QueueType::graphics);
|
2020-04-19 23:59:32 +00:00
|
|
|
// TODO: handle error of queue's not available
|
2021-02-18 18:43:20 +00:00
|
|
|
info.graphics_queue_index = present.value();
|
|
|
|
info.present_queue_index = graphics.value();
|
2021-02-18 17:46:05 +00:00
|
|
|
info.allocation_callbacks = device.allocation_callbacks;
|
2020-04-19 23:59:32 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder::SwapchainBuilder(VkPhysicalDevice const physical_device,
|
2020-12-17 07:42:48 +00:00
|
|
|
VkDevice const device,
|
|
|
|
VkSurfaceKHR const surface,
|
2021-02-18 18:25:06 +00:00
|
|
|
uint32_t graphics_queue_index,
|
|
|
|
uint32_t present_queue_index) {
|
2020-10-21 19:25:48 +00:00
|
|
|
info.physical_device = physical_device;
|
2020-12-17 07:42:48 +00:00
|
|
|
info.device = device;
|
2020-10-21 19:25:48 +00:00
|
|
|
info.surface = surface;
|
2021-02-18 18:25:06 +00:00
|
|
|
info.graphics_queue_index = graphics_queue_index;
|
|
|
|
info.present_queue_index = present_queue_index;
|
|
|
|
if (graphics_queue_index == detail::QUEUE_INDEX_MAX_VALUE || present_queue_index == detail::QUEUE_INDEX_MAX_VALUE) {
|
2021-02-18 18:43:20 +00:00
|
|
|
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties>(
|
|
|
|
detail::vulkan_functions().fp_vkGetPhysicalDeviceQueueFamilyProperties, physical_device);
|
2021-02-18 18:25:06 +00:00
|
|
|
if (graphics_queue_index == detail::QUEUE_INDEX_MAX_VALUE)
|
2021-02-18 18:43:20 +00:00
|
|
|
info.graphics_queue_index = detail::get_graphics_queue_index(queue_families);
|
2021-02-18 18:25:06 +00:00
|
|
|
if (present_queue_index == detail::QUEUE_INDEX_MAX_VALUE)
|
2021-02-18 18:43:20 +00:00
|
|
|
info.present_queue_index = detail::get_present_queue_index(physical_device, surface, queue_families);
|
2020-10-26 19:17:52 +00:00
|
|
|
}
|
2020-10-21 19:25:48 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<Swapchain> SwapchainBuilder::build() const {
|
2020-04-19 23:59:32 +00:00
|
|
|
if (info.surface == VK_NULL_HANDLE) {
|
2020-05-17 13:31:02 +00:00
|
|
|
return detail::Error{ SwapchainError::surface_handle_not_provided };
|
2020-04-19 23:59:32 +00:00
|
|
|
}
|
|
|
|
|
2020-03-08 05:21:27 +00:00
|
|
|
auto desired_formats = info.desired_formats;
|
2021-02-18 18:43:20 +00:00
|
|
|
if (desired_formats.size() == 0) add_desired_formats(desired_formats);
|
2020-03-08 05:21:27 +00:00
|
|
|
auto desired_present_modes = info.desired_present_modes;
|
2021-02-18 18:43:20 +00:00
|
|
|
if (desired_present_modes.size() == 0) add_desired_present_modes(desired_present_modes);
|
2020-02-04 03:34:46 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
auto surface_support_ret = detail::query_surface_support_details(info.physical_device, info.surface);
|
|
|
|
if (!surface_support_ret.has_value())
|
2020-05-17 13:31:02 +00:00
|
|
|
return detail::Error{ SwapchainError::failed_query_surface_support_details,
|
2021-02-18 18:43:20 +00:00
|
|
|
surface_support_ret.vk_result() };
|
|
|
|
auto surface_support = surface_support_ret.value();
|
2020-01-31 22:23:22 +00:00
|
|
|
|
2020-06-08 20:28:32 +00:00
|
|
|
uint32_t image_count = surface_support.capabilities.minImageCount + 1;
|
|
|
|
if (surface_support.capabilities.maxImageCount > 0 && image_count > surface_support.capabilities.maxImageCount) {
|
|
|
|
image_count = surface_support.capabilities.maxImageCount;
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
VkSurfaceFormatKHR surface_format = detail::find_surface_format(surface_support.formats, desired_formats);
|
2020-06-08 20:28:32 +00:00
|
|
|
|
|
|
|
VkExtent2D extent =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::find_extent(surface_support.capabilities, info.desired_width, info.desired_height);
|
2020-06-08 20:28:32 +00:00
|
|
|
|
|
|
|
uint32_t image_array_layers = info.array_layer_count;
|
|
|
|
if (surface_support.capabilities.maxImageArrayLayers < info.array_layer_count)
|
|
|
|
image_array_layers = surface_support.capabilities.maxImageArrayLayers;
|
|
|
|
if (info.array_layer_count == 0) image_array_layers = 1;
|
|
|
|
|
|
|
|
uint32_t queue_family_indices[] = { info.graphics_queue_index, info.present_queue_index };
|
|
|
|
|
|
|
|
|
|
|
|
VkPresentModeKHR present_mode =
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::find_present_mode(surface_support.present_modes, desired_present_modes);
|
2020-06-08 20:28:32 +00:00
|
|
|
|
|
|
|
VkSurfaceTransformFlagBitsKHR pre_transform = info.pre_transform;
|
2021-02-18 18:43:20 +00:00
|
|
|
if (info.pre_transform == static_cast<VkSurfaceTransformFlagBitsKHR>(0))
|
2020-06-08 20:28:32 +00:00
|
|
|
pre_transform = surface_support.capabilities.currentTransform;
|
2020-01-31 22:23:22 +00:00
|
|
|
|
|
|
|
VkSwapchainCreateInfoKHR swapchain_create_info = {};
|
|
|
|
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::setup_pNext_chain(swapchain_create_info, info.pNext_chain);
|
2020-06-08 20:28:32 +00:00
|
|
|
swapchain_create_info.flags = info.create_flags;
|
2020-01-31 22:23:22 +00:00
|
|
|
swapchain_create_info.surface = info.surface;
|
2020-06-08 20:28:32 +00:00
|
|
|
swapchain_create_info.minImageCount = image_count;
|
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;
|
2020-06-08 20:28:32 +00:00
|
|
|
swapchain_create_info.imageArrayLayers = image_array_layers;
|
2020-05-26 19:33:40 +00:00
|
|
|
swapchain_create_info.imageUsage = info.image_usage_flags;
|
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;
|
|
|
|
}
|
|
|
|
|
2020-06-08 20:28:32 +00:00
|
|
|
swapchain_create_info.preTransform = pre_transform;
|
|
|
|
swapchain_create_info.compositeAlpha = info.composite_alpha;
|
2020-02-03 23:23:47 +00:00
|
|
|
swapchain_create_info.presentMode = present_mode;
|
2020-05-26 19:33:40 +00:00
|
|
|
swapchain_create_info.clipped = info.clipped;
|
2020-06-08 20:28:32 +00:00
|
|
|
swapchain_create_info.oldSwapchain = info.old_swapchain;
|
2020-02-06 22:46:14 +00:00
|
|
|
Swapchain swapchain{};
|
2021-02-18 18:43:20 +00:00
|
|
|
VkResult res = detail::vulkan_functions().fp_vkCreateSwapchainKHR(
|
2020-03-07 22:33:17 +00:00
|
|
|
info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
2020-05-17 13:31:02 +00:00
|
|
|
return detail::Error{ 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;
|
2021-02-18 18:43:20 +00:00
|
|
|
auto images = swapchain.get_images();
|
2020-04-19 03:24:59 +00:00
|
|
|
if (!images) {
|
2020-05-17 13:31:02 +00:00
|
|
|
return detail::Error{ SwapchainError::failed_get_swapchain_images };
|
2020-04-19 03:24:59 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
swapchain.image_count = static_cast<uint32_t>(images.value().size());
|
2020-03-07 22:33:17 +00:00
|
|
|
swapchain.allocation_callbacks = info.allocation_callbacks;
|
2020-01-31 22:23:22 +00:00
|
|
|
return swapchain;
|
2020-03-08 05:21:27 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<std::vector<VkImage>> Swapchain::get_images() {
|
2020-05-17 13:31:02 +00:00
|
|
|
std::vector<VkImage> swapchain_images;
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
auto swapchain_images_ret = detail::get_vector<VkImage>(
|
|
|
|
swapchain_images, detail::vulkan_functions().fp_vkGetSwapchainImagesKHR, device, swapchain);
|
2020-05-17 13:31:02 +00:00
|
|
|
if (swapchain_images_ret != VK_SUCCESS) {
|
|
|
|
return detail::Error{ SwapchainError::failed_get_swapchain_images, swapchain_images_ret };
|
2020-02-04 03:34:46 +00:00
|
|
|
}
|
2020-05-17 13:31:02 +00:00
|
|
|
return swapchain_images;
|
2020-02-04 03:34:46 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::Result<std::vector<VkImageView>> Swapchain::get_image_views() {
|
2020-04-19 03:24:59 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
auto swapchain_images_ret = get_images();
|
|
|
|
if (!swapchain_images_ret) return swapchain_images_ret.error();
|
|
|
|
auto swapchain_images = swapchain_images_ret.value();
|
2020-02-04 03:34:46 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
std::vector<VkImageView> views(swapchain_images.size());
|
2020-02-04 03:34:46 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
for (size_t i = 0; i < swapchain_images.size(); i++) {
|
2020-02-04 03:34:46 +00:00
|
|
|
VkImageViewCreateInfo createInfo = {};
|
|
|
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
2020-04-19 03:24:59 +00:00
|
|
|
createInfo.image = swapchain_images[i];
|
2020-02-04 03:34:46 +00:00
|
|
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
2020-04-19 03:24:59 +00:00
|
|
|
createInfo.format = image_format;
|
2020-02-04 03:34:46 +00:00
|
|
|
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;
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
VkResult res = detail::vulkan_functions().fp_vkCreateImageView(
|
2020-06-17 23:13:39 +00:00
|
|
|
device, &createInfo, allocation_callbacks, &views[i]);
|
2020-02-06 22:46:14 +00:00
|
|
|
if (res != VK_SUCCESS)
|
2020-05-17 13:31:02 +00:00
|
|
|
return detail::Error{ SwapchainError::failed_create_swapchain_image_views, res };
|
2020-02-04 03:34:46 +00:00
|
|
|
}
|
|
|
|
return views;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
void Swapchain::destroy_image_views(std::vector<VkImageView> const& image_views) {
|
2020-04-19 03:24:59 +00:00
|
|
|
for (auto& image_view : image_views) {
|
2021-02-18 18:43:20 +00:00
|
|
|
detail::vulkan_functions().fp_vkDestroyImageView(device, image_view, allocation_callbacks);
|
2020-04-19 03:24:59 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_old_swapchain(VkSwapchainKHR old_swapchain) {
|
2020-06-08 20:28:32 +00:00
|
|
|
info.old_swapchain = old_swapchain;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_old_swapchain(Swapchain const& swapchain) {
|
2020-06-08 20:28:32 +00:00
|
|
|
info.old_swapchain = swapchain.swapchain;
|
|
|
|
return *this;
|
2020-01-31 22:23:22 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_desired_extent(uint32_t width, uint32_t height) {
|
2020-03-08 05:58:23 +00:00
|
|
|
info.desired_width = width;
|
|
|
|
info.desired_height = height;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_desired_format(VkSurfaceFormatKHR format) {
|
|
|
|
info.desired_formats.insert(info.desired_formats.begin(), format);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::add_fallback_format(VkSurfaceFormatKHR format) {
|
|
|
|
info.desired_formats.push_back(format);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::use_default_format_selection() {
|
|
|
|
info.desired_formats.clear();
|
|
|
|
add_desired_formats(info.desired_formats);
|
2020-02-03 23:23:47 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_desired_present_mode(VkPresentModeKHR present_mode) {
|
|
|
|
info.desired_present_modes.insert(info.desired_present_modes.begin(), present_mode);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::add_fallback_present_mode(VkPresentModeKHR present_mode) {
|
|
|
|
info.desired_present_modes.push_back(present_mode);
|
2020-02-03 23:23:47 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::use_default_present_mode_selection() {
|
|
|
|
info.desired_present_modes.clear();
|
|
|
|
add_desired_present_modes(info.desired_present_modes);
|
2020-01-31 22:23:22 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_allocation_callbacks(VkAllocationCallbacks* callbacks) {
|
2020-03-07 22:33:17 +00:00
|
|
|
info.allocation_callbacks = callbacks;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_image_usage_flags(VkImageUsageFlags usage_flags) {
|
2020-05-26 19:33:40 +00:00
|
|
|
info.image_usage_flags = usage_flags;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::add_image_usage_flags(VkImageUsageFlags usage_flags) {
|
2020-05-26 19:33:40 +00:00
|
|
|
info.image_usage_flags = info.image_usage_flags | usage_flags;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::use_default_image_usage_flags() {
|
2020-05-26 19:33:40 +00:00
|
|
|
info.image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_image_array_layer_count(uint32_t array_layer_count) {
|
2020-05-26 19:33:40 +00:00
|
|
|
info.array_layer_count = array_layer_count;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_clipped(bool clipped) {
|
2020-05-26 19:33:40 +00:00
|
|
|
info.clipped = clipped;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_create_flags(VkSwapchainCreateFlagBitsKHR create_flags) {
|
2020-06-08 20:28:32 +00:00
|
|
|
info.create_flags = create_flags;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_pre_transform_flags(VkSurfaceTransformFlagBitsKHR pre_transform_flags) {
|
2020-06-08 20:28:32 +00:00
|
|
|
info.pre_transform = pre_transform_flags;
|
|
|
|
return *this;
|
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
SwapchainBuilder& SwapchainBuilder::set_composite_alpha_flags(VkCompositeAlphaFlagBitsKHR composite_alpha_flags) {
|
2020-06-08 20:28:32 +00:00
|
|
|
info.composite_alpha = composite_alpha_flags;
|
|
|
|
return *this;
|
|
|
|
}
|
2020-05-26 19:33:40 +00:00
|
|
|
|
2021-02-18 18:43:20 +00:00
|
|
|
void SwapchainBuilder::add_desired_formats(std::vector<VkSurfaceFormatKHR>& formats) const {
|
|
|
|
formats.push_back({ VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR });
|
|
|
|
formats.push_back({ VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR });
|
2020-03-08 05:21:27 +00:00
|
|
|
}
|
2021-02-18 18:43:20 +00:00
|
|
|
void SwapchainBuilder::add_desired_present_modes(std::vector<VkPresentModeKHR>& modes) const {
|
|
|
|
modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
|
|
|
|
modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
|
2020-03-08 05:21:27 +00:00
|
|
|
}
|
2020-01-31 22:23:22 +00:00
|
|
|
} // namespace vkb
|