mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-22 15:24:34 +00:00
Fixed up swapchain, added an example based on vulkan-tutorial
Now there is a concise example of the library in use all the way to presenting. Needs to be rewritten to remove exceptions, but for first pass its good enough.
This commit is contained in:
parent
37bc741658
commit
39a3c37465
@ -25,4 +25,13 @@ target_link_libraries(vk-bootstrap-test vk-bootstrap)
|
|||||||
target_link_libraries(vk-bootstrap-test glfw)
|
target_link_libraries(vk-bootstrap-test glfw)
|
||||||
target_link_libraries(vk-bootstrap-test Catch2)
|
target_link_libraries(vk-bootstrap-test Catch2)
|
||||||
|
|
||||||
|
add_executable(vk-bootstrap-triangle tests/triangle.cpp)
|
||||||
|
target_link_libraries(vk-bootstrap-triangle vk-bootstrap)
|
||||||
|
target_link_libraries(vk-bootstrap-triangle glfw)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET vk-bootstrap-triangle POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tests/shaders ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
endif()
|
endif()
|
@ -160,21 +160,17 @@ detail::Expected<Instance, VkResult> InstanceBuilder::build ()
|
|||||||
{
|
{
|
||||||
extensions.push_back (VK_KHR_SURFACE_EXTENSION_NAME);
|
extensions.push_back (VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
extensions.push_back (VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
extensions.push_back ("VK_KHR_win32_surface");
|
||||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
#elif defined(__ANDROID__)
|
||||||
extensions.push_back (VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
extensions.push_back (VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
||||||
#elif defined(_DIRECT2DISPLAY)
|
#elif defined(_DIRECT2DISPLAY)
|
||||||
extensions.push_back (VK_KHR_DISPLAY_EXTENSION_NAME);
|
extensions.push_back (VK_KHR_DISPLAY_EXTENSION_NAME);
|
||||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
#elif defined(__linux__)
|
||||||
extensions.push_back (VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
extensions.push_back ("VK_KHR_xcb_surface");
|
||||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
extensions.push_back ("VK_KHR_xlib_surface");
|
||||||
extensions.push_back (VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
extensions.push_back ("VK_KHR_wayland_surface");
|
||||||
#elif defined(VK_USE_PLATFORM_X11_HKR)
|
#elif defined(__APPLE__)
|
||||||
extensions.push_back (VK_KHR_X11_SURFACE_EXTENSION_NAME);
|
extensions.push_back ("VK_KHR_metal_surface");
|
||||||
#elif defined(VK_USE_PLATFORM_IOS_MVK)
|
|
||||||
extensions.push_back (VK_MVK_IOS_SURFACE_EXTENSION_NAME);
|
|
||||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
|
||||||
extensions.push_back (VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
std::vector<const char*> layers;
|
std::vector<const char*> layers;
|
||||||
@ -188,7 +184,7 @@ detail::Expected<Instance, VkResult> InstanceBuilder::build ()
|
|||||||
bool all_layers_supported = detail::check_layers_supported (layers);
|
bool all_layers_supported = detail::check_layers_supported (layers);
|
||||||
if (!all_layers_supported)
|
if (!all_layers_supported)
|
||||||
{
|
{
|
||||||
return detail::Error<VkResult>{ VK_ERROR_LAYER_NOT_PRESENT, "Not all layers supported!" };
|
return detail::Error{ VK_ERROR_LAYER_NOT_PRESENT, "Not all layers supported!" };
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
|
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
|
||||||
@ -236,7 +232,7 @@ detail::Expected<Instance, VkResult> InstanceBuilder::build ()
|
|||||||
|
|
||||||
Instance instance;
|
Instance instance;
|
||||||
VkResult res = vkCreateInstance (&instance_create_info, nullptr, &instance.instance);
|
VkResult res = vkCreateInstance (&instance_create_info, nullptr, &instance.instance);
|
||||||
if (res != VK_SUCCESS) return detail::Error<VkResult>{ res, "Failed to create instance" };
|
if (res != VK_SUCCESS) return detail::Error{ res, "Failed to create instance" };
|
||||||
|
|
||||||
if (info.use_debug_messenger)
|
if (info.use_debug_messenger)
|
||||||
{
|
{
|
||||||
@ -248,7 +244,7 @@ detail::Expected<Instance, VkResult> InstanceBuilder::build ()
|
|||||||
&instance.debug_messenger);
|
&instance.debug_messenger);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
return detail::Error<VkResult>{ res, "Failed to create setup debug callback" };
|
return detail::Error{ res, "Failed to create setup debug callback" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +366,7 @@ Expected<SurfaceSupportDetails, VkResult> query_surface_support_details (
|
|||||||
VkPhysicalDevice phys_device, VkSurfaceKHR surface)
|
VkPhysicalDevice phys_device, VkSurfaceKHR surface)
|
||||||
{
|
{
|
||||||
if (surface == VK_NULL_HANDLE)
|
if (surface == VK_NULL_HANDLE)
|
||||||
return Error<VkResult>{ VK_ERROR_INITIALIZATION_FAILED, "surface handle was null" };
|
return Error{ VK_ERROR_INITIALIZATION_FAILED, "surface handle was null" };
|
||||||
|
|
||||||
VkSurfaceCapabilitiesKHR capabilities;
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities);
|
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities);
|
||||||
@ -386,11 +382,11 @@ Expected<SurfaceSupportDetails, VkResult> query_surface_support_details (
|
|||||||
auto formats = detail::get_vector<VkSurfaceFormatKHR> (
|
auto formats = detail::get_vector<VkSurfaceFormatKHR> (
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
|
vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
|
||||||
if (!formats.has_value ())
|
if (!formats.has_value ())
|
||||||
return detail::Error<VkResult>{ formats.error ().error_code, "Couldn't get surface formats" };
|
return detail::Error{ formats.error ().error_code, "Couldn't get surface formats" };
|
||||||
auto present_modes = detail::get_vector<VkPresentModeKHR> (
|
auto present_modes = detail::get_vector<VkPresentModeKHR> (
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface);
|
vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface);
|
||||||
if (!present_modes.has_value ())
|
if (!present_modes.has_value ())
|
||||||
return detail::Error<VkResult>{ formats.error ().error_code, "Couldn't get surface present modes" };
|
return detail::Error{ formats.error ().error_code, "Couldn't get surface present modes" };
|
||||||
|
|
||||||
return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () };
|
return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () };
|
||||||
}
|
}
|
||||||
@ -417,24 +413,23 @@ VkFormat find_supported_format (
|
|||||||
return VK_FORMAT_UNDEFINED;
|
return VK_FORMAT_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_device_extension_support (VkPhysicalDevice device, std::vector<std::string> extensions)
|
std::vector<std::string> check_device_extension_support (
|
||||||
|
VkPhysicalDevice device, std::vector<std::string> desired_extensions)
|
||||||
{
|
{
|
||||||
auto available_extensions =
|
auto available_extensions =
|
||||||
detail::get_vector<VkExtensionProperties> (vkEnumerateDeviceExtensionProperties, device, nullptr);
|
detail::get_vector<VkExtensionProperties> (vkEnumerateDeviceExtensionProperties, device, nullptr);
|
||||||
if (!available_extensions.has_value ()) return false; // maybe handle error
|
if (!available_extensions.has_value ()) return {};
|
||||||
|
|
||||||
bool all_available = true;
|
std::vector<std::string> extensions_to_enable;
|
||||||
for (const auto& extension : available_extensions.value ())
|
for (const auto& extension : available_extensions.value ())
|
||||||
{
|
{
|
||||||
bool found = false;
|
for (auto& req_ext : desired_extensions)
|
||||||
for (auto& req_ext : extensions)
|
|
||||||
{
|
{
|
||||||
if (req_ext == extension.extensionName) found = true;
|
if (req_ext == extension.extensionName) extensions_to_enable.push_back (req_ext);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!found) all_available = false;
|
|
||||||
}
|
}
|
||||||
return all_available;
|
return extensions_to_enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::QueueFamilies find_queue_families (VkPhysicalDevice phys_device, VkSurfaceKHR surface)
|
detail::QueueFamilies find_queue_families (VkPhysicalDevice phys_device, VkSurfaceKHR surface)
|
||||||
@ -571,13 +566,15 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable (VkP
|
|||||||
suitable = Suitable::no;
|
suitable = Suitable::no;
|
||||||
if (criteria.require_present && indices.present == -1) suitable = Suitable::no;
|
if (criteria.require_present && indices.present == -1) suitable = Suitable::no;
|
||||||
|
|
||||||
bool required_extensions_supported =
|
auto required_extensions_supported =
|
||||||
detail::check_device_extension_support (phys_device, criteria.required_extensions);
|
detail::check_device_extension_support (phys_device, criteria.required_extensions);
|
||||||
if (!required_extensions_supported) suitable = Suitable::no;
|
if (required_extensions_supported.size () != criteria.required_extensions.size ())
|
||||||
|
suitable = Suitable::no;
|
||||||
|
|
||||||
bool desired_extensions_supported =
|
auto desired_extensions_supported =
|
||||||
detail::check_device_extension_support (phys_device, criteria.desired_extensions);
|
detail::check_device_extension_support (phys_device, criteria.desired_extensions);
|
||||||
if (!desired_extensions_supported) suitable = Suitable::partial;
|
if (desired_extensions_supported.size () != criteria.desired_extensions.size ())
|
||||||
|
suitable = Suitable::partial;
|
||||||
|
|
||||||
|
|
||||||
bool swapChainAdequate = false;
|
bool swapChainAdequate = false;
|
||||||
@ -647,7 +644,7 @@ detail::Expected<PhysicalDevice, VkResult> PhysicalDeviceSelector::select ()
|
|||||||
auto physical_devices = detail::get_vector<VkPhysicalDevice> (vkEnumeratePhysicalDevices, info.instance);
|
auto physical_devices = detail::get_vector<VkPhysicalDevice> (vkEnumeratePhysicalDevices, info.instance);
|
||||||
if (!physical_devices.has_value ())
|
if (!physical_devices.has_value ())
|
||||||
{
|
{
|
||||||
return detail::Error<VkResult>{ physical_devices.error ().error_code, "Failed to find physical devices" };
|
return detail::Error{ physical_devices.error ().error_code, "Failed to find physical devices" };
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicalDevice physical_device;
|
PhysicalDevice physical_device;
|
||||||
@ -667,13 +664,24 @@ detail::Expected<PhysicalDevice, VkResult> PhysicalDeviceSelector::select ()
|
|||||||
|
|
||||||
if (physical_device.phys_device == VK_NULL_HANDLE)
|
if (physical_device.phys_device == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
return detail::Error<VkResult>{ VK_ERROR_INITIALIZATION_FAILED, "Failed to find a suitable GPU!" };
|
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to find a suitable GPU!" };
|
||||||
}
|
}
|
||||||
detail::populate_physical_device_details (physical_device);
|
detail::populate_physical_device_details (physical_device);
|
||||||
|
physical_device.surface = info.surface;
|
||||||
|
|
||||||
physical_device.physical_device_features = criteria.required_features;
|
physical_device.physical_device_features = criteria.required_features;
|
||||||
|
|
||||||
physical_device.queue_family_properties =
|
physical_device.queue_family_properties =
|
||||||
detail::find_queue_families (physical_device.phys_device, info.surface);
|
detail::find_queue_families (physical_device.phys_device, info.surface);
|
||||||
|
|
||||||
|
physical_device.extensions_to_enable.insert (physical_device.extensions_to_enable.end (),
|
||||||
|
criteria.required_extensions.begin (),
|
||||||
|
criteria.required_extensions.end ());
|
||||||
|
auto desired_extensions_supported =
|
||||||
|
detail::check_device_extension_support (physical_device.phys_device, criteria.desired_extensions);
|
||||||
|
physical_device.extensions_to_enable.insert (physical_device.extensions_to_enable.end (),
|
||||||
|
desired_extensions_supported.begin (),
|
||||||
|
desired_extensions_supported.end ());
|
||||||
return physical_device;
|
return physical_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,7 +766,11 @@ struct QueueFamily
|
|||||||
int32_t family;
|
int32_t family;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
};
|
};
|
||||||
DeviceBuilder::DeviceBuilder (PhysicalDevice device) { info.physical_device = device; }
|
DeviceBuilder::DeviceBuilder (PhysicalDevice phys_device)
|
||||||
|
{
|
||||||
|
info.physical_device = phys_device;
|
||||||
|
info.extensions = phys_device.extensions_to_enable;
|
||||||
|
}
|
||||||
|
|
||||||
detail::Expected<Device, VkResult> DeviceBuilder::build ()
|
detail::Expected<Device, VkResult> DeviceBuilder::build ()
|
||||||
{
|
{
|
||||||
@ -787,8 +799,8 @@ detail::Expected<Device, VkResult> DeviceBuilder::build ()
|
|||||||
std::vector<const char*> extensions;
|
std::vector<const char*> extensions;
|
||||||
for (auto& ext : info.extensions)
|
for (auto& ext : info.extensions)
|
||||||
extensions.push_back (ext.c_str ());
|
extensions.push_back (ext.c_str ());
|
||||||
// if (info.physical_device.surface != VK_NULL_HANDLE)
|
if (info.physical_device.surface != VK_NULL_HANDLE)
|
||||||
// extensions.push_back ({ VK_KHR_SWAPCHAIN_EXTENSION_NAME });
|
extensions.push_back ({ VK_KHR_SWAPCHAIN_EXTENSION_NAME });
|
||||||
|
|
||||||
VkDeviceCreateInfo device_create_info = {};
|
VkDeviceCreateInfo device_create_info = {};
|
||||||
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
@ -805,8 +817,11 @@ detail::Expected<Device, VkResult> DeviceBuilder::build ()
|
|||||||
vkCreateDevice (info.physical_device.phys_device, &device_create_info, nullptr, &device.device);
|
vkCreateDevice (info.physical_device.phys_device, &device_create_info, nullptr, &device.device);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
return detail::Error<VkResult>{ res, "Couldn't create device" };
|
return detail::Error{ res, "Couldn't create device" };
|
||||||
}
|
}
|
||||||
|
device.allocator = info.allocator;
|
||||||
|
device.physical_device = info.physical_device;
|
||||||
|
device.surface = info.physical_device.surface;
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,6 +833,27 @@ template <typename T> DeviceBuilder& DeviceBuilder::add_pNext (T* structure)
|
|||||||
|
|
||||||
// ---- Queue ---- //
|
// ---- Queue ---- //
|
||||||
|
|
||||||
|
uint32_t get_queue_index_present (Device const& device)
|
||||||
|
{
|
||||||
|
return device.physical_device.queue_family_properties.present;
|
||||||
|
}
|
||||||
|
uint32_t get_queue_index_graphics (Device const& device)
|
||||||
|
{
|
||||||
|
return device.physical_device.queue_family_properties.graphics;
|
||||||
|
}
|
||||||
|
uint32_t get_queue_index_compute (Device const& device)
|
||||||
|
{
|
||||||
|
return device.physical_device.queue_family_properties.compute;
|
||||||
|
}
|
||||||
|
uint32_t get_queue_index_transfer (Device const& device)
|
||||||
|
{
|
||||||
|
return device.physical_device.queue_family_properties.transfer;
|
||||||
|
}
|
||||||
|
uint32_t get_queue_index_sparse (Device const& device)
|
||||||
|
{
|
||||||
|
return device.physical_device.queue_family_properties.sparse;
|
||||||
|
}
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
VkQueue get_queue (Device const& device, uint32_t family, uint32_t index)
|
VkQueue get_queue (Device const& device, uint32_t family, uint32_t index)
|
||||||
@ -834,63 +870,67 @@ detail::Expected<VkQueue, VkResult> get_queue_present (Device const& device)
|
|||||||
detail::Expected<VkQueue, VkResult> get_queue_graphics (Device const& device, uint32_t index)
|
detail::Expected<VkQueue, VkResult> get_queue_graphics (Device const& device, uint32_t index)
|
||||||
{
|
{
|
||||||
if (index >= device.physical_device.queue_family_properties.count_graphics)
|
if (index >= device.physical_device.queue_family_properties.count_graphics)
|
||||||
return detail::Error<VkResult>{ VK_ERROR_INITIALIZATION_FAILED,
|
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested graphics queue index is out of bounds" };
|
||||||
"requested graphics queue index is out of bounds" };
|
|
||||||
return detail::get_queue (device, device.physical_device.queue_family_properties.graphics, index);
|
return detail::get_queue (device, device.physical_device.queue_family_properties.graphics, index);
|
||||||
}
|
}
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_compute (Device const& device, uint32_t index)
|
detail::Expected<VkQueue, VkResult> get_queue_compute (Device const& device, uint32_t index)
|
||||||
{
|
{
|
||||||
if (index >= device.physical_device.queue_family_properties.count_compute)
|
if (index >= device.physical_device.queue_family_properties.count_compute)
|
||||||
return detail::Error<VkResult>{ VK_ERROR_INITIALIZATION_FAILED,
|
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested compute queue index is out of bounds" };
|
||||||
"requested compute queue index is out of bounds" };
|
|
||||||
return detail::get_queue (device, device.physical_device.queue_family_properties.compute, index);
|
return detail::get_queue (device, device.physical_device.queue_family_properties.compute, index);
|
||||||
}
|
}
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_transfer (Device const& device, uint32_t index)
|
detail::Expected<VkQueue, VkResult> get_queue_transfer (Device const& device, uint32_t index)
|
||||||
{
|
{
|
||||||
if (index >= device.physical_device.queue_family_properties.count_transfer)
|
if (index >= device.physical_device.queue_family_properties.count_transfer)
|
||||||
return detail::Error<VkResult>{ VK_ERROR_INITIALIZATION_FAILED,
|
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested transfer queue index is out of bounds" };
|
||||||
"requested transfer queue index is out of bounds" };
|
|
||||||
return detail::get_queue (device, device.physical_device.queue_family_properties.transfer, index);
|
return detail::get_queue (device, device.physical_device.queue_family_properties.transfer, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_sparse (Device const& device, uint32_t index)
|
detail::Expected<VkQueue, VkResult> get_queue_sparse (Device const& device, uint32_t index)
|
||||||
{
|
{
|
||||||
if (index >= device.physical_device.queue_family_properties.count_sparse)
|
if (index >= device.physical_device.queue_family_properties.count_sparse)
|
||||||
return detail::Error<VkResult>{ VK_ERROR_INITIALIZATION_FAILED,
|
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested sparse queue index is out of bounds" };
|
||||||
"requested sparse queue index is out of bounds" };
|
|
||||||
return detail::get_queue (device, device.physical_device.queue_family_properties.sparse, index);
|
return detail::get_queue (device, device.physical_device.queue_family_properties.sparse, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector<VkSurfaceFormatKHR> const& availableFormats)
|
VkSurfaceFormatKHR find_surface_format (std::vector<VkSurfaceFormatKHR> const& available_formats,
|
||||||
|
std::vector<VkSurfaceFormatKHR> const& desired_formats)
|
||||||
{
|
{
|
||||||
for (const auto& availableFormat : availableFormats)
|
for (auto const& desired_format : desired_formats)
|
||||||
{
|
{
|
||||||
if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
for (auto const& available_format : available_formats)
|
||||||
{
|
{
|
||||||
return availableFormat;
|
// finds the first format that is desired and available
|
||||||
|
if (desired_format.format == available_format.format &&
|
||||||
|
desired_format.colorSpace == available_format.colorSpace)
|
||||||
|
{
|
||||||
|
return desired_format;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return availableFormats[0];
|
// use the first available one if any desired formats aren't found
|
||||||
|
return available_formats[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPresentModeKHR choose_swap_present_mode (std::vector<VkPresentModeKHR> const& availablePresentModes)
|
VkPresentModeKHR find_present_mode (std::vector<VkPresentModeKHR> const& available_resent_modes,
|
||||||
|
std::vector<VkPresentModeKHR> const& desired_present_modes)
|
||||||
{
|
{
|
||||||
for (const auto& availablePresentMode : availablePresentModes)
|
for (auto const& desired_pm : desired_present_modes)
|
||||||
{
|
{
|
||||||
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
for (auto const& available_pm : available_resent_modes)
|
||||||
{
|
{
|
||||||
return availablePresentMode;
|
// finds the first present mode that is desired and available
|
||||||
|
if (desired_pm == available_pm) return desired_pm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// only present mode required, use as a fallback
|
||||||
return VK_PRESENT_MODE_FIFO_KHR;
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkExtent2D choose_swap_extent (
|
VkExtent2D find_extent (VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height)
|
||||||
VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height)
|
|
||||||
{
|
{
|
||||||
if (capabilities.currentExtent.width != UINT32_MAX)
|
if (capabilities.currentExtent.width != UINT32_MAX)
|
||||||
{
|
{
|
||||||
@ -923,12 +963,12 @@ detail::Expected<Swapchain, VkResult> SwapchainBuilder::build ()
|
|||||||
{
|
{
|
||||||
auto surface_support =
|
auto surface_support =
|
||||||
detail::query_surface_support_details (info.physical_device.phys_device, info.surface);
|
detail::query_surface_support_details (info.physical_device.phys_device, info.surface);
|
||||||
if (!surface_support.has_value ())
|
if (!surface_support.has_value ()) return surface_support.error ();
|
||||||
return detail::Error<VkResult>{ surface_support.error ().error_code, "can't get surface support" };
|
VkSurfaceFormatKHR surface_format =
|
||||||
VkSurfaceFormatKHR surfaceFormat =
|
detail::find_surface_format (surface_support.value ().formats, info.desired_formats);
|
||||||
detail::choose_swapchain_surface_format (surface_support.value ().formats);
|
VkPresentModeKHR present_mode =
|
||||||
VkPresentModeKHR presentMode = detail::choose_swap_present_mode (surface_support.value ().present_modes);
|
detail::find_present_mode (surface_support.value ().present_modes, info.desired_present_modes);
|
||||||
VkExtent2D extent = detail::choose_swap_extent (
|
VkExtent2D extent = detail::find_extent (
|
||||||
surface_support.value ().capabilities, info.desired_width, info.desired_height);
|
surface_support.value ().capabilities, info.desired_width, info.desired_height);
|
||||||
|
|
||||||
uint32_t imageCount = surface_support.value ().capabilities.minImageCount + 1;
|
uint32_t imageCount = surface_support.value ().capabilities.minImageCount + 1;
|
||||||
@ -943,8 +983,8 @@ detail::Expected<Swapchain, VkResult> SwapchainBuilder::build ()
|
|||||||
swapchain_create_info.surface = info.surface;
|
swapchain_create_info.surface = info.surface;
|
||||||
|
|
||||||
swapchain_create_info.minImageCount = imageCount;
|
swapchain_create_info.minImageCount = imageCount;
|
||||||
swapchain_create_info.imageFormat = surfaceFormat.format;
|
swapchain_create_info.imageFormat = surface_format.format;
|
||||||
swapchain_create_info.imageColorSpace = surfaceFormat.colorSpace;
|
swapchain_create_info.imageColorSpace = surface_format.colorSpace;
|
||||||
swapchain_create_info.imageExtent = extent;
|
swapchain_create_info.imageExtent = extent;
|
||||||
swapchain_create_info.imageArrayLayers = 1;
|
swapchain_create_info.imageArrayLayers = 1;
|
||||||
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
@ -967,19 +1007,23 @@ detail::Expected<Swapchain, VkResult> SwapchainBuilder::build ()
|
|||||||
|
|
||||||
swapchain_create_info.preTransform = surface_support.value ().capabilities.currentTransform;
|
swapchain_create_info.preTransform = surface_support.value ().capabilities.currentTransform;
|
||||||
swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
swapchain_create_info.presentMode = presentMode;
|
swapchain_create_info.presentMode = present_mode;
|
||||||
swapchain_create_info.clipped = VK_TRUE;
|
swapchain_create_info.clipped = VK_TRUE;
|
||||||
swapchain_create_info.oldSwapchain = info.old_swapchain;
|
swapchain_create_info.oldSwapchain = info.old_swapchain;
|
||||||
Swapchain swapchain;
|
Swapchain swapchain;
|
||||||
VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain);
|
VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
return detail::Error<VkResult>{ res, "Failed to create swapchain" };
|
return detail::Error{ res, "Failed to create swapchain" };
|
||||||
}
|
}
|
||||||
auto swapchain_images =
|
auto swapchain_images =
|
||||||
detail::get_vector<VkImage> (vkGetSwapchainImagesKHR, info.device, swapchain.swapchain);
|
detail::get_vector<VkImage> (vkGetSwapchainImagesKHR, info.device, swapchain.swapchain);
|
||||||
|
if (!swapchain_images)
|
||||||
swapchain.image_format = surfaceFormat.format;
|
{
|
||||||
|
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to get swapchain Images" };
|
||||||
|
}
|
||||||
|
swapchain.images = swapchain_images.value ();
|
||||||
|
swapchain.image_format = surface_format.format;
|
||||||
swapchain.extent = extent;
|
swapchain.extent = extent;
|
||||||
|
|
||||||
return swapchain;
|
return swapchain;
|
||||||
@ -990,33 +1034,48 @@ detail::Expected<Swapchain, VkResult> SwapchainBuilder::recreate (Swapchain cons
|
|||||||
return build ();
|
return build ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwapchainBuilder::destroy (Swapchain const& swapchain)
|
void destroy_swapchain (Swapchain const& swapchain)
|
||||||
{
|
{
|
||||||
vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocator);
|
if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE &&
|
||||||
|
swapchain.allocator != VK_NULL_HANDLE)
|
||||||
|
vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwapchainBuilder& SwapchainBuilder::set_desired_format (VkSurfaceFormatKHR format)
|
||||||
|
{
|
||||||
|
info.desired_formats.insert (info.desired_formats.begin (), format);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SwapchainBuilder& SwapchainBuilder::add_fallback_format (VkSurfaceFormatKHR format)
|
||||||
|
{
|
||||||
|
info.desired_formats.push_back (format);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SwapchainBuilder& SwapchainBuilder::use_default_format_selection ()
|
||||||
|
{
|
||||||
|
info.desired_formats.push_back ({ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR });
|
||||||
|
info.desired_formats.push_back ({ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR });
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
SwapchainBuilder& SwapchainBuilder::set_desired_format (VkFormat format)
|
|
||||||
{
|
|
||||||
info.desired_format = format;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
SwapchainBuilder& SwapchainBuilder::set_fallback_format (VkFormat format)
|
|
||||||
{
|
|
||||||
info.fallback_format = format;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
SwapchainBuilder& SwapchainBuilder::set_desired_present_mode (VkPresentModeKHR present_mode)
|
SwapchainBuilder& SwapchainBuilder::set_desired_present_mode (VkPresentModeKHR present_mode)
|
||||||
{
|
{
|
||||||
info.desired_present_mode = present_mode;
|
info.desired_present_modes.insert (info.desired_present_modes.begin (), present_mode);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
SwapchainBuilder& SwapchainBuilder::set_fallback_present_mode (VkPresentModeKHR present_mode)
|
SwapchainBuilder& SwapchainBuilder::add_fallback_present_mode (VkPresentModeKHR present_mode)
|
||||||
{
|
{
|
||||||
info.fallback_present_mode = present_mode;
|
info.desired_present_modes.push_back (present_mode);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SwapchainBuilder& SwapchainBuilder::use_default_present_mode_selection ()
|
||||||
|
{
|
||||||
|
info.desired_present_modes.push_back (VK_PRESENT_MODE_MAILBOX_KHR);
|
||||||
|
info.desired_present_modes.push_back (VK_PRESENT_MODE_FIFO_KHR);
|
||||||
|
info.desired_present_modes.push_back (VK_PRESENT_MODE_FIFO_RELAXED_KHR);
|
||||||
|
info.desired_present_modes.push_back (VK_PRESENT_MODE_IMMEDIATE_KHR);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace vkb
|
} // namespace vkb
|
@ -14,9 +14,14 @@ namespace vkb
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename T> struct Error
|
enum class BootstrapErrorType : uint32_t
|
||||||
{
|
{
|
||||||
T error_code;
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Error
|
||||||
|
{
|
||||||
|
VkResult error_code;
|
||||||
const char* msg;
|
const char* msg;
|
||||||
};
|
};
|
||||||
template <typename E, typename U> class Expected
|
template <typename E, typename U> class Expected
|
||||||
@ -24,22 +29,22 @@ template <typename E, typename U> class Expected
|
|||||||
public:
|
public:
|
||||||
Expected (const E& expect) : m_expect{ expect }, m_init{ true } {}
|
Expected (const E& expect) : m_expect{ expect }, m_init{ true } {}
|
||||||
Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {}
|
Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {}
|
||||||
Expected (const Error<U>& error) : m_error{ error }, m_init{ false } {}
|
Expected (const Error& error) : m_error{ error }, m_init{ false } {}
|
||||||
Expected (Error<U>&& error) : m_error{ std::move (error) }, m_init{ false } {}
|
Expected (Error&& error) : m_error{ std::move (error) }, m_init{ false } {}
|
||||||
~Expected () { destroy (); }
|
~Expected () { destroy (); }
|
||||||
Expected (Expected const& expected) : m_init (expected.m_init)
|
Expected (Expected const& expected) : m_init (expected.m_init)
|
||||||
{
|
{
|
||||||
if (m_init)
|
if (m_init)
|
||||||
new (&m_expect) E{ expected.m_expect };
|
new (&m_expect) E{ expected.m_expect };
|
||||||
else
|
else
|
||||||
new (&m_error) Error<U>{ expected.m_error };
|
new (&m_error) Error{ expected.m_error };
|
||||||
}
|
}
|
||||||
Expected (Expected&& expected) : m_init (expected.m_init)
|
Expected (Expected&& expected) : m_init (expected.m_init)
|
||||||
{
|
{
|
||||||
if (m_init)
|
if (m_init)
|
||||||
new (&m_expect) E{ std::move (expected.m_expect) };
|
new (&m_expect) E{ std::move (expected.m_expect) };
|
||||||
else
|
else
|
||||||
new (&m_error) Error<U>{ std::move (expected.m_error) };
|
new (&m_error) Error{ std::move (expected.m_error) };
|
||||||
expected.destroy ();
|
expected.destroy ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,18 +62,18 @@ template <typename E, typename U> class Expected
|
|||||||
new (&m_expect) E{ std::move (expect) };
|
new (&m_expect) E{ std::move (expect) };
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Expected& operator= (const Error<U>& error)
|
Expected& operator= (const Error& error)
|
||||||
{
|
{
|
||||||
destroy ();
|
destroy ();
|
||||||
m_init = false;
|
m_init = false;
|
||||||
new (&m_error) Error<U>{ error };
|
new (&m_error) Error{ error };
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Expected& operator= (Error<U>&& error)
|
Expected& operator= (Error&& error)
|
||||||
{
|
{
|
||||||
destroy ();
|
destroy ();
|
||||||
m_init = false;
|
m_init = false;
|
||||||
new (&m_error) Error<U>{ std::move (error) };
|
new (&m_error) Error{ std::move (error) };
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@ -81,10 +86,10 @@ template <typename E, typename U> class Expected
|
|||||||
E& value () & { assert (m_init); return m_expect; }
|
E& value () & { assert (m_init); return m_expect; }
|
||||||
const E&& value () const&& { assert (m_init); return std::move (m_expect); }
|
const E&& value () const&& { assert (m_init); return std::move (m_expect); }
|
||||||
E&& value () && { assert (m_init); return std::move (m_expect); }
|
E&& value () && { assert (m_init); return std::move (m_expect); }
|
||||||
const Error<U>& error () const& { assert (!m_init); return m_error; }
|
const Error& error () const& { assert (!m_init); return m_error; }
|
||||||
Error<U>& error () & { assert (!m_init); return m_error; }
|
Error& error () & { assert (!m_init); return m_error; }
|
||||||
const Error<U>&& error () const&& { assert (!m_init); return std::move (m_error); }
|
const Error&& error () const&& { assert (!m_init); return std::move (m_error); }
|
||||||
Error<U>&& error () && { assert (!m_init); return move (m_error); }
|
Error&& error () && { assert (!m_init); return std::move (m_error); }
|
||||||
// clang-format on
|
// clang-format on
|
||||||
bool has_value () const { return m_init; }
|
bool has_value () const { return m_init; }
|
||||||
explicit operator bool () const { return m_init; }
|
explicit operator bool () const { return m_init; }
|
||||||
@ -95,12 +100,12 @@ template <typename E, typename U> class Expected
|
|||||||
if (m_init)
|
if (m_init)
|
||||||
m_expect.~E ();
|
m_expect.~E ();
|
||||||
else
|
else
|
||||||
m_error.~Error<U> ();
|
m_error.~Error ();
|
||||||
}
|
}
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
E m_expect;
|
E m_expect;
|
||||||
Error<U> m_error;
|
Error m_error;
|
||||||
};
|
};
|
||||||
bool m_init;
|
bool m_init;
|
||||||
};
|
};
|
||||||
@ -120,14 +125,14 @@ auto get_vector_init (F&& f, T init, Ts&&... ts) -> Expected<std::vector<T>, VkR
|
|||||||
err = f (ts..., &count, nullptr);
|
err = f (ts..., &count, nullptr);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
return Error<VkResult>{ err, "" };
|
return Error{ err, "" };
|
||||||
};
|
};
|
||||||
results.resize (count, init);
|
results.resize (count, init);
|
||||||
err = f (ts..., &count, results.data ());
|
err = f (ts..., &count, results.data ());
|
||||||
} while (err == VK_INCOMPLETE);
|
} while (err == VK_INCOMPLETE);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
return Error<VkResult>{ err, "" };
|
return Error{ err, "" };
|
||||||
};
|
};
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
@ -289,7 +294,7 @@ VkFormat find_supported_format (VkPhysicalDevice physical_device,
|
|||||||
VkImageTiling tiling,
|
VkImageTiling tiling,
|
||||||
VkFormatFeatureFlags features);
|
VkFormatFeatureFlags features);
|
||||||
|
|
||||||
bool check_device_extension_support (VkPhysicalDevice device, std::vector<std::string> extensions);
|
std::vector<std::string> device_extension_support (VkPhysicalDevice device, std::vector<std::string> extensions);
|
||||||
|
|
||||||
detail::QueueFamilies find_queue_families (VkPhysicalDevice physDevice, VkSurfaceKHR windowSurface);
|
detail::QueueFamilies find_queue_families (VkPhysicalDevice physDevice, VkSurfaceKHR windowSurface);
|
||||||
|
|
||||||
@ -304,11 +309,13 @@ struct PhysicalDevice
|
|||||||
VkPhysicalDevice phys_device = VK_NULL_HANDLE;
|
VkPhysicalDevice phys_device = VK_NULL_HANDLE;
|
||||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkPhysicalDeviceProperties physical_device_properties{};
|
|
||||||
VkPhysicalDeviceFeatures physical_device_features{};
|
VkPhysicalDeviceFeatures physical_device_features{};
|
||||||
|
VkPhysicalDeviceProperties physical_device_properties{};
|
||||||
VkPhysicalDeviceMemoryProperties memory_properties{};
|
VkPhysicalDeviceMemoryProperties memory_properties{};
|
||||||
|
|
||||||
detail::QueueFamilies queue_family_properties;
|
detail::QueueFamilies queue_family_properties;
|
||||||
|
|
||||||
|
std::vector<std::string> extensions_to_enable;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
@ -421,6 +428,12 @@ namespace detail
|
|||||||
VkQueue get_queue (Device const& device, uint32_t family, uint32_t index = 0);
|
VkQueue get_queue (Device const& device, uint32_t family, uint32_t index = 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t get_queue_index_present (Device const& device);
|
||||||
|
uint32_t get_queue_index_graphics (Device const& device);
|
||||||
|
uint32_t get_queue_index_compute (Device const& device);
|
||||||
|
uint32_t get_queue_index_transfer (Device const& device);
|
||||||
|
uint32_t get_queue_index_sparse (Device const& device);
|
||||||
|
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_present (Device const& device);
|
detail::Expected<VkQueue, VkResult> get_queue_present (Device const& device);
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_graphics (Device const& device, uint32_t index = 0);
|
detail::Expected<VkQueue, VkResult> get_queue_graphics (Device const& device, uint32_t index = 0);
|
||||||
detail::Expected<VkQueue, VkResult> get_queue_compute (Device const& device, uint32_t index = 0);
|
detail::Expected<VkQueue, VkResult> get_queue_compute (Device const& device, uint32_t index = 0);
|
||||||
@ -430,9 +443,10 @@ detail::Expected<VkQueue, VkResult> get_queue_sparse (Device const& device, uint
|
|||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector<VkSurfaceFormatKHR> const& availableFormats);
|
VkSurfaceFormatKHR find_surface_format (std::vector<VkFormat> const& available_formats);
|
||||||
VkPresentModeKHR choose_swap_present_mode (std::vector<VkPresentModeKHR> const& availablePresentModes);
|
VkPresentModeKHR find_present_mode (std::vector<VkPresentModeKHR> const& available_present_modes,
|
||||||
VkExtent2D choose_swap_extent (
|
std::vector<VkPresentModeKHR> const& desired_present_modes);
|
||||||
|
VkExtent2D find_extent (
|
||||||
VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height);
|
VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height);
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
@ -446,6 +460,8 @@ struct Swapchain
|
|||||||
VkExtent2D extent = { 0, 0 };
|
VkExtent2D extent = { 0, 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void destroy_swapchain (Swapchain const& swapchain);
|
||||||
|
|
||||||
class SwapchainBuilder
|
class SwapchainBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -453,13 +469,18 @@ class SwapchainBuilder
|
|||||||
|
|
||||||
detail::Expected<Swapchain, VkResult> build ();
|
detail::Expected<Swapchain, VkResult> build ();
|
||||||
detail::Expected<Swapchain, VkResult> recreate (Swapchain const& swapchain);
|
detail::Expected<Swapchain, VkResult> recreate (Swapchain const& swapchain);
|
||||||
void destroy (Swapchain const& swapchain);
|
|
||||||
|
|
||||||
SwapchainBuilder& set_desired_format (VkFormat format);
|
// SwapchainBuilder& set_desired_image_count (uint32_t count);
|
||||||
SwapchainBuilder& set_fallback_format (VkFormat format);
|
// SwapchainBuilder& set_maximum_image_count (uint32_t count);
|
||||||
|
|
||||||
|
SwapchainBuilder& set_desired_format (VkSurfaceFormatKHR format);
|
||||||
|
SwapchainBuilder& add_fallback_format (VkSurfaceFormatKHR format);
|
||||||
|
SwapchainBuilder& use_default_format_selection ();
|
||||||
|
|
||||||
SwapchainBuilder& set_desired_present_mode (VkPresentModeKHR present_mode);
|
SwapchainBuilder& set_desired_present_mode (VkPresentModeKHR present_mode);
|
||||||
SwapchainBuilder& set_fallback_present_mode (VkPresentModeKHR present_mode);
|
SwapchainBuilder& add_fallback_present_mode (VkPresentModeKHR present_mode);
|
||||||
|
SwapchainBuilder& use_default_present_mode_selection ();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -469,11 +490,8 @@ class SwapchainBuilder
|
|||||||
PhysicalDevice physical_device;
|
PhysicalDevice physical_device;
|
||||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
VkSwapchainKHR old_swapchain = VK_NULL_HANDLE;
|
VkSwapchainKHR old_swapchain = VK_NULL_HANDLE;
|
||||||
VkFormat desired_format = VK_FORMAT_R8G8B8A8_UNORM;
|
std::vector<VkSurfaceFormatKHR> desired_formats;
|
||||||
VkFormat fallback_format = VK_FORMAT_R8G8B8A8_UNORM;
|
std::vector<VkPresentModeKHR> desired_present_modes;
|
||||||
VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
VkPresentModeKHR fallback_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
std::vector<VkPresentModeKHR> acceptable_present_modes;
|
|
||||||
uint32_t desired_width = 256;
|
uint32_t desired_width = 256;
|
||||||
uint32_t desired_height = 256;
|
uint32_t desired_height = 256;
|
||||||
} info;
|
} info;
|
||||||
|
41
tests/common.h
Normal file
41
tests/common.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
|
#include "../src/VkBootstrap.h"
|
||||||
|
|
||||||
|
GLFWwindow* create_window_glfw ()
|
||||||
|
{
|
||||||
|
glfwInit ();
|
||||||
|
glfwWindowHint (GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
return glfwCreateWindow (640, 480, "Vulkan Triangle", NULL, NULL);
|
||||||
|
}
|
||||||
|
void destroy_window_glfw (GLFWwindow* window)
|
||||||
|
{
|
||||||
|
glfwDestroyWindow (window);
|
||||||
|
glfwTerminate ();
|
||||||
|
}
|
||||||
|
VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window)
|
||||||
|
{
|
||||||
|
VkSurfaceKHR surface = nullptr;
|
||||||
|
VkResult err = glfwCreateWindowSurface (instance, window, NULL, &surface);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
const char* error_msg;
|
||||||
|
int ret = glfwGetError (&error_msg);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
std::cout << ret << " ";
|
||||||
|
if (error_msg != nullptr) std::cout << error_msg;
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
surface = nullptr;
|
||||||
|
}
|
||||||
|
return surface;
|
||||||
|
}
|
@ -1,36 +1,5 @@
|
|||||||
#include <stdio.h>
|
#include "common.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "VkBootstrap.h"
|
|
||||||
|
|
||||||
#define GLFW_INCLUDE_VULKAN
|
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
|
|
||||||
#include "catch2/catch.hpp"
|
|
||||||
|
|
||||||
GLFWwindow* create_window_glfw ()
|
|
||||||
{
|
|
||||||
glfwInit ();
|
|
||||||
glfwWindowHint (GLFW_CLIENT_API, GLFW_NO_API);
|
|
||||||
return glfwCreateWindow (640, 480, "Window Title", NULL, NULL);
|
|
||||||
}
|
|
||||||
void destroy_window_glfw (GLFWwindow* window)
|
|
||||||
{
|
|
||||||
glfwDestroyWindow (window);
|
|
||||||
glfwTerminate ();
|
|
||||||
}
|
|
||||||
VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window)
|
|
||||||
{
|
|
||||||
VkSurfaceKHR surface = nullptr;
|
|
||||||
VkResult err = glfwCreateWindowSurface (instance, window, NULL, &surface);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
surface = nullptr;
|
|
||||||
}
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
int test_happy_path ()
|
int test_happy_path ()
|
||||||
{
|
{
|
||||||
auto window = create_window_glfw ();
|
auto window = create_window_glfw ();
|
||||||
|
8
tests/shaders/frag.glsl
Normal file
8
tests/shaders/frag.glsl
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 450
|
||||||
|
#extension GL_ARB_separate_shader_objects : enable
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 fragColor;
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main () { outColor = vec4 (fragColor, 1.0); }
|
BIN
tests/shaders/frag.spv
Normal file
BIN
tests/shaders/frag.spv
Normal file
Binary file not shown.
14
tests/shaders/vert.glsl
Normal file
14
tests/shaders/vert.glsl
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#version 450
|
||||||
|
#extension GL_ARB_separate_shader_objects : enable
|
||||||
|
|
||||||
|
layout (location = 0) out vec3 fragColor;
|
||||||
|
|
||||||
|
vec2 positions[3] = vec2[](vec2 (0.0, -0.5), vec2 (0.5, 0.5), vec2 (-0.5, 0.5));
|
||||||
|
|
||||||
|
vec3 colors[3] = vec3[](vec3 (1.0, 0.0, 0.0), vec3 (0.0, 1.0, 0.0), vec3 (0.0, 0.0, 1.0));
|
||||||
|
|
||||||
|
void main ()
|
||||||
|
{
|
||||||
|
gl_Position = vec4 (positions[gl_VertexIndex], 0.0, 1.0);
|
||||||
|
fragColor = colors[gl_VertexIndex];
|
||||||
|
}
|
BIN
tests/shaders/vert.spv
Normal file
BIN
tests/shaders/vert.spv
Normal file
Binary file not shown.
@ -1,11 +1,8 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#include "common.h"
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
#include "VkBootstrap.h"
|
|
||||||
|
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
|
542
tests/triangle.cpp
Normal file
542
tests/triangle.cpp
Normal file
@ -0,0 +1,542 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct Init
|
||||||
|
{
|
||||||
|
GLFWwindow* window;
|
||||||
|
vkb::Instance instance;
|
||||||
|
VkSurfaceKHR surface;
|
||||||
|
vkb::Device device;
|
||||||
|
vkb::Swapchain swapchain;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderData
|
||||||
|
{
|
||||||
|
VkQueue graphicsQueue;
|
||||||
|
VkQueue presentQueue;
|
||||||
|
|
||||||
|
std::vector<VkImageView> swapChainImageViews;
|
||||||
|
std::vector<VkFramebuffer> swapChainFramebuffers;
|
||||||
|
|
||||||
|
VkRenderPass renderPass;
|
||||||
|
VkPipelineLayout pipelineLayout;
|
||||||
|
VkPipeline graphicsPipeline;
|
||||||
|
|
||||||
|
VkCommandPool commandPool;
|
||||||
|
std::vector<VkCommandBuffer> commandBuffers;
|
||||||
|
|
||||||
|
std::vector<VkSemaphore> imageAvailableSemaphores;
|
||||||
|
std::vector<VkSemaphore> renderFinishedSemaphores;
|
||||||
|
std::vector<VkFence> inFlightFences;
|
||||||
|
std::vector<VkFence> imagesInFlight;
|
||||||
|
size_t currentFrame = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void device_initialization (Init& init)
|
||||||
|
{
|
||||||
|
init.window = create_window_glfw ();
|
||||||
|
|
||||||
|
vkb::InstanceBuilder instance_builder;
|
||||||
|
auto instance_ret = instance_builder.set_default_debug_messenger ().setup_validation_layers ().build ();
|
||||||
|
if (!instance_ret)
|
||||||
|
{
|
||||||
|
std::cout << instance_ret.error ().msg << "\n";
|
||||||
|
}
|
||||||
|
init.instance = instance_ret.value ();
|
||||||
|
|
||||||
|
init.surface = create_surface_glfw (init.instance.instance, init.window);
|
||||||
|
|
||||||
|
vkb::PhysicalDeviceSelector phys_device_selector (init.instance);
|
||||||
|
auto phys_device_ret = phys_device_selector.set_surface (init.surface).select ();
|
||||||
|
if (!phys_device_ret)
|
||||||
|
{
|
||||||
|
std::cout << phys_device_ret.error ().msg << "\n";
|
||||||
|
}
|
||||||
|
vkb::PhysicalDevice physical_device = phys_device_ret.value ();
|
||||||
|
|
||||||
|
vkb::DeviceBuilder device_builder (physical_device);
|
||||||
|
auto device_ret = device_builder.build ();
|
||||||
|
if (!device_ret)
|
||||||
|
{
|
||||||
|
std::cout << device_ret.error ().msg << "\n";
|
||||||
|
}
|
||||||
|
init.device = device_ret.value ();
|
||||||
|
|
||||||
|
vkb::SwapchainBuilder swapchain_builder (init.device);
|
||||||
|
auto swap_ret =
|
||||||
|
swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build ();
|
||||||
|
if (!swap_ret)
|
||||||
|
{
|
||||||
|
std::cout << swap_ret.error ().msg << "\n";
|
||||||
|
}
|
||||||
|
init.swapchain = swap_ret.value ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_queues (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
data.graphicsQueue = vkb::get_queue_graphics (init.device).value ();
|
||||||
|
data.presentQueue = vkb::get_queue_graphics (init.device).value ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void createImageViews (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
data.swapChainImageViews.resize (init.swapchain.images.size ());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < init.swapchain.images.size (); i++)
|
||||||
|
{
|
||||||
|
VkImageViewCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
createInfo.image = init.swapchain.images[i];
|
||||||
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
createInfo.format = init.swapchain.image_format;
|
||||||
|
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
createInfo.subresourceRange.baseMipLevel = 0;
|
||||||
|
createInfo.subresourceRange.levelCount = 1;
|
||||||
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
|
createInfo.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
if (vkCreateImageView (init.device.device, &createInfo, nullptr, &data.swapChainImageViews[i]) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to create image views!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createRenderPass (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
VkAttachmentDescription colorAttachment = {};
|
||||||
|
colorAttachment.format = init.swapchain.image_format;
|
||||||
|
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
|
||||||
|
VkAttachmentReference colorAttachmentRef = {};
|
||||||
|
colorAttachmentRef.attachment = 0;
|
||||||
|
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkSubpassDescription subpass = {};
|
||||||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpass.colorAttachmentCount = 1;
|
||||||
|
subpass.pColorAttachments = &colorAttachmentRef;
|
||||||
|
|
||||||
|
VkSubpassDependency dependency = {};
|
||||||
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||||
|
dependency.dstSubpass = 0;
|
||||||
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
dependency.srcAccessMask = 0;
|
||||||
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo renderPassInfo = {};
|
||||||
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
renderPassInfo.attachmentCount = 1;
|
||||||
|
renderPassInfo.pAttachments = &colorAttachment;
|
||||||
|
renderPassInfo.subpassCount = 1;
|
||||||
|
renderPassInfo.pSubpasses = &subpass;
|
||||||
|
renderPassInfo.dependencyCount = 1;
|
||||||
|
renderPassInfo.pDependencies = &dependency;
|
||||||
|
|
||||||
|
if (vkCreateRenderPass (init.device.device, &renderPassInfo, nullptr, &data.renderPass) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to create render pass!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> readFile (const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ifstream file (filename, std::ios::ate | std::ios::binary);
|
||||||
|
|
||||||
|
if (!file.is_open ())
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to open file!");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fileSize = (size_t)file.tellg ();
|
||||||
|
std::vector<char> buffer (fileSize);
|
||||||
|
|
||||||
|
file.seekg (0);
|
||||||
|
file.read (buffer.data (), fileSize);
|
||||||
|
|
||||||
|
file.close ();
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule createShaderModule (Init& init, const std::vector<char>& code)
|
||||||
|
{
|
||||||
|
VkShaderModuleCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
createInfo.codeSize = code.size ();
|
||||||
|
createInfo.pCode = reinterpret_cast<const uint32_t*> (code.data ());
|
||||||
|
|
||||||
|
VkShaderModule shaderModule;
|
||||||
|
if (vkCreateShaderModule (init.device.device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to create shader module!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return shaderModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createGraphicsPipeline (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
auto vertShaderCode = readFile ("vert.spv");
|
||||||
|
auto fragShaderCode = readFile ("frag.spv");
|
||||||
|
|
||||||
|
VkShaderModule vertShaderModule = createShaderModule (init, vertShaderCode);
|
||||||
|
VkShaderModule fragShaderModule = createShaderModule (init, fragShaderCode);
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
|
||||||
|
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
vertShaderStageInfo.module = vertShaderModule;
|
||||||
|
vertShaderStageInfo.pName = "main";
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
|
||||||
|
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
fragShaderStageInfo.module = fragShaderModule;
|
||||||
|
fragShaderStageInfo.pName = "main";
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
|
||||||
|
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
vertexInputInfo.vertexBindingDescriptionCount = 0;
|
||||||
|
vertexInputInfo.vertexAttributeDescriptionCount = 0;
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
|
||||||
|
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
inputAssembly.primitiveRestartEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkViewport viewport = {};
|
||||||
|
viewport.x = 0.0f;
|
||||||
|
viewport.y = 0.0f;
|
||||||
|
viewport.width = (float)init.swapchain.extent.width;
|
||||||
|
viewport.height = (float)init.swapchain.extent.height;
|
||||||
|
viewport.minDepth = 0.0f;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
|
VkRect2D scissor = {};
|
||||||
|
scissor.offset = { 0, 0 };
|
||||||
|
scissor.extent = init.swapchain.extent;
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo viewportState = {};
|
||||||
|
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
viewportState.viewportCount = 1;
|
||||||
|
viewportState.pViewports = &viewport;
|
||||||
|
viewportState.scissorCount = 1;
|
||||||
|
viewportState.pScissors = &scissor;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rasterizer = {};
|
||||||
|
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rasterizer.depthClampEnable = VK_FALSE;
|
||||||
|
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||||
|
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
rasterizer.lineWidth = 1.0f;
|
||||||
|
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
|
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
rasterizer.depthBiasEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisampling = {};
|
||||||
|
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
multisampling.sampleShadingEnable = VK_FALSE;
|
||||||
|
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
|
||||||
|
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||||
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
colorBlendAttachment.blendEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo colorBlending = {};
|
||||||
|
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
colorBlending.logicOpEnable = VK_FALSE;
|
||||||
|
colorBlending.logicOp = VK_LOGIC_OP_COPY;
|
||||||
|
colorBlending.attachmentCount = 1;
|
||||||
|
colorBlending.pAttachments = &colorBlendAttachment;
|
||||||
|
colorBlending.blendConstants[0] = 0.0f;
|
||||||
|
colorBlending.blendConstants[1] = 0.0f;
|
||||||
|
colorBlending.blendConstants[2] = 0.0f;
|
||||||
|
colorBlending.blendConstants[3] = 0.0f;
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
||||||
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
pipelineLayoutInfo.setLayoutCount = 0;
|
||||||
|
pipelineLayoutInfo.pushConstantRangeCount = 0;
|
||||||
|
|
||||||
|
if (vkCreatePipelineLayout (init.device.device, &pipelineLayoutInfo, nullptr, &data.pipelineLayout) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to create pipeline layout!");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
|
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
pipelineInfo.stageCount = 2;
|
||||||
|
pipelineInfo.pStages = shaderStages;
|
||||||
|
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
||||||
|
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
||||||
|
pipelineInfo.pViewportState = &viewportState;
|
||||||
|
pipelineInfo.pRasterizationState = &rasterizer;
|
||||||
|
pipelineInfo.pMultisampleState = &multisampling;
|
||||||
|
pipelineInfo.pColorBlendState = &colorBlending;
|
||||||
|
pipelineInfo.layout = data.pipelineLayout;
|
||||||
|
pipelineInfo.renderPass = data.renderPass;
|
||||||
|
pipelineInfo.subpass = 0;
|
||||||
|
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
if (vkCreateGraphicsPipelines (
|
||||||
|
init.device.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &data.graphicsPipeline) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to create graphics pipeline!");
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroyShaderModule (init.device.device, fragShaderModule, nullptr);
|
||||||
|
vkDestroyShaderModule (init.device.device, vertShaderModule, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createFramebuffers (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
data.swapChainFramebuffers.resize (data.swapChainImageViews.size ());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < data.swapChainImageViews.size (); i++)
|
||||||
|
{
|
||||||
|
VkImageView attachments[] = { data.swapChainImageViews[i] };
|
||||||
|
|
||||||
|
VkFramebufferCreateInfo framebufferInfo = {};
|
||||||
|
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
framebufferInfo.renderPass = data.renderPass;
|
||||||
|
framebufferInfo.attachmentCount = 1;
|
||||||
|
framebufferInfo.pAttachments = attachments;
|
||||||
|
framebufferInfo.width = init.swapchain.extent.width;
|
||||||
|
framebufferInfo.height = init.swapchain.extent.height;
|
||||||
|
framebufferInfo.layers = 1;
|
||||||
|
|
||||||
|
if (vkCreateFramebuffer (
|
||||||
|
init.device.device, &framebufferInfo, nullptr, &data.swapChainFramebuffers[i]) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to create framebuffer!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createCommandPool (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
|
||||||
|
VkCommandPoolCreateInfo poolInfo = {};
|
||||||
|
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
poolInfo.queueFamilyIndex = vkb::get_queue_index_graphics (init.device);
|
||||||
|
|
||||||
|
if (vkCreateCommandPool (init.device.device, &poolInfo, nullptr, &data.commandPool) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to create command pool!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createCommandBuffers (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
data.commandBuffers.resize (data.swapChainFramebuffers.size ());
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo allocInfo = {};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
allocInfo.commandPool = data.commandPool;
|
||||||
|
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
allocInfo.commandBufferCount = (uint32_t)data.commandBuffers.size ();
|
||||||
|
|
||||||
|
if (vkAllocateCommandBuffers (init.device.device, &allocInfo, data.commandBuffers.data ()) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to allocate command buffers!");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < data.commandBuffers.size (); i++)
|
||||||
|
{
|
||||||
|
VkCommandBufferBeginInfo beginInfo = {};
|
||||||
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
|
||||||
|
if (vkBeginCommandBuffer (data.commandBuffers[i], &beginInfo) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to begin recording command buffer!");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRenderPassBeginInfo renderPassInfo = {};
|
||||||
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
renderPassInfo.renderPass = data.renderPass;
|
||||||
|
renderPassInfo.framebuffer = data.swapChainFramebuffers[i];
|
||||||
|
renderPassInfo.renderArea.offset = { 0, 0 };
|
||||||
|
renderPassInfo.renderArea.extent = init.swapchain.extent;
|
||||||
|
|
||||||
|
VkClearValue clearColor = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||||
|
renderPassInfo.clearValueCount = 1;
|
||||||
|
renderPassInfo.pClearValues = &clearColor;
|
||||||
|
|
||||||
|
vkCmdBeginRenderPass (data.commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
vkCmdBindPipeline (data.commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, data.graphicsPipeline);
|
||||||
|
|
||||||
|
vkCmdDraw (data.commandBuffers[i], 3, 1, 0, 0);
|
||||||
|
|
||||||
|
vkCmdEndRenderPass (data.commandBuffers[i]);
|
||||||
|
|
||||||
|
if (vkEndCommandBuffer (data.commandBuffers[i]) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to record command buffer!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createSyncObjects (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
data.imageAvailableSemaphores.resize (init.swapchain.images.size ());
|
||||||
|
data.renderFinishedSemaphores.resize (init.swapchain.images.size ());
|
||||||
|
data.inFlightFences.resize (init.swapchain.images.size ());
|
||||||
|
data.imagesInFlight.resize (init.swapchain.images.size (), VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
VkSemaphoreCreateInfo semaphoreInfo = {};
|
||||||
|
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
|
||||||
|
VkFenceCreateInfo fenceInfo = {};
|
||||||
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < init.swapchain.images.size (); i++)
|
||||||
|
{
|
||||||
|
if (vkCreateSemaphore (
|
||||||
|
init.device.device, &semaphoreInfo, nullptr, &data.imageAvailableSemaphores[i]) != VK_SUCCESS ||
|
||||||
|
vkCreateSemaphore (
|
||||||
|
init.device.device, &semaphoreInfo, nullptr, &data.renderFinishedSemaphores[i]) != VK_SUCCESS ||
|
||||||
|
vkCreateFence (init.device.device, &fenceInfo, nullptr, &data.inFlightFences[i]) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to create synchronization objects for a frame!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawFrame (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
vkWaitForFences (init.device.device, 1, &data.inFlightFences[data.currentFrame], VK_TRUE, UINT64_MAX);
|
||||||
|
|
||||||
|
uint32_t imageIndex;
|
||||||
|
vkAcquireNextImageKHR (init.device.device,
|
||||||
|
init.swapchain.swapchain,
|
||||||
|
UINT64_MAX,
|
||||||
|
data.imageAvailableSemaphores[data.currentFrame],
|
||||||
|
VK_NULL_HANDLE,
|
||||||
|
&imageIndex);
|
||||||
|
|
||||||
|
if (data.imagesInFlight[imageIndex] != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkWaitForFences (init.device.device, 1, &data.imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX);
|
||||||
|
}
|
||||||
|
data.imagesInFlight[imageIndex] = data.inFlightFences[data.currentFrame];
|
||||||
|
|
||||||
|
VkSubmitInfo submitInfo = {};
|
||||||
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
|
||||||
|
VkSemaphore waitSemaphores[] = { data.imageAvailableSemaphores[data.currentFrame] };
|
||||||
|
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||||
|
submitInfo.waitSemaphoreCount = 1;
|
||||||
|
submitInfo.pWaitSemaphores = waitSemaphores;
|
||||||
|
submitInfo.pWaitDstStageMask = waitStages;
|
||||||
|
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = &data.commandBuffers[imageIndex];
|
||||||
|
|
||||||
|
VkSemaphore signalSemaphores[] = { data.renderFinishedSemaphores[data.currentFrame] };
|
||||||
|
submitInfo.signalSemaphoreCount = 1;
|
||||||
|
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||||
|
|
||||||
|
vkResetFences (init.device.device, 1, &data.inFlightFences[data.currentFrame]);
|
||||||
|
|
||||||
|
if (vkQueueSubmit (data.graphicsQueue, 1, &submitInfo, data.inFlightFences[data.currentFrame]) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("failed to submit draw command buffer!");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPresentInfoKHR presentInfo = {};
|
||||||
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
|
|
||||||
|
presentInfo.waitSemaphoreCount = 1;
|
||||||
|
presentInfo.pWaitSemaphores = signalSemaphores;
|
||||||
|
|
||||||
|
VkSwapchainKHR swapChains[] = { init.swapchain.swapchain };
|
||||||
|
presentInfo.swapchainCount = 1;
|
||||||
|
presentInfo.pSwapchains = swapChains;
|
||||||
|
|
||||||
|
presentInfo.pImageIndices = &imageIndex;
|
||||||
|
|
||||||
|
vkQueuePresentKHR (data.presentQueue, &presentInfo);
|
||||||
|
|
||||||
|
data.currentFrame = (data.currentFrame + 1) % init.swapchain.images.size ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup (Init& init, RenderData& data)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < init.swapchain.images.size (); i++)
|
||||||
|
{
|
||||||
|
vkDestroySemaphore (init.device.device, data.renderFinishedSemaphores[i], nullptr);
|
||||||
|
vkDestroySemaphore (init.device.device, data.imageAvailableSemaphores[i], nullptr);
|
||||||
|
vkDestroyFence (init.device.device, data.inFlightFences[i], nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroyCommandPool (init.device.device, data.commandPool, nullptr);
|
||||||
|
|
||||||
|
for (auto framebuffer : data.swapChainFramebuffers)
|
||||||
|
{
|
||||||
|
vkDestroyFramebuffer (init.device.device, framebuffer, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroyPipeline (init.device.device, data.graphicsPipeline, nullptr);
|
||||||
|
vkDestroyPipelineLayout (init.device.device, data.pipelineLayout, nullptr);
|
||||||
|
vkDestroyRenderPass (init.device.device, data.renderPass, nullptr);
|
||||||
|
|
||||||
|
for (auto imageView : data.swapChainImageViews)
|
||||||
|
{
|
||||||
|
vkDestroyImageView (init.device.device, imageView, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkb::destroy_swapchain (init.swapchain);
|
||||||
|
vkb::destroy_device (init.device);
|
||||||
|
vkDestroySurfaceKHR (init.instance.instance, init.surface, nullptr);
|
||||||
|
vkb::destroy_instance (init.instance);
|
||||||
|
destroy_window_glfw (init.window);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
Init init;
|
||||||
|
RenderData render_data;
|
||||||
|
|
||||||
|
|
||||||
|
device_initialization (init);
|
||||||
|
get_queues (init, render_data);
|
||||||
|
createImageViews (init, render_data);
|
||||||
|
createRenderPass (init, render_data);
|
||||||
|
createGraphicsPipeline (init, render_data);
|
||||||
|
createFramebuffers (init, render_data);
|
||||||
|
createCommandPool (init, render_data);
|
||||||
|
createCommandBuffers (init, render_data);
|
||||||
|
createSyncObjects (init, render_data);
|
||||||
|
|
||||||
|
while (!glfwWindowShouldClose (init.window))
|
||||||
|
{
|
||||||
|
glfwPollEvents ();
|
||||||
|
drawFrame (init, render_data);
|
||||||
|
}
|
||||||
|
vkDeviceWaitIdle (init.device.device);
|
||||||
|
|
||||||
|
cleanup (init, render_data);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user