From: Charles Giessen Date: Thu, 27 Feb 2020 22:02:29 +0000 (-0700) Subject: vulkaninfo: Refactor error handling X-Git-Tag: upstream/1.2.179~133 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1af57a3ec4143286f12d32565dcd7ed44f01754c;p=platform%2Fupstream%2FVulkan-Tools.git vulkaninfo: Refactor error handling Previously, if vulkaninfo encountered any errors, it shut down then and there. This is bad for json output where you are left with an invalid file. By using exceptions, vulkaninfo will catch errors, print it to cerr, then finish off the file so its left in a valid state. Change-Id: I2c0116b435713df6135b9c606fa95cfadbfdf8d8 --- diff --git a/vulkaninfo/outputprinter.h b/vulkaninfo/outputprinter.h index 80318e4..3fce9b9 100644 --- a/vulkaninfo/outputprinter.h +++ b/vulkaninfo/outputprinter.h @@ -181,12 +181,14 @@ class Printer { out << "\t}"; indents++; is_first_item.push(false); + is_array.push(false); break; case (OutputType::vkconfig_output): out << "{\n"; out << "\t\"Vulkan Instance Version\": \"" << VkVersionString(vulkan_version) << "\""; indents++; is_first_item.push(false); + is_array.push(false); break; default: break; @@ -209,6 +211,7 @@ class Printer { indents--; is_first_item.pop(); assert(is_first_item.empty() && "mismatched number of ObjectStart/ObjectEnd or ArrayStart/ArrayEnd's"); + is_array.pop(); break; } assert(indents == 0 && "indents must be zero at program end"); @@ -219,6 +222,34 @@ class Printer { OutputType Type() { return output_type; } + // When an error occurs, call this to create a valid output file. Needed for json/html + void FinishOutput() { + switch (output_type) { + case (OutputType::text): + indents = 0; + break; + case (OutputType::html): + while (indents > 3) { + out << "\n"; + indents--; + } + break; + case (OutputType::json): + case (OutputType::vkconfig_output): + while (indents > 1) { + out << "\n" << std::string(static_cast(indents), '\t'); + if (is_array.top()) { + out << "]"; + } else { + out << "}"; + } + is_array.pop(); + indents--; + } + break; + } + } + // Custom Formatting // use by prepending with p.SetXXX().ObjectStart/ArrayStart @@ -316,6 +347,8 @@ class Printer { } is_first_item.push(true); + is_array.push(false); + break; case (OutputType::vkconfig_output): if (!is_first_item.top()) { @@ -332,6 +365,8 @@ class Printer { out << "\"" << object_name << "\": {\n"; } is_first_item.push(true); + is_array.push(false); + break; default: break; @@ -352,6 +387,8 @@ class Printer { case (OutputType::vkconfig_output): out << "\n" << std::string(static_cast(indents), '\t') << "}"; is_first_item.pop(); + assert(is_array.top() == false && "cannot call ObjectEnd while inside an Array"); + is_array.pop(); break; default: break; @@ -394,6 +431,7 @@ class Printer { out << std::string(static_cast(indents), '\t') << "\"" << array_name << "\": " << "[\n"; is_first_item.push(true); + is_array.push(true); break; default: break; @@ -414,6 +452,8 @@ class Printer { case (OutputType::vkconfig_output): out << "\n" << std::string(static_cast(indents), '\t') << "]"; is_first_item.pop(); + assert(is_array.top() == true && "cannot call ArrayEnd while inside an Object"); + is_array.pop(); break; default: break; @@ -636,7 +676,8 @@ class Printer { int element_index = -1; // negative one is the sentinel value // json - std::stack is_first_item; + std::stack is_first_item; // for json: for adding a comma inbetween objects + std::stack is_array; // for json: match pairs of {}'s and []'s // utility void PrintHeaderUnderlines(size_t length) { @@ -651,6 +692,21 @@ class Printer { } } }; +// Purpose: When a Printer starts an object or array it will automatically indent the output. This isn't +// always desired, requiring a manual decrease of indention. This wrapper facilitates that while also +// automatically re-indenting the output to the previous indent level on scope exit. +class IndentWrapper { + public: + IndentWrapper(Printer &p) : p(p) { + if (p.Type() == OutputType::text) p.IndentDecrease(); + } + ~IndentWrapper() { + if (p.Type() == OutputType::text) p.IndentIncrease(); + } + + private: + Printer &p; +}; class ObjectWrapper { public: diff --git a/vulkaninfo/vulkaninfo.cpp b/vulkaninfo/vulkaninfo.cpp index 4dc1dfe..d81749b 100644 --- a/vulkaninfo/vulkaninfo.cpp +++ b/vulkaninfo/vulkaninfo.cpp @@ -74,7 +74,8 @@ void DumpLayers(Printer &p, std::vector layers, const std::v case OutputType::html: { p.SetHeader(); ArrayWrapper arr(p, "Layers", layers.size()); - p.IndentDecrease(); + IndentWrapper indent(p); + for (auto &layer : layers) { auto v_str = VkVersionString(layer.layer_properties.specVersion); auto props = layer.layer_properties; @@ -93,7 +94,6 @@ void DumpLayers(Printer &p, std::vector layers, const std::v p.AddNewline(); } } - p.IndentIncrease(); break; } @@ -212,7 +212,7 @@ void DumpPresentableSurfaces(Printer &p, AppInstance &inst, const std::vector> &surfaces) { p.SetHeader(); ObjectWrapper obj(p, "Presentable Surfaces"); - p.IndentDecrease(); + IndentWrapper indent(p); std::vector surface_list; @@ -240,7 +240,6 @@ void DumpPresentableSurfaces(Printer &p, AppInstance &inst, const std::vector> printers; + std::ostream out(std::cout.rdbuf()); + std::ofstream html_out; + std::ofstream vkconfig_out; - AppInstance instance = {}; - SetupWindowExtensions(instance); + // if any essential vulkan call fails, it throws an exception + try { + AppInstance instance = {}; + SetupWindowExtensions(instance); - auto pNext_chains = get_chain_infos(); + auto pNext_chains = get_chain_infos(); - auto phys_devices = instance.FindPhysicalDevices(); + auto phys_devices = instance.FindPhysicalDevices(); - std::vector> surfaces; + std::vector> surfaces; #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \ defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_WAYLAND_KHR) - for (auto &surface_extension : instance.surface_extensions) { - surface_extension.create_window(instance); - surface_extension.surface = surface_extension.create_surface(instance); - for (auto &phys_device : phys_devices) { - surfaces.push_back(std::unique_ptr( - new AppSurface(instance, phys_device, surface_extension, pNext_chains.surface_capabilities2))); + for (auto &surface_extension : instance.surface_extensions) { + surface_extension.create_window(instance); + surface_extension.surface = surface_extension.create_surface(instance); + for (auto &phys_device : phys_devices) { + surfaces.push_back(std::unique_ptr( + new AppSurface(instance, phys_device, surface_extension, pNext_chains.surface_capabilities2))); + } } - } #endif - std::vector> gpus; + std::vector> gpus; - uint32_t gpu_counter = 0; - for (auto &phys_device : phys_devices) { - gpus.push_back(std::unique_ptr(new AppGpu(instance, gpu_counter++, phys_device, pNext_chains))); - } - - if (selected_gpu >= gpus.size()) { - std::cout << "The selected gpu (" << selected_gpu << ") is not in the valid range of 0 to " << gpus.size() - 1 << ".\n"; - return 0; - } - - std::vector> printers; + uint32_t gpu_counter = 0; + for (auto &phys_device : phys_devices) { + gpus.push_back(std::unique_ptr(new AppGpu(instance, gpu_counter++, phys_device, pNext_chains))); + } - std::streambuf *buf; - buf = std::cout.rdbuf(); - std::ostream out(buf); - std::ofstream html_out; - std::ofstream vkconfig_out; + if (selected_gpu >= gpus.size()) { + std::cout << "The selected gpu (" << selected_gpu << ") is not in the valid range of 0 to " << gpus.size() - 1 << ".\n"; + return 0; + } - if (human_readable_output) { - printers.push_back(std::unique_ptr(new Printer(OutputType::text, out, selected_gpu, instance.vk_version))); - } - if (html_output) { - html_out = std::ofstream("vulkaninfo.html"); - printers.push_back(std::unique_ptr(new Printer(OutputType::html, html_out, selected_gpu, instance.vk_version))); - } - if (json_output) { - printers.push_back(std::unique_ptr(new Printer(OutputType::json, out, selected_gpu, instance.vk_version))); - } - if (vkconfig_output) { + if (human_readable_output) { + printers.push_back(std::unique_ptr(new Printer(OutputType::text, out, selected_gpu, instance.vk_version))); + } + if (html_output) { + html_out = std::ofstream("vulkaninfo.html"); + printers.push_back( + std::unique_ptr(new Printer(OutputType::html, html_out, selected_gpu, instance.vk_version))); + } + if (json_output) { + printers.push_back(std::unique_ptr(new Printer(OutputType::json, out, selected_gpu, instance.vk_version))); + } + if (vkconfig_output) { #ifdef WIN32 - vkconfig_out = std::ofstream(std::string(output_path) + "\\vulkaninfo.json"); + vkconfig_out = std::ofstream(std::string(output_path) + "\\vulkaninfo.json"); #else - vkconfig_out = std::ofstream(std::string(output_path) + "/vulkaninfo.json"); + vkconfig_out = std::ofstream(std::string(output_path) + "/vulkaninfo.json"); #endif - printers.push_back( - std::unique_ptr(new Printer(OutputType::vkconfig_output, vkconfig_out, selected_gpu, instance.vk_version))); - } + printers.push_back(std::unique_ptr( + new Printer(OutputType::vkconfig_output, vkconfig_out, selected_gpu, instance.vk_version))); + } - for (auto &p : printers) { - if (p->Type() == OutputType::json) { - DumpLayers(*p.get(), instance.global_layers, gpus); - DumpGpuJson(*p.get(), *gpus.at(selected_gpu).get()); + for (auto &p : printers) { + if (p->Type() == OutputType::json) { + DumpLayers(*p.get(), instance.global_layers, gpus); + DumpGpuJson(*p.get(), *gpus.at(selected_gpu).get()); - } else { - p->SetHeader(); - DumpExtensions(*p.get(), "Instance", instance.global_extensions); - p->AddNewline(); + } else { + p->SetHeader(); + DumpExtensions(*p.get(), "Instance", instance.global_extensions); + p->AddNewline(); - DumpLayers(*p.get(), instance.global_layers, gpus); + DumpLayers(*p.get(), instance.global_layers, gpus); #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \ defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_WAYLAND_KHR) - DumpPresentableSurfaces(*p.get(), instance, gpus, surfaces); + DumpPresentableSurfaces(*p.get(), instance, gpus, surfaces); #endif - DumpGroups(*p.get(), instance); + DumpGroups(*p.get(), instance); - p->SetHeader(); - ObjectWrapper obj(*p, "Device Properties and Extensions"); - p->IndentDecrease(); + p->SetHeader(); + ObjectWrapper obj(*p, "Device Properties and Extensions"); + IndentWrapper indent(*p); - for (auto &gpu : gpus) { - DumpGpu(*p.get(), *gpu.get(), show_formats); + for (auto &gpu : gpus) { + DumpGpu(*p.get(), *gpu.get(), show_formats); + } } - - p->IndentIncrease(); } - p.reset(); - } #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \ defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_WAYLAND_KHR) - for (auto &surface_extension : instance.surface_extensions) { - AppDestroySurface(instance, surface_extension.surface); - surface_extension.destroy_window(instance); - } + for (auto &surface_extension : instance.surface_extensions) { + AppDestroySurface(instance, surface_extension.surface); + surface_extension.destroy_window(instance); + } #endif + } catch (std::exception &e) { + // Print the error to stderr and leave all outputs in a valid state (mainly for json) + std::cerr << "ERROR at " << e.what() << "\n"; + for (auto &p : printers) { + if (p) { + p->FinishOutput(); + } + } + } + // Call the printer's descrtuctor before the file handle gets closed + for (auto &p : printers) { + p.reset(nullptr); + } WAIT_FOR_CONSOLE_DESTROY; #ifdef _WIN32 diff --git a/vulkaninfo/vulkaninfo.h b/vulkaninfo/vulkaninfo.h index ed0ed4e..bb83e70 100644 --- a/vulkaninfo/vulkaninfo.h +++ b/vulkaninfo/vulkaninfo.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -73,7 +74,33 @@ #include -#define ERR(err) std::cerr << __FILE__ << ":" << __LINE__ << ": failed with " << VkResultString(err) << "\n"; +static const char *VkResultString(VkResult err); + +// General error: Get file + line and a short message +struct FileLineException : std::runtime_error { + FileLineException(const std::string &arg, const char *file, int line) : runtime_error(arg) { + msg = std::string(file) + ":" + std::to_string(line) + ": " + arg; + } + ~FileLineException() throw() {} + const char *what() const throw() { return msg.c_str(); } + + private: + std::string msg; +}; +#define THROW_ERR(arg) throw FileLineException(arg, __FILE__, __LINE__); + +// Vulkan function error: Get name of function, file, line, and the error code returned by the function +struct VulkanException : std::runtime_error { + VulkanException(const std::string &function, const char *file, int line, VkResult err) : runtime_error(function) { + msg = std::string(file) + ":" + std::to_string(line) + ":" + function + " failed with " + VkResultString(err); + } + ~VulkanException() throw() {} + const char *what() const throw() { return msg.c_str(); } + + private: + std::string msg; +}; +#define THROW_VK_ERR(func_name, err) throw VulkanException(func_name, __FILE__, __LINE__, err); // global configuration bool human_readable_output = true; @@ -101,15 +128,6 @@ static int ConsoleIsExclusive(void) { #define WAIT_FOR_CONSOLE_DESTROY #endif -#define ERR_EXIT(err) \ - do { \ - ERR(err); \ - fflush(stdout); \ - fflush(stderr); \ - WAIT_FOR_CONSOLE_DESTROY; \ - exit(-1); \ - } while (0) - #ifdef _WIN32 #define _CALL_PFN(pfn, ...) (pfn) @@ -177,8 +195,6 @@ void FreeUser32Dll() { } #endif // _WIN32 -static const char *VkResultString(VkResult err); - const char *app_short_name = "vulkaninfo"; std::vector get_c_str_array(std::vector const &vec) { @@ -208,30 +224,30 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DbgCallback(VkDebugReportFlagsEXT msgFlags const char *pMsg, void *pUserData) { std::cerr << VkDebugReportFlagsEXTString(msgFlags) << ": [" << pLayerPrefix << "] Code " << msgCode << " : " << pMsg << "\n"; - // True is reserved for layer developers, and MAY mean calls are not distributed down the layer chain after validation error. - // False SHOULD always be returned by apps: + // True is reserved for layer developers, and MAY mean calls are not distributed down the layer chain after validation + // error. False SHOULD always be returned by apps: return VK_FALSE; } // Helper for robustly executing the two-call pattern template -auto GetVectorInit(F &&f, T init, Ts &&... ts) -> std::vector { +auto GetVectorInit(const char *func_name, F &&f, T init, Ts &&... ts) -> std::vector { uint32_t count = 0; std::vector results; VkResult err; do { err = f(ts..., &count, nullptr); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR(func_name, err); results.resize(count, init); err = f(ts..., &count, results.data()); } while (err == VK_INCOMPLETE); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR(func_name, err); return results; } template -auto GetVector(F &&f, Ts &&... ts) -> std::vector { - return GetVectorInit(f, T(), ts...); +auto GetVector(const char *func_name, F &&f, Ts &&... ts) -> std::vector { + return GetVectorInit(func_name, f, T(), ts...); } // ----------- Instance Setup ------- // @@ -470,7 +486,7 @@ void buildpNextChain(VkStructureHeader *first, const std::vectorpNext = static_cast(malloc(chain_info[i].mem_size)); if (!place->pNext) { - ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY); + THROW_ERR("buildpNextChain's malloc failed to allocate"); } std::memset(place->pNext, 0, chain_info[i].mem_size); place = place->pNext; @@ -565,10 +581,9 @@ struct AppInstance { ANativeWindow *window; #endif AppInstance() { - if (dll.Initialize() != VK_SUCCESS) { - std::cerr << "Failed to initialize: Vulkan loader is not installed, not found, or failed to load.\n"; - WAIT_FOR_CONSOLE_DESTROY; - exit(1); + VkResult dllErr = dll.Initialize(); + if (dllErr != VK_SUCCESS) { + THROW_ERR("Failed to initialize: Vulkan loader is not installed, not found, or failed to load."); } dll.InitializeDispatchPointers(); @@ -576,7 +591,7 @@ struct AppInstance { instance_version = VK_API_VERSION_1_0; } else { const VkResult err = dll.vkEnumerateInstanceVersion(&instance_version); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkEnumerateInstanceVersion", err); } // fallback to baked header version if loader returns 0 for the patch version @@ -606,9 +621,9 @@ struct AppInstance { std::cerr << "Cannot create Vulkan instance.\n"; std::cerr << "This problem is often caused by a faulty installation of the Vulkan driver or attempting to use a GPU " "that does not support Vulkan.\n"; - ERR_EXIT(err); + THROW_VK_ERR("vkCreateInstance", err); } else if (err) { - ERR_EXIT(err); + THROW_VK_ERR("vkCreateInstance", err); } ext_funcs.LoadInstanceExtensionDispatchPointers(dll.vkGetInstanceProcAddr, instance); } @@ -633,7 +648,8 @@ struct AppInstance { /* Gets a list of layer and instance extensions */ void AppGetInstanceExtensions() { /* Scan layers */ - auto global_layer_properties = GetVector(dll.vkEnumerateInstanceLayerProperties); + auto global_layer_properties = + GetVector("vkEnumerateInstanceLayerProperties", dll.vkEnumerateInstanceLayerProperties); global_layers.resize(global_layer_properties.size()); for (size_t i = 0; i < global_layer_properties.size(); i++) { @@ -656,11 +672,12 @@ struct AppInstance { void AddSurfaceExtension(SurfaceExtension ext) { surface_extensions.push_back(ext); } std::vector AppGetGlobalLayerExtensions(char *layer_name) { - return GetVector(dll.vkEnumerateInstanceExtensionProperties, layer_name); + return GetVector("vkEnumerateInstanceExtensionProperties", + dll.vkEnumerateInstanceExtensionProperties, layer_name); } std::vector FindPhysicalDevices() { - return GetVector(dll.vkEnumeratePhysicalDevices, instance); + return GetVector("vkEnumerateInstanceExtensionProperties", dll.vkEnumeratePhysicalDevices, instance); } }; @@ -696,8 +713,7 @@ static void AppCreateWin32Window(AppInstance &inst) { // Register window class: if (!CALL_PFN(RegisterClassExA)(&win_class)) { // It didn't work, so try to give a useful error: - fprintf(stderr, "Failed to register the window class!\n"); - exit(1); + THROW_ERR("Failed to register the window class!"); } // Create window with the registered class: RECT wr = {0, 0, inst.width, inst.height}; @@ -716,8 +732,7 @@ static void AppCreateWin32Window(AppInstance &inst) { nullptr); // no extra parameters if (!inst.h_wnd) { // It didn't work, so try to give a useful error: - fprintf(stderr, "Failed to create a window!\n"); - exit(1); + THROW_ERR("Failed to create a window!"); } } @@ -731,7 +746,7 @@ static VkSurfaceKHR AppCreateWin32Surface(AppInstance &inst) { VkSurfaceKHR surface; VkResult err = inst.dll.vkCreateWin32SurfaceKHR(inst.instance, &createInfo, nullptr, &surface); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkCreateWin32SurfaceKHR", err); return surface; } @@ -787,7 +802,7 @@ static void AppCreateXcbWindow(AppInstance &inst) { static VkSurfaceKHR AppCreateXcbSurface(AppInstance &inst) { if (!inst.xcb_connection) { - ERR_EXIT(VK_ERROR_INITIALIZATION_FAILED); + THROW_ERR("AppCreateXcbSurface failed to establish connection"); } VkXcbSurfaceCreateInfoKHR xcb_createInfo; @@ -799,7 +814,7 @@ static VkSurfaceKHR AppCreateXcbSurface(AppInstance &inst) { VkSurfaceKHR surface; VkResult err = inst.dll.vkCreateXcbSurfaceKHR(inst.instance, &xcb_createInfo, nullptr, &surface); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkCreateXcbSurfaceKHR", err); return surface; } @@ -822,8 +837,7 @@ static void AppCreateXlibWindow(AppInstance &inst) { inst.xlib_display = XOpenDisplay(nullptr); if (inst.xlib_display == nullptr) { - fprintf(stderr, "XLib failed to connect to the X server.\nExiting ...\n"); - exit(1); + THROW_ERR("XLib failed to connect to the X server.\nExiting..."); } XVisualInfo vInfoTemplate = {}; @@ -846,7 +860,7 @@ static VkSurfaceKHR AppCreateXlibSurface(AppInstance &inst) { VkSurfaceKHR surface; VkResult err = inst.dll.vkCreateXlibSurfaceKHR(inst.instance, &createInfo, nullptr, &surface); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkCreateXlibSurfaceKHR", err); return surface; } @@ -862,8 +876,7 @@ static void AppDestroyXlibWindow(AppInstance &inst) { static void AppCreateMacOSWindow(AppInstance &inst) { inst.macos_window = CreateMetalView(inst.width, inst.height); if (inst.macos_window == nullptr) { - fprintf(stderr, "Could not create a native Metal view.\nExiting...\n"); - exit(1); + THROW_ERR("Could not create a native Metal view.\nExiting..."); } } @@ -876,7 +889,7 @@ static VkSurfaceKHR AppCreateMacOSSurface(AppInstance &inst) { VkSurfaceKHR surface; VkResult err = inst.dll.vkCreateMacOSSurfaceMVK(inst.instance, &createInfo, nullptr, &surface); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkCreateMacOSSurfaceMVK", err); return surface; } @@ -889,8 +902,7 @@ static void AppDestroyMacOSWindow(AppInstance &inst) { DestroyMetalView(inst.mac static void AppCreateMetalWindow(AppInstance &inst) { inst.metal_window = CreateMetalView(inst.width, inst.height); if (inst.metal_window == nullptr) { - fprintf(stderr, "Could not create a native Metal view.\nExiting...\n"); - exit(1); + THROW_ERR("Could not create a native Metal view.\nExiting..."); } } @@ -903,7 +915,7 @@ static VkSurfaceKHR AppCreateMetalSurface(AppInstance &inst) { VkSurfaceKHR surface; VkResult err = inst.dll.vkCreateMetalSurfaceEXT(inst.instance, &createInfo, nullptr, &surface); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkCreateMetalSurfaceEXT", err); return surface; } @@ -942,7 +954,7 @@ static VkSurfaceKHR AppCreateWaylandSurface(AppInstance &inst) { VkSurfaceKHR surface; VkResult err = inst.dll.vkCreateWaylandSurfaceKHR(inst.instance, &createInfo, nullptr, &surface); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkCreateWaylandSurfaceKHR", err); return surface; } @@ -961,7 +973,7 @@ static VkSurfaceKHR AppCreateAndroidSurface(AppInstance &inst) { createInfo.window = (struct ANativeWindow *)(inst.window); err = inst.dll.vkCreateAndroidSurfaceKHR(inst.inst, &createInfo, NULL, &inst.surface); - EXIT_ERR(err); + THROW_VK_ERR("vkCreateAndroidSurfaceKHR", err); } static VkSurfaceKHR AppDestroyAndroidSurface(AppInstance &inst) {} #endif @@ -974,9 +986,8 @@ void SetupWindowExtensions(AppInstance &inst) { bool has_display = true; const char *display_var = getenv("DISPLAY"); if (display_var == nullptr || strlen(display_var) == 0) { - fprintf(stderr, "'DISPLAY' environment variable not set... skipping surface info\n"); - fflush(stderr); has_display = false; + THROW_ERR("'DISPLAY' environment variable not set... skipping surface info"); } #endif @@ -1100,7 +1111,8 @@ class AppSurface { : inst(inst), phys_device(phys_device), surface_extension(surface_extension), - surf_present_modes(GetVector(inst.ext_funcs.vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, + surf_present_modes(GetVector("vkGetPhysicalDeviceSurfacePresentModesKHR", + inst.ext_funcs.vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface_extension.surface)) { const VkPhysicalDeviceSurfaceInfo2KHR surface_info2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface_extension.surface}; @@ -1109,17 +1121,19 @@ class AppSurface { VkSurfaceFormat2KHR init; init.sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR; init.pNext = nullptr; - surf_formats2 = GetVectorInit(inst.ext_funcs.vkGetPhysicalDeviceSurfaceFormats2KHR, init, + surf_formats2 = GetVectorInit("vkGetPhysicalDeviceSurfaceFormats2KHR", + inst.ext_funcs.vkGetPhysicalDeviceSurfaceFormats2KHR, init, phys_device, &surface_info2); } else { - surf_formats = GetVector(inst.ext_funcs.vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, + surf_formats = GetVector("vkGetPhysicalDeviceSurfaceFormatsKHR", + inst.ext_funcs.vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface_extension.surface); } if (inst.CheckExtensionEnabled(VK_KHR_SURFACE_EXTENSION_NAME)) { VkResult err = inst.ext_funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_device, surface_extension.surface, &surface_capabilities); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkGetPhysicalDeviceSurfaceCapabilitiesKHR", err); } if (inst.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) { @@ -1133,7 +1147,7 @@ class AppSurface { VkResult err = inst.ext_funcs.vkGetPhysicalDeviceSurfaceCapabilities2KHR(phys_device, &surface_info, &surface_capabilities2_khr); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkGetPhysicalDeviceSurfaceCapabilities2KHR", err); } if (inst.CheckExtensionEnabled(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)) { @@ -1141,7 +1155,7 @@ class AppSurface { surface_capabilities2_ext.pNext = nullptr; VkResult err = inst.ext_funcs.vkGetPhysicalDeviceSurfaceCapabilities2EXT(phys_device, surface_extension.surface, &surface_capabilities2_ext); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkGetPhysicalDeviceSurfaceCapabilities2EXT", err); } } @@ -1159,7 +1173,8 @@ class AppSurface { std::vector GetGroups(AppInstance &inst) { if (inst.CheckExtensionEnabled(VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME)) { - return GetVector(inst.ext_funcs.vkEnumeratePhysicalDeviceGroupsKHR, inst.instance); + return GetVector("vkEnumeratePhysicalDeviceGroupsKHR", + inst.ext_funcs.vkEnumeratePhysicalDeviceGroupsKHR, inst.instance); } return {}; } @@ -1193,7 +1208,7 @@ std::pair GetGroupCapabilities(AppIns VkDevice logical_device = VK_NULL_HANDLE; VkResult err = inst.dll.vkCreateDevice(group.physicalDevices[0], &device_ci, nullptr, &logical_device); - if (err != VK_SUCCESS && err != VK_ERROR_EXTENSION_NOT_PRESENT) ERR_EXIT(err); + if (err != VK_SUCCESS && err != VK_ERROR_EXTENSION_NOT_PRESENT) THROW_VK_ERR("vkCreateDevice", err); if (err == VK_ERROR_EXTENSION_NOT_PRESENT) { VkDeviceGroupPresentCapabilitiesKHR group_capabilities = {VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR, nullptr}; @@ -1206,7 +1221,7 @@ std::pair GetGroupCapabilities(AppIns // If the KHR_device_group extension is present, write the capabilities of the logical device into a struct for later // output to user. err = inst.ext_funcs.vkGetDeviceGroupPresentCapabilitiesKHR(logical_device, &group_capabilities); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkGetDeviceGroupPresentCapabilitiesKHR", err); inst.dll.vkDestroyDevice(logical_device, nullptr); @@ -1293,7 +1308,6 @@ struct AppGpu { inst.ext_funcs.vkGetPhysicalDeviceProperties2KHR(phys_device, &props2); } - /* get queue count */ inst.dll.vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &queue_count, nullptr); @@ -1342,7 +1356,7 @@ struct AppGpu { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, nullptr, 0, 1, &q_ci, 0, nullptr, 0, nullptr, &enabled_features}; VkResult err = inst.dll.vkCreateDevice(phys_device, &device_ci, nullptr, &dev); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkCreateDevice", err); const VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM; const std::vector formats = { @@ -1431,11 +1445,11 @@ struct AppGpu { if (err == VK_ERROR_FORMAT_NOT_SUPPORTED) { *support = false; } else { - if (err) ERR_EXIT(err); + if (err != VK_SUCCESS) THROW_VK_ERR("vkGetPhysicalDeviceImageFormatProperties", err); VkImage dummy_img; err = inst.dll.vkCreateImage(dev, &image_ci, nullptr, &dummy_img); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkCreateImage", err); VkMemoryRequirements mem_req; inst.dll.vkGetImageMemoryRequirements(dev, dummy_img, &mem_req); @@ -1523,7 +1537,8 @@ struct AppGpu { } std::vector AppGetPhysicalDeviceLayerExtensions(char *layer_name) { - return GetVector(inst.dll.vkEnumerateDeviceExtensionProperties, phys_device, layer_name); + return GetVector("vkEnumerateDeviceExtensionProperties", + inst.dll.vkEnumerateDeviceExtensionProperties, phys_device, layer_name); } // Helper function to determine whether a format range is currently supported. @@ -1567,7 +1582,7 @@ struct AppQueueFamilyProperties { for (auto &surface_ext : gpu.inst.surface_extensions) { VkResult err = gpu.inst.ext_funcs.vkGetPhysicalDeviceSurfaceSupportKHR( gpu.phys_device, queue_index, surface_ext.surface, &surface_ext.supports_present); - if (err) ERR_EXIT(err); + if (err) THROW_VK_ERR("vkGetPhysicalDeviceSurfaceSupportKHR", err); const bool first = (surface_ext == gpu.inst.surface_extensions.at(0)); if (!first && platforms_support_present != surface_ext.supports_present) { @@ -1581,7 +1596,8 @@ struct AppQueueFamilyProperties { std::vector GetToolingInfo(AppGpu &gpu) { if (gpu.inst.ext_funcs.vkGetPhysicalDeviceToolPropertiesEXT == nullptr) return {}; - return GetVector(gpu.inst.ext_funcs.vkGetPhysicalDeviceToolPropertiesEXT, gpu.phys_device); + return GetVector("vkGetPhysicalDeviceToolPropertiesEXT", + gpu.inst.ext_funcs.vkGetPhysicalDeviceToolPropertiesEXT, gpu.phys_device); } // --------- Format Properties ----------// @@ -1626,7 +1642,6 @@ VkFormatProperties2 GetFormatProperties2(AppGpu &gpu, VkFormat format, pNextChai VkFormatProperties2 props; props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; buildpNextChain((VkStructureHeader *)&props, chainInfos.format_properties2); - gpu.inst.ext_funcs.vkGetPhysicalDeviceFormatProperties2KHR(gpu.phys_device, format, &props); return props; }