diff --git a/example/triangle.cpp b/example/triangle.cpp index 9926021..d96402c 100644 --- a/example/triangle.cpp +++ b/example/triangle.cpp @@ -44,7 +44,8 @@ int device_initialization (Init& init) { vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.use_default_debug_messenger ().request_validation_layers ().build (); if (!instance_ret) { - std::cout << static_cast (instance_ret.error ().type) << "\n"; + std::cout << vkb::to_string (instance_ret.error ().type) << "\n"; + return -1; } init.instance = instance_ret.value (); @@ -53,14 +54,16 @@ int device_initialization (Init& init) { 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 << static_cast (phys_device_ret.error ().type) << "\n"; + std::cout << vkb::to_string (phys_device_ret.error ().type) << "\n"; + return -1; } 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 << static_cast (device_ret.error ().type) << "\n"; + std::cout << vkb::to_string (device_ret.error ().type) << "\n"; + return -1; } init.device = device_ret.value (); @@ -68,7 +71,8 @@ int device_initialization (Init& init) { auto swap_ret = swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build (); if (!swap_ret) { - std::cout << static_cast (swap_ret.error ().type) << "\n"; + std::cout << vkb::to_string (swap_ret.error ().type) << "\n"; + return -1; } init.swapchain = swap_ret.value (); return 0; @@ -77,14 +81,14 @@ int device_initialization (Init& init) { int get_queues (Init& init, RenderData& data) { auto gq = init.device.get_queue (vkb::QueueType::graphics); if (!gq.has_value ()) { - std::cout << "failed to get graphics queue\n"; + std::cout << "failed to get graphics queue: " << vkb::to_string (gq.error ().type) << "\n"; return -1; } data.graphics_queue = gq.value (); auto pq = init.device.get_queue (vkb::QueueType::present); if (!pq.has_value ()) { - std::cout << "failed to get present queue\n"; + std::cout << "failed to get present queue: " << vkb::to_string (gq.error ().type) << "\n"; return -1; } data.present_queue = pq.value (); @@ -129,6 +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"; return -1; // failed to create render pass! } return 0; @@ -173,6 +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"; return -1; // failed to create shader modules } @@ -257,6 +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"; return -1; // failed to create pipeline layout } @@ -277,6 +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"; return -1; // failed to create graphics pipeline } @@ -318,6 +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"; return -1; // failed to create command pool } return 0; @@ -364,6 +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"; return -1; // failed to record command buffer! } } @@ -387,6 +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"; return -1; // failed to create synchronization objects for a frame } } @@ -428,7 +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) { - 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 = {}; @@ -481,20 +493,14 @@ int main () { Init init; RenderData render_data; - int res = 0; - res = device_initialization (init); - res = get_queues (init, render_data); - res = create_render_pass (init, render_data); - res = create_graphics_pipeline (init, render_data); - res = create_framebuffers (init, render_data); - res = create_command_pool (init, render_data); - res = create_command_buffers (init, render_data); - res = create_sync_objects (init, render_data); - - if (res != 0) { - std::cout << "failed to initialize vulkan\n"; - 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/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index 6bd5b67..7770652 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -172,8 +172,14 @@ const char* validation_layer_name = "VK_LAYER_KHRONOS_validation"; const char* to_string (InstanceError err) { switch (err) { - case InstanceError::unavailable_vulkan_version: - return "unavailable_vulkan_version"; + case InstanceError::vulkan_unavailable: + return "vulkan_unavailable"; + case InstanceError::vulkan_version_unavailable: + return "vulkan_version_unavailable"; + case InstanceError::vulkan_version_1_1_unavailable: + return "vulkan_version_1_1_unavailable"; + case InstanceError::vulkan_version_1_2_unavailable: + return "vulkan_version_1_2_unavailable"; case InstanceError::failed_create_debug_messenger: return "failed_create_debug_messenger"; case InstanceError::failed_create_instance: @@ -278,19 +284,38 @@ SystemInfo InstanceBuilder::get_system_info () const { return system; } detail::Expected> InstanceBuilder::build () const { - if (VK_VERSION_MINOR (info.api_version) > 0) { + uint32_t api_version = VK_MAKE_VERSION (1, 0, 0); + + if (info.required_api_version > VK_MAKE_VERSION (1, 0, 0) || info.desired_api_version > VK_MAKE_VERSION (1, 0, 0)) { PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion; detail::get_inst_proc_addr ( pfn_vkEnumerateInstanceVersion, "vkEnumerateInstanceVersion", nullptr, vkGetInstanceProcAddr); - if (pfn_vkEnumerateInstanceVersion == nullptr) { - return detail::Error{ InstanceError::unavailable_vulkan_version }; - } else if (pfn_vkEnumerateInstanceVersion != nullptr) { - uint32_t api_version = 0; - pfn_vkEnumerateInstanceVersion (&api_version); - if (VK_VERSION_MINOR (api_version) < VK_VERSION_MINOR (info.api_version)) - return detail::Error{ InstanceError::unavailable_vulkan_version }; + + uint32_t queried_api_version = VK_MAKE_VERSION (1, 0, 0); + if (pfn_vkEnumerateInstanceVersion != nullptr) { + VkResult res = pfn_vkEnumerateInstanceVersion (&api_version); + // Should always return VK_SUCCESS + if (res != VK_SUCCESS && info.required_api_version > 0) + return detail::Error{ InstanceError::vulkan_version_unavailable }; + } + if (pfn_vkEnumerateInstanceVersion == nullptr || queried_api_version < info.required_api_version) { + if (VK_VERSION_MINOR (info.required_api_version) == 2) + return detail::Error{ InstanceError::vulkan_version_1_2_unavailable }; + else if (VK_VERSION_MINOR (info.required_api_version)) + return detail::Error{ InstanceError::vulkan_version_1_1_unavailable }; + else + return detail::Error{ InstanceError::vulkan_version_unavailable }; + } + if (info.required_api_version > VK_MAKE_VERSION (1, 0, 0)) { + api_version = info.required_api_version; + } else if (info.desired_api_version > VK_MAKE_VERSION (1, 0, 0)) { + if (queried_api_version >= info.desired_api_version) + api_version = info.desired_api_version; + else + api_version = queried_api_version; } } + VkApplicationInfo app_info = {}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.pNext = nullptr; @@ -298,7 +323,7 @@ detail::Expected> InstanceBuilder::build app_info.applicationVersion = info.application_version; app_info.pEngineName = info.engine_name != nullptr ? info.engine_name : ""; app_info.engineVersion = info.engine_version; - app_info.apiVersion = info.api_version; + app_info.apiVersion = api_version; std::vector extensions; for (auto& ext : info.extensions) @@ -406,7 +431,7 @@ detail::Expected> InstanceBuilder::build instance.headless = true; } instance.allocation_callbacks = info.allocation_callbacks; - instance.instance_version = info.api_version; + instance.instance_version = api_version; return instance; } @@ -429,7 +454,11 @@ InstanceBuilder& InstanceBuilder::set_engine_version (uint32_t major, uint32_t m return *this; } InstanceBuilder& InstanceBuilder::require_api_version (uint32_t major, uint32_t minor, uint32_t patch) { - info.api_version = VK_MAKE_VERSION (major, minor, patch); + info.required_api_version = VK_MAKE_VERSION (major, minor, patch); + return *this; +} +InstanceBuilder& InstanceBuilder::desire_api_version (uint32_t major, uint32_t minor, uint32_t patch) { + info.desired_api_version = VK_MAKE_VERSION (major, minor, patch); return *this; } InstanceBuilder& InstanceBuilder::enable_layer (const char* layer_name) { @@ -674,24 +703,27 @@ PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_devi PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable (PhysicalDeviceDesc pd) const { Suitable suitable = Suitable::yes; + if (criteria.required_version > pd.device_properties.apiVersion) return Suitable::no; + if (criteria.desired_version > pd.device_properties.apiVersion) suitable = Suitable::partial; + bool dedicated_compute = detail::get_dedicated_compute_queue_index (pd.queue_families) >= 0; bool dedicated_transfer = detail::get_dedicated_transfer_queue_index (pd.queue_families) >= 0; bool separate_compute = detail::get_separate_compute_queue_index (pd.queue_families) >= 0; bool separate_transfer = detail::get_separate_transfer_queue_index (pd.queue_families) >= 0; bool present_queue = - detail::get_present_queue_index (pd.phys_device, system_info.surface, pd.queue_families); + detail::get_present_queue_index (pd.phys_device, system_info.surface, pd.queue_families) >= 0; - if (criteria.require_dedicated_compute_queue && !dedicated_compute) suitable = Suitable::no; - if (criteria.require_dedicated_transfer_queue && !dedicated_transfer) suitable = Suitable::no; - if (criteria.require_separate_compute_queue && !separate_compute) suitable = Suitable::no; - if (criteria.require_separate_transfer_queue && !separate_transfer) suitable = Suitable::no; - if (criteria.require_present && !present_queue) suitable = Suitable::no; + if (criteria.require_dedicated_compute_queue && !dedicated_compute) return Suitable::no; + if (criteria.require_dedicated_transfer_queue && !dedicated_transfer) return Suitable::no; + if (criteria.require_separate_compute_queue && !separate_compute) return Suitable::no; + if (criteria.require_separate_transfer_queue && !separate_transfer) return Suitable::no; + if (criteria.require_present && !present_queue) return Suitable::no; auto required_extensions_supported = detail::check_device_extension_support (pd.phys_device, criteria.required_extensions); if (required_extensions_supported.size () != criteria.required_extensions.size ()) - suitable = Suitable::no; + return Suitable::no; auto desired_extensions_supported = detail::check_device_extension_support (pd.phys_device, criteria.desired_extensions); @@ -713,21 +745,18 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable (Phy swapChainAdequate = !formats.value ().empty () && !present_modes.value ().empty (); } } - if (criteria.require_present && !swapChainAdequate) suitable = Suitable::no; + if (criteria.require_present && !swapChainAdequate) return Suitable::no; if (pd.device_properties.deviceType != static_cast (criteria.preferred_type)) { if (criteria.allow_any_type) suitable = Suitable::partial; else - suitable = Suitable::no; + return Suitable::no; } - if (criteria.required_version < pd.device_properties.apiVersion) suitable = Suitable::no; - if (criteria.desired_version < pd.device_properties.apiVersion) suitable = Suitable::partial; - bool required_features_supported = detail::supports_features (pd.device_features, criteria.required_features); - if (!required_features_supported) suitable = Suitable::no; + if (!required_features_supported) return Suitable::no; bool has_required_memory = false; bool has_preferred_memory = false; @@ -741,7 +770,7 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable (Phy } } } - if (!has_required_memory) suitable = Suitable::no; + if (!has_required_memory) return Suitable::no; if (!has_preferred_memory) suitable = Suitable::partial; return suitable; @@ -752,6 +781,7 @@ PhysicalDeviceSelector::PhysicalDeviceSelector (Instance const& instance) { system_info.headless = instance.headless; criteria.require_present = !instance.headless; criteria.required_version = instance.instance_version; + criteria.desired_version = instance.instance_version; } detail::Expected> PhysicalDeviceSelector::select () const { diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index e131975..516c397 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -98,7 +98,10 @@ template class Expected { } // namespace detail enum class InstanceError { - unavailable_vulkan_version, + vulkan_unavailable, + vulkan_version_unavailable, + vulkan_version_1_1_unavailable, + vulkan_version_1_2_unavailable, failed_create_instance, failed_create_debug_messenger, requested_layers_not_present, @@ -183,8 +186,10 @@ class InstanceBuilder { InstanceBuilder& set_app_version (uint32_t major, uint32_t minor, uint32_t patch); // Sets the (major, minor, patch) version of the engine. InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch); - // Require a minimum vulkan instance API version. + // 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. + 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. InstanceBuilder& enable_layer (const char* layer_name); @@ -234,7 +239,8 @@ class InstanceBuilder { const char* engine_name = nullptr; uint32_t application_version = 0; uint32_t engine_version = 0; - uint32_t api_version = VK_MAKE_VERSION (1, 0, 0); + uint32_t required_api_version = VK_MAKE_VERSION (1, 0, 0); + uint32_t desired_api_version = VK_MAKE_VERSION (1, 0, 0); // VkInstanceCreateInfo std::vector layers; diff --git a/tests/run_tests.cpp b/tests/run_tests.cpp index fb76b63..c331764 100644 --- a/tests/run_tests.cpp +++ b/tests/run_tests.cpp @@ -90,10 +90,14 @@ int test_instance_headless () { } int test_physical_device_selection () { - printf ("\nphysical device selection\n"); + 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); @@ -119,7 +123,7 @@ int test_device_creation () { vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.use_default_debug_messenger ().build (); if (!instance_ret.has_value ()) { - printf ("couldn't create instance %i\n", static_cast (instance_ret.error ().type)); + printf ("couldn't create instance %s\n", vkb::to_string (instance_ret.error ().type)); return -1; } auto instance = instance_ret.value (); @@ -129,16 +133,16 @@ int test_device_creation () { vkb::PhysicalDeviceSelector selector (instance); auto phys_dev_ret = selector.set_surface (surface).select (); - auto phys_dev = phys_dev_ret.value (); if (!phys_dev_ret.has_value ()) { - printf ("couldn't select device %i\n", static_cast (phys_dev_ret.error ().type)); + 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 %i\n", static_cast (dev_ret.error ().type)); + printf ("couldn't create device %s\n", vkb::to_string (dev_ret.error ().type)); return -1; } vkb::destroy_device (dev_ret.value ());