diff --git a/.gitignore b/.gitignore index 493424b..f46c005 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.vscode -*.vs \ No newline at end of file +*.vs +*.idea +cmake-build-* diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e9c04d..289f576 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,15 +6,9 @@ find_package(Vulkan REQUIRED) add_library(vk-bootstrap src/VkBootstrap.h src/VkBootstrap.cpp) add_library(vk-bootstrap::vk-bootstrap ALIAS vk-bootstrap) -target_include_directories(vk-bootstrap PUBLIC src) - -target_include_directories(vk-bootstrap PRIVATE ${Vulkan_INCLUDE_DIR}) -target_link_libraries(vk-bootstrap PRIVATE ${Vulkan_LIBRARY}) - -target_compile_features(vk-bootstrap PUBLIC cxx_std_11) -target_compile_options( - vk-bootstrap - PRIVATE +add_library(vk-bootstrap-compiler-warnings INTERFACE) +target_compile_options(vk-bootstrap-compiler-warnings + INTERFACE $<$,$,$>: -Wall -Wextra @@ -23,40 +17,20 @@ target_compile_options( -Wsign-conversion> $<$: /WX - /W4>) + /W4> + ) + +target_include_directories(vk-bootstrap PUBLIC src) +target_include_directories(vk-bootstrap PUBLIC ${Vulkan_INCLUDE_DIR}) +target_link_libraries(vk-bootstrap + PUBLIC ${Vulkan_LIBRARY} + PRIVATE + vk-bootstrap-compiler-warnings) + option(VK_BOOTSTRAP_TEST "Test Vk-Bootstrap with glfw and Catch2" OFF) -if (VK_BOOTSTRAP_TEST) - set(GLFW_BUILD_TESTS - OFF - CACHE BOOL "" FORCE) - set(GLFW_BUILD_DOCS - OFF - CACHE BOOL "" FORCE) - set(GLFW_INSTALL - OFF - CACHE BOOL "" FORCE) - set(GLFW_BUILD_EXAMPLES - OFF - CACHE BOOL "" FORCE) - add_subdirectory(ext/glfw) - add_subdirectory(ext/Catch2) - - add_executable(vk-bootstrap-test tests/run_tests.cpp) - - target_link_libraries(vk-bootstrap-test vk-bootstrap) - target_link_libraries(vk-bootstrap-test glfw) - target_link_libraries(vk-bootstrap-test Catch2) - - add_executable(vk-bootstrap-triangle example/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}/example/shaders ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}) +if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR VK_BOOTSTRAP_TEST) + add_subdirectory(ext) + add_subdirectory(tests) + add_subdirectory(example) endif () diff --git a/README.md b/README.md index 9fb41ca..662d5de 100644 --- a/README.md +++ b/README.md @@ -110,10 +110,11 @@ In the project directory, run the following to get the required dependencies to git submodule update --init ``` -In the build directory, enable tests by adding `-DVK_BOOTSTRAP_TEST` to the cmake command line arguments +Tests will be enabled by default if you open this project standalone. If you include this project as a subdirectory, +you can force enable tests by adding `-DVK_BOOTSTRAP_TEST` to the cmake command line arguments ```bash -cmake ../path/to/vk-bootstrap/ -DVK_BOOTSTRAP_TEST=ON +cmake ../path/to/your-project/ -DVK_BOOTSTRAP_TEST=ON ``` ## Todo's diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..fe8e433 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,14 @@ +add_executable(vk-bootstrap-triangle triangle.cpp) +target_link_libraries(vk-bootstrap-triangle + PRIVATE + glfw + vk-bootstrap + vk-bootstrap-compiler-warnings) + +add_custom_command( + TARGET vk-bootstrap-triangle + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/example/shaders ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}) \ No newline at end of file diff --git a/example/triangle.cpp b/example/triangle.cpp index d96402c..fa7e4fa 100644 --- a/example/triangle.cpp +++ b/example/triangle.cpp @@ -133,7 +133,7 @@ int create_render_pass (Init& init, RenderData& data) { render_pass_info.pDependencies = &dependency; if (vkCreateRenderPass (init.device.device, &render_pass_info, nullptr, &data.render_pass) != VK_SUCCESS) { - std::cout << "failed to create render pass\n"; + std::cout << "failed to create render pass\n"; return -1; // failed to create render pass! } return 0; @@ -150,7 +150,7 @@ std::vector readFile (const std::string& filename) { std::vector buffer (file_size); file.seekg (0); - file.read (buffer.data (), file_size); + file.read (buffer.data (), static_cast (file_size)); file.close (); @@ -178,7 +178,7 @@ int create_graphics_pipeline (Init& init, RenderData& data) { VkShaderModule vert_module = createShaderModule (init, vert_code); VkShaderModule frag_module = createShaderModule (init, frag_code); if (vert_module == VK_NULL_HANDLE || frag_module == VK_NULL_HANDLE) { - std::cout << "failed to create shader module\n"; + std::cout << "failed to create shader module\n"; return -1; // failed to create shader modules } @@ -263,7 +263,7 @@ int create_graphics_pipeline (Init& init, RenderData& data) { if (vkCreatePipelineLayout ( init.device.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) { - std::cout << "failed to create pipeline layout\n"; + std::cout << "failed to create pipeline layout\n"; return -1; // failed to create pipeline layout } @@ -284,7 +284,7 @@ int create_graphics_pipeline (Init& init, RenderData& data) { if (vkCreateGraphicsPipelines ( init.device.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &data.graphics_pipeline) != VK_SUCCESS) { - std::cout << "failed to create pipline\n"; + std::cout << "failed to create pipline\n"; return -1; // failed to create graphics pipeline } @@ -326,7 +326,7 @@ int create_command_pool (Init& init, RenderData& data) { pool_info.queueFamilyIndex = init.device.get_queue_index (vkb::QueueType::graphics).value (); if (vkCreateCommandPool (init.device.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS) { - std::cout << "failed to create command pool\n"; + std::cout << "failed to create command pool\n"; return -1; // failed to create command pool } return 0; @@ -373,7 +373,7 @@ int create_command_buffers (Init& init, RenderData& data) { vkCmdEndRenderPass (data.command_buffers[i]); if (vkEndCommandBuffer (data.command_buffers[i]) != VK_SUCCESS) { - std::cout << "failed to record command buffer\n"; + std::cout << "failed to record command buffer\n"; return -1; // failed to record command buffer! } } @@ -397,7 +397,7 @@ int create_sync_objects (Init& init, RenderData& data) { if (vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.available_semaphores[i]) != VK_SUCCESS || vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.finished_semaphore[i]) != VK_SUCCESS || vkCreateFence (init.device.device, &fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS) { - std::cout << "failed to create sync objects\n"; + std::cout << "failed to create sync objects\n"; return -1; // failed to create synchronization objects for a frame } } @@ -439,8 +439,8 @@ int draw_frame (Init& init, RenderData& data) { vkResetFences (init.device.device, 1, &data.in_flight_fences[data.current_frame]); if (vkQueueSubmit (data.graphics_queue, 1, &submitInfo, data.in_flight_fences[data.current_frame]) != VK_SUCCESS) { - std::cout << "failed to submit draw command buffer\n"; - return -1; //"failed to submit draw command buffer + std::cout << "failed to submit draw command buffer\n"; + return -1; //"failed to submit draw command buffer } VkPresentInfoKHR present_info = {}; @@ -493,14 +493,14 @@ int main () { Init init; RenderData render_data; - if(0 != device_initialization (init)) return -1; - if(0 != get_queues (init, render_data)) return -1; - if(0 != create_render_pass (init, render_data)) return -1; - if(0 != create_graphics_pipeline (init, render_data)) return -1; - if(0 != create_framebuffers (init, render_data)) return -1; - if(0 != create_command_pool (init, render_data)) return -1; - if(0 != create_command_buffers (init, render_data)) return -1; - if(0 != create_sync_objects (init, render_data)) return -1; + if (0 != device_initialization (init)) return -1; + if (0 != get_queues (init, render_data)) return -1; + if (0 != create_render_pass (init, render_data)) return -1; + if (0 != create_graphics_pipeline (init, render_data)) return -1; + if (0 != create_framebuffers (init, render_data)) return -1; + if (0 != create_command_pool (init, render_data)) return -1; + if (0 != create_command_buffers (init, render_data)) return -1; + if (0 != create_sync_objects (init, render_data)) return -1; while (!glfwWindowShouldClose (init.window)) { glfwPollEvents (); diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt new file mode 100644 index 0000000..4708fa3 --- /dev/null +++ b/ext/CMakeLists.txt @@ -0,0 +1,14 @@ +set(GLFW_BUILD_TESTS + OFF + CACHE BOOL "" FORCE) +set(GLFW_BUILD_DOCS + OFF + CACHE BOOL "" FORCE) +set(GLFW_INSTALL + OFF + CACHE BOOL "" FORCE) +set(GLFW_BUILD_EXAMPLES + OFF + CACHE BOOL "" FORCE) +add_subdirectory(glfw) +add_subdirectory(Catch2) \ No newline at end of file diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index 8fab494..b4f2f18 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -98,8 +98,8 @@ template class Expected { } // namespace detail enum class InstanceError { - vulkan_unavailable, - vulkan_version_unavailable, + vulkan_unavailable, + vulkan_version_unavailable, vulkan_version_1_1_unavailable, vulkan_version_1_2_unavailable, failed_create_instance, @@ -189,7 +189,7 @@ class InstanceBuilder { InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch); // Require a vulkan instance API version. Will fail to create if this version isn't available. InstanceBuilder& require_api_version (uint32_t major, uint32_t minor, uint32_t patch); - // Prefer a vulkan instance API version. If the desired version isn't available, it will use the highest version available. + // Prefer a vulkan instance API version. If the desired version isn't available, it will use the highest version available. InstanceBuilder& desire_api_version (uint32_t major, uint32_t minor, uint32_t patch); // Adds a layer to be enabled. Will fail to create an instance if the layer isn't available. @@ -284,7 +284,7 @@ void destroy_debug_utils_messenger (VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE); -static VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, +VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..3ac876a --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,8 @@ +add_executable(vk-bootstrap-test main.cpp run_tests.cpp) +target_link_libraries(vk-bootstrap-test + PRIVATE + vk-bootstrap + vk-bootstrap-compiler-warnings + glfw + Catch2 + ) \ No newline at end of file diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..2380d6b --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include \ No newline at end of file diff --git a/tests/run_tests.cpp b/tests/run_tests.cpp index c331764..080cc85 100644 --- a/tests/run_tests.cpp +++ b/tests/run_tests.cpp @@ -1,46 +1,61 @@ #include "common.h" -int test_happy_path () { - printf ("happy path\n"); +#include - auto window = create_window_glfw (); +// TODO +// Getting queues +// get dedicated vs distinct compute queues +// Swapchain creation +// Swapchain recreation +// changing present modes and/or image formats - vkb::InstanceBuilder instance_builder; - auto instance_ret = instance_builder.use_default_debug_messenger ().build (); - if (!instance_ret) { - std::cout << static_cast (instance_ret.error ().type) << "\n"; - return -1; // couldn't make instance +TEST_CASE ("Instance with surface") { + GIVEN ("A window and a vulkan instance") { + + auto window = create_window_glfw (); + + vkb::InstanceBuilder instance_builder; + auto instance_ret = instance_builder.use_default_debug_messenger ().build (); + REQUIRE (instance_ret); + vkb::Instance instance = instance_ret.value (); + auto surface = create_surface_glfw (instance.instance, window); + + GIVEN ("A default selected physical device") { + vkb::PhysicalDeviceSelector phys_device_selector (instance); + auto phys_device_ret = phys_device_selector.set_surface (surface).select (); + REQUIRE (phys_device_ret); + vkb::PhysicalDevice physical_device = phys_device_ret.value (); + + GIVEN ("A device created with default parameters") { + vkb::DeviceBuilder device_builder (physical_device); + auto device_ret = device_builder.build (); + REQUIRE (device_ret); + vkb::Device device = device_ret.value (); + + // possible swapchain creation... + + vkb::destroy_device (device); + } + } + + THEN ("Can select physical device with customized requirements") { + vkb::PhysicalDeviceSelector selector (instance); + auto phys_dev_ret = selector.set_surface (surface) + .add_desired_extension (VK_KHR_MULTIVIEW_EXTENSION_NAME) + .add_required_extension (VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME) + .set_minimum_version (1, 0) + .set_desired_version (1, 1) + .select (); + REQUIRE (phys_dev_ret.has_value ()); + } + + destroy_surface (instance.instance, surface); + vkb::destroy_instance (instance); + destroy_window_glfw (window); } - vkb::Instance instance = instance_ret.value (); - printf ("made instance\n"); - - auto surface = create_surface_glfw (instance.instance, window); - - vkb::PhysicalDeviceSelector phys_device_selector (instance); - auto phys_device_ret = phys_device_selector.set_surface (surface).select (); - if (!phys_device_ret) return -2; // couldn't select physical device - vkb::PhysicalDevice physical_device = phys_device_ret.value (); - printf ("made physical device\n"); - - vkb::DeviceBuilder device_builder (physical_device); - auto device_ret = device_builder.build (); - if (!device_ret) return -1; // couldn't create device - vkb::Device device = device_ret.value (); - printf ("made device\n"); - - // possible swapchain creation... - - vkb::destroy_device (device); - destroy_surface (instance.instance, surface); - vkb::destroy_instance (instance); - destroy_window_glfw (window); - return 0; } - -int test_instance_basic () { - printf ("\nbasic instance\n"); - +TEST_CASE ("basic instance") { vkb::InstanceBuilder builder; auto instance_ret = @@ -49,7 +64,8 @@ int test_instance_basic () { .set_debug_callback ([] (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData) -> VkBool32 { + void * + /*pUserData*/) -> VkBool32 { auto ms = vkb::to_string_message_severity (messageSeverity); auto mt = vkb::to_string_message_type (messageType); printf ("[%s: %s](user defined)\n%s\n", ms, mt, pCallbackData->pMessage); @@ -57,17 +73,13 @@ int test_instance_basic () { }) .require_api_version (1, 2, 111) .build (); - if (!instance_ret.has_value ()) { - return 1; - } - vkb::destroy_instance (instance_ret.value ()); - return 0; + REQUIRE (instance_ret.has_value ()); + + vkb::destroy_instance (instance_ret.value ()); } -int test_instance_headless () { - printf ("\nheadless instance\n"); - +TEST_CASE ("headless instance") { vkb::InstanceBuilder builder; auto instance_ret = @@ -82,88 +94,6 @@ int test_instance_headless () { .add_validation_feature_disable (VkValidationFeatureDisableEXT::VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT) .add_validation_disable (VkValidationCheckEXT::VK_VALIDATION_CHECK_SHADERS_EXT) .build (); - if (!instance_ret.has_value ()) { - return 1; - } + REQUIRE (instance_ret.has_value ()); vkb::destroy_instance (instance_ret.value ()); - return 0; } - -int test_physical_device_selection () { - - printf ("\nphysical device selection\n"); - vkb::InstanceBuilder instance_builder; - auto instance_ret = instance_builder.use_default_debug_messenger ().build (); - if(!instance_ret.has_value()){ - printf("\n%s",vkb::to_string(instance_ret.error().type)); - return -1; - } - auto instance = instance_ret.value (); - auto window = create_window_glfw (); - auto surface = create_surface_glfw (instance.instance, window); - - vkb::PhysicalDeviceSelector selector (instance); - auto phys_dev_ret = selector.set_surface (surface) - .add_desired_extension (VK_KHR_MULTIVIEW_EXTENSION_NAME) - .add_required_extension (VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME) - .set_minimum_version (1, 0) - .set_desired_version (1, 1) - .select (); - if (!phys_dev_ret.has_value ()) { - return -1; - } - destroy_surface (instance.instance, surface); - vkb::destroy_instance (instance); - destroy_window_glfw (window); - return 0; -} - -int test_device_creation () { - printf ("\ndevice creation\n"); - vkb::InstanceBuilder instance_builder; - auto instance_ret = instance_builder.use_default_debug_messenger ().build (); - if (!instance_ret.has_value ()) { - printf ("couldn't create instance %s\n", vkb::to_string (instance_ret.error ().type)); - return -1; - } - auto instance = instance_ret.value (); - - auto window = create_window_glfw (); - auto surface = create_surface_glfw (instance.instance, window); - - vkb::PhysicalDeviceSelector selector (instance); - auto phys_dev_ret = selector.set_surface (surface).select (); - if (!phys_dev_ret.has_value ()) { - printf ("couldn't select device %s\n", vkb::to_string (phys_dev_ret.error ().type)); - return -1; - } - auto phys_dev = phys_dev_ret.value (); - - vkb::DeviceBuilder device_builder (phys_dev); - auto dev_ret = device_builder.build (); - if (!dev_ret.has_value ()) { - printf ("couldn't create device %s\n", vkb::to_string (dev_ret.error ().type)); - return -1; - } - vkb::destroy_device (dev_ret.value ()); - destroy_surface (instance.instance, surface); - vkb::destroy_instance (instance); - destroy_window_glfw (window); - return 0; -} - -// TODO -// Migrate to Catch2 -// Getting queues -// get dedicated vs distinct compute queues -// Swapchain creation -// Swapchain recreation -// changing present modes and/or image formats - -int main () { - test_happy_path (); - test_instance_basic (); - test_instance_headless (); - test_physical_device_selection (); - test_device_creation (); -} \ No newline at end of file