Implemented missing instance functions, deleted surface in tests.

This commit is contained in:
Charles Giessen 2020-02-18 15:18:08 -07:00
parent b171ced11e
commit 7de79b81b1
4 changed files with 110 additions and 62 deletions

View File

@ -106,44 +106,42 @@ VkBool32 default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageS
} }
namespace detail { namespace detail {
bool check_layers_supported (std::vector<const char*> layer_names) { bool check_layer_supported (std::vector<VkLayerProperties> available_layers, const char* layer_name) {
auto available_layers = detail::get_vector<VkLayerProperties> (vkEnumerateInstanceLayerProperties); if (!layer_name) return false;
if (!available_layers.has_value ()) { for (const auto& layer_properties : available_layers) {
return false; // maybe report error? if (strcmp (layer_name, layer_properties.layerName) == 0) {
return true;
} }
}
return false;
}
bool check_layers_supported (std::vector<VkLayerProperties> available_layers, std::vector<const char*> layer_names) {
bool all_found = true; bool all_found = true;
for (const auto& layer_name : layer_names) { for (const auto& layer_name : layer_names) {
bool found = false; bool found = check_layer_supported (available_layers, layer_name);
for (const auto& layer_properties : available_layers.value ()) {
if (strcmp (layer_name, layer_properties.layerName) == 0) {
found = true;
break;
}
}
if (!found) all_found = false; if (!found) all_found = false;
} }
return all_found; return all_found;
} }
bool check_extensions_supported (std::vector<const char*> extension_names) { bool check_extension_supported (std::vector<VkExtensionProperties> available_extensions, const char* extension_name) {
auto available_extensions = if (!extension_name) return false;
detail::get_vector<VkExtensionProperties> (vkEnumerateInstanceExtensionProperties, nullptr); for (const auto& layer_properties : available_extensions) {
if (!available_extensions.has_value ()) { if (strcmp (extension_name, layer_properties.extensionName) == 0) {
return false; // maybe report error? return true;
} }
}
return false;
}
bool check_extensions_supported (std::vector<VkExtensionProperties> available_extensions,
std::vector<const char*> extension_names) {
bool all_found = true; bool all_found = true;
for (const auto& extension_name : extension_names) { for (const auto& extension_name : extension_names) {
bool found = false; bool found = check_extension_supported (available_extensions, extension_name);
for (const auto& layer_properties : available_extensions.value ()) {
if (strcmp (extension_name, layer_properties.extensionName) == 0) {
found = true;
break;
}
}
if (!found) all_found = false; if (!found) all_found = false;
} }
return all_found; return all_found;
} }
@ -156,6 +154,8 @@ void setup_pNext_chain (T& structure, std::vector<VkBaseOutStructure*> const& st
} }
structure.pNext = structs.at (0); structure.pNext = structs.at (0);
} }
const char* validation_layer_name = "VK_LAYER_KHRONOS_validation";
} // namespace detail } // namespace detail
void destroy_instance (Instance instance) { void destroy_instance (Instance instance) {
@ -165,6 +165,17 @@ void destroy_instance (Instance instance) {
vkDestroyInstance (instance.instance, nullptr); vkDestroyInstance (instance.instance, nullptr);
} }
} }
InstanceBuilder::InstanceBuilder () {
auto available_extensions =
detail::get_vector<VkExtensionProperties> (vkEnumerateInstanceExtensionProperties, nullptr);
if (available_extensions.has_value ()) {
system.available_extensions = available_extensions.value ();
}
auto available_layers = detail::get_vector<VkLayerProperties> (vkEnumerateInstanceLayerProperties);
if (available_layers.has_value ()) {
system.available_layers = available_layers.value ();
}
}
detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build () { detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build () {
@ -200,7 +211,7 @@ detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build
extensions.push_back ("VK_KHR_metal_surface"); extensions.push_back ("VK_KHR_metal_surface");
#endif #endif
} }
bool all_extensions_supported = detail::check_extensions_supported (extensions); bool all_extensions_supported = detail::check_extensions_supported (system.available_extensions, extensions);
if (!all_extensions_supported) { if (!all_extensions_supported) {
return detail::Error<InstanceError>{ InstanceError::requested_extensions_not_present }; return detail::Error<InstanceError>{ InstanceError::requested_extensions_not_present };
} }
@ -210,9 +221,9 @@ detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build
layers.push_back (layer); layers.push_back (layer);
if (info.enable_validation_layers) { if (info.enable_validation_layers) {
layers.push_back ("VK_LAYER_KHRONOS_validation"); layers.push_back (detail::validation_layer_name);
} }
bool all_layers_supported = detail::check_layers_supported (layers); bool all_layers_supported = detail::check_layers_supported (system.available_layers, layers);
if (!all_layers_supported) { if (!all_layers_supported) {
return detail::Error<InstanceError>{ InstanceError::requested_layers_not_present }; return detail::Error<InstanceError>{ InstanceError::requested_layers_not_present };
} }
@ -280,10 +291,12 @@ detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build
} }
InstanceBuilder& InstanceBuilder::set_app_name (const char* app_name) { InstanceBuilder& InstanceBuilder::set_app_name (const char* app_name) {
if (!app_name) return *this;
info.app_name = app_name; info.app_name = app_name;
return *this; return *this;
} }
InstanceBuilder& InstanceBuilder::set_engine_name (const char* engine_name) { InstanceBuilder& InstanceBuilder::set_engine_name (const char* engine_name) {
if (!engine_name) return *this;
info.engine_name = engine_name; info.engine_name = engine_name;
return *this; return *this;
} }
@ -300,17 +313,38 @@ InstanceBuilder& InstanceBuilder::set_api_version (uint32_t major, uint32_t mino
return *this; return *this;
} }
InstanceBuilder& InstanceBuilder::add_layer (const char* layer_name) { InstanceBuilder& InstanceBuilder::add_layer (const char* layer_name) {
if (!layer_name) return *this;
info.layers.push_back (layer_name); info.layers.push_back (layer_name);
return *this; return *this;
} }
InstanceBuilder& InstanceBuilder::add_extension (const char* extension_name) { InstanceBuilder& InstanceBuilder::add_extension (const char* extension_name) {
if (!extension_name) return *this;
info.extensions.push_back (extension_name); info.extensions.push_back (extension_name);
return *this; return *this;
} }
bool InstanceBuilder::check_and_add_layer (const char* layer_name) {
if (!layer_name) return false;
bool available = detail::check_layer_supported (system.available_layers, layer_name);
if (available) info.layers.push_back (layer_name);
return available;
}
bool InstanceBuilder::check_and_add_extension (const char* extension_name) {
if (!extension_name) return false;
bool available = detail::check_extension_supported (system.available_extensions, extension_name);
if (available) info.extensions.push_back (extension_name);
return available;
}
InstanceBuilder& InstanceBuilder::setup_validation_layers (bool enable_validation) { InstanceBuilder& InstanceBuilder::setup_validation_layers (bool enable_validation) {
info.enable_validation_layers = enable_validation; info.enable_validation_layers = enable_validation;
return *this; return *this;
} }
bool InstanceBuilder::check_and_setup_validation_layers (bool enable_validation) {
bool available =
detail::check_extension_supported (system.available_extensions, detail::validation_layer_name);
setup_validation_layers (available);
return available;
}
InstanceBuilder& InstanceBuilder::set_default_debug_messenger () { InstanceBuilder& InstanceBuilder::set_default_debug_messenger () {
info.use_debug_messenger = true; info.use_debug_messenger = true;
info.debug_callback = default_debug_callback; info.debug_callback = default_debug_callback;
@ -394,25 +428,6 @@ Expected<SurfaceSupportDetails, detail::Error<SurfaceSupportError>> query_surfac
return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () }; return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () };
} }
// Given a list of formats, return a format supported by the hardware, else return VK_FORMAT_UNDEFINED
VkFormat find_supported_format (VkPhysicalDevice physical_device,
const std::vector<VkFormat>& candidates,
VkImageTiling tiling,
VkFormatFeatureFlags features) {
for (VkFormat format : candidates) {
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties (physical_device, format, &props);
if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) {
return format;
} else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) {
return format;
}
}
return VK_FORMAT_UNDEFINED;
}
std::vector<const char*> check_device_extension_support ( std::vector<const char*> check_device_extension_support (
VkPhysicalDevice device, std::vector<const char*> desired_extensions) { VkPhysicalDevice device, std::vector<const char*> desired_extensions) {
auto available_extensions = auto available_extensions =
@ -491,12 +506,15 @@ bool supports_features (VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeat
} }
} // namespace detail } // namespace detail
// finds the first queue which supports graphics operations. returns -1 if none is found
int get_graphics_queue_index (std::vector<VkQueueFamilyProperties> const& families) { int get_graphics_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
for (int i = 0; i < families.size (); i++) { for (int i = 0; i < families.size (); i++) {
if (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) return i; if (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) return i;
} }
return -1; return -1;
} }
// finds a compute queue which is distinct from the graphics queue and tries to find one without transfer support
// returns -1 if none is found
int get_distinct_compute_queue_index (std::vector<VkQueueFamilyProperties> const& families) { int get_distinct_compute_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
int compute = -1; int compute = -1;
for (int i = 0; i < families.size (); i++) { for (int i = 0; i < families.size (); i++) {
@ -511,6 +529,8 @@ int get_distinct_compute_queue_index (std::vector<VkQueueFamilyProperties> const
} }
return compute; return compute;
} }
// finds a transfer queue which is distinct from the graphics queue and tries to find one without compute support
// returns -1 if none is found
int get_distinct_transfer_queue_index (std::vector<VkQueueFamilyProperties> const& families) { int get_distinct_transfer_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
int transfer = -1; int transfer = -1;
for (int i = 0; i < families.size (); i++) { for (int i = 0; i < families.size (); i++) {
@ -523,8 +543,29 @@ int get_distinct_transfer_queue_index (std::vector<VkQueueFamilyProperties> cons
} }
} }
} }
return transfer;
}
// finds the first queue which supports only compute (not graphics or transfer). returns -1 if none is found
int get_dedicated_compute_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
for (int i = 0; i < families.size (); i++) {
if ((families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) &&
(families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 &&
(families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) == 0)
return i;
}
return -1; return -1;
} }
// finds the first queue which supports only transfer (not graphics or compute). returns -1 if none is found
int get_dedicated_transfer_queue_index (std::vector<VkQueueFamilyProperties> const& families) {
for (int i = 0; i < families.size (); i++) {
if ((families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) &&
(families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 &&
(families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0)
return i;
}
return -1;
}
// finds the first queue which supports presenting. returns -1 if none is found
int get_present_queue_index (VkPhysicalDevice const phys_device, int get_present_queue_index (VkPhysicalDevice const phys_device,
VkSurfaceKHR const surface, VkSurfaceKHR const surface,
std::vector<VkQueueFamilyProperties> const& families) { std::vector<VkQueueFamilyProperties> const& families) {

View File

@ -124,6 +124,8 @@ void destroy_instance (Instance instance); // release instance resources
class InstanceBuilder { class InstanceBuilder {
public: public:
InstanceBuilder(); //automatically gets available layers and extensions
detail::Expected<Instance, detail::Error<InstanceError>> build (); // use builder pattern detail::Expected<Instance, detail::Error<InstanceError>> build (); // use builder pattern
InstanceBuilder& set_app_name (const char* app_name); InstanceBuilder& set_app_name (const char* app_name);
@ -133,11 +135,11 @@ class InstanceBuilder {
InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch); InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch);
InstanceBuilder& set_api_version (uint32_t major, uint32_t minor, uint32_t patch); InstanceBuilder& set_api_version (uint32_t major, uint32_t minor, uint32_t patch);
InstanceBuilder& add_layer (const char* app_name); InstanceBuilder& add_layer (const char* layer_name);
InstanceBuilder& add_extension (const char* app_name); InstanceBuilder& add_extension (const char* extension_name);
bool check_and_add_layer (const char* app_name); bool check_and_add_layer (const char* layer_name);
bool check_and_add_extension (const char* app_name); bool check_and_add_extension (const char* extension_name);
InstanceBuilder& setup_validation_layers (bool enable_validation = true); InstanceBuilder& setup_validation_layers (bool enable_validation = true);
InstanceBuilder& set_headless (bool headless = false); InstanceBuilder& set_headless (bool headless = false);
@ -189,6 +191,11 @@ class InstanceBuilder {
bool use_debug_messenger = false; bool use_debug_messenger = false;
bool headless_context = false; bool headless_context = false;
} info; } info;
struct SystemInfo {
std::vector<VkLayerProperties> available_layers;
std::vector<VkExtensionProperties> available_extensions;
} system;
}; };
const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s); const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s);

View File

@ -10,29 +10,24 @@
#include "../src/VkBootstrap.h" #include "../src/VkBootstrap.h"
GLFWwindow* create_window_glfw (bool resize = true) GLFWwindow* create_window_glfw (bool resize = true) {
{
glfwInit (); glfwInit ();
glfwWindowHint (GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint (GLFW_CLIENT_API, GLFW_NO_API);
if (!resize) glfwWindowHint (GLFW_RESIZABLE, GLFW_FALSE); if (!resize) glfwWindowHint (GLFW_RESIZABLE, GLFW_FALSE);
return glfwCreateWindow (640, 480, "Vulkan Triangle", NULL, NULL); return glfwCreateWindow (640, 480, "Vulkan Triangle", NULL, NULL);
} }
void destroy_window_glfw (GLFWwindow* window) void destroy_window_glfw (GLFWwindow* window) {
{
glfwDestroyWindow (window); glfwDestroyWindow (window);
glfwTerminate (); glfwTerminate ();
} }
VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window) VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window) {
{
VkSurfaceKHR surface = nullptr; VkSurfaceKHR surface = nullptr;
VkResult err = glfwCreateWindowSurface (instance, window, NULL, &surface); VkResult err = glfwCreateWindowSurface (instance, window, NULL, &surface);
if (err) if (err) {
{
const char* error_msg; const char* error_msg;
int ret = glfwGetError (&error_msg); int ret = glfwGetError (&error_msg);
if (ret != 0) if (ret != 0) {
{
std::cout << ret << " "; std::cout << ret << " ";
if (error_msg != nullptr) std::cout << error_msg; if (error_msg != nullptr) std::cout << error_msg;
std::cout << "\n"; std::cout << "\n";
@ -41,3 +36,6 @@ VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window)
} }
return surface; return surface;
} }
void destroy_surface (VkInstance instance, VkSurfaceKHR surface) {
vkDestroySurfaceKHR (instance, surface, nullptr);
}

View File

@ -31,6 +31,7 @@ int test_happy_path () {
// possible swapchain creation... // possible swapchain creation...
vkb::destroy_device (device); vkb::destroy_device (device);
destroy_surface (instance.instance, surface);
vkb::destroy_instance (instance); vkb::destroy_instance (instance);
destroy_window_glfw (window); destroy_window_glfw (window);
return 0; return 0;
@ -107,6 +108,7 @@ int test_physical_device_selection () {
if (!phys_dev_ret.has_value ()) { if (!phys_dev_ret.has_value ()) {
return -1; return -1;
} }
destroy_surface (instance.instance, surface);
vkb::destroy_instance (instance); vkb::destroy_instance (instance);
destroy_window_glfw (window); destroy_window_glfw (window);
return 0; return 0;
@ -139,8 +141,8 @@ int test_device_creation () {
printf ("couldn't create device %i\n", static_cast<uint32_t> (dev_ret.error ().type)); printf ("couldn't create device %i\n", static_cast<uint32_t> (dev_ret.error ().type));
return -1; return -1;
} }
vkb::destroy_device (dev_ret.value ()); vkb::destroy_device (dev_ret.value ());
destroy_surface (instance.instance, surface);
vkb::destroy_instance (instance); vkb::destroy_instance (instance);
destroy_window_glfw (window); destroy_window_glfw (window);
return 0; return 0;