From 181bcce094cefd4df30861b760ff1779bfb65fce Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Fri, 18 Jun 2021 18:32:32 -0600 Subject: vulkaninfo: Refactor main function The main funciton was a chonky 300+ lines of code, this commit pulls out some of the sections into their own functions to make it easier to read. It also simplifies the logic in many places by doing so. --- vulkaninfo/vulkaninfo.cpp | 341 +++++++++++++++++++++++++--------------------- 1 file changed, 186 insertions(+), 155 deletions(-) (limited to 'vulkaninfo/vulkaninfo.cpp') diff --git a/vulkaninfo/vulkaninfo.cpp b/vulkaninfo/vulkaninfo.cpp index ef172bbf..70cb30f7 100644 --- a/vulkaninfo/vulkaninfo.cpp +++ b/vulkaninfo/vulkaninfo.cpp @@ -841,66 +841,183 @@ void print_usage(const char *argv0) { std::cout << "--summary Show a summary of the instance and GPU's on a system.\n\n"; } -#ifdef VK_USE_PLATFORM_IOS_MVK -// On iOS, we'll call this ourselves from a parent routine in the GUI -int vulkanInfoMain(int argc, char **argv) { -#else -int main(int argc, char **argv) { -#endif - OutputCategory output_category = OutputCategory::text; - uint32_t selected_gpu = 0; - bool show_tool_props = false; - bool show_formats = false; - char *output_path = nullptr; - -#ifdef _WIN32 - if (ConsoleIsExclusive()) ConsoleEnlarge(); - User32Handles local_user32_handles; - user32_handles = &local_user32_handles; - if (local_user32_handles.load()) { - fprintf(stderr, "Failed to load user32.dll library!\n"); - if (output_category == OutputCategory::text) wait_for_console_destroy(); - exit(1); - } -#endif +struct ParsedResults { + OutputCategory output_category; + uint32_t selected_gpu; + bool has_selected_gpu; // differentiate between selecting the 0th gpu and using the default 0th value + bool show_tool_props; + bool show_formats; + char *output_path; +}; - // Combinations of output: html only, html AND json, json only, human readable only +util::trivial_optional parse_arguments(int argc, char **argv) { + ParsedResults results{}; // default it to zero init everything for (int i = 1; i < argc; ++i) { // A internal-use-only format for communication with the Vulkan Configurator tool // Usage "--vkconfig_output " if (0 == strcmp("--vkconfig_output", argv[i]) && argc > (i + 1)) { - output_category = OutputCategory::vkconfig_output; - output_path = argv[i + 1]; + results.output_category = OutputCategory::vkconfig_output; + results.output_path = argv[i + 1]; ++i; } else if (strncmp("--json", argv[i], 6) == 0 || strcmp(argv[i], "-j") == 0) { if (strlen(argv[i]) > 7 && strncmp("--json=", argv[i], 7) == 0) { - selected_gpu = static_cast(strtol(argv[i] + 7, nullptr, 10)); + results.selected_gpu = static_cast(strtol(argv[i] + 7, nullptr, 10)); + results.has_selected_gpu = true; } - output_category = OutputCategory::devsim_json; + results.output_category = OutputCategory::devsim_json; #if defined(VK_ENABLE_BETA_EXTENSIONS) } else if (strncmp("--portability", argv[i], 13) == 0) { if (strlen(argv[i]) > 14 && strncmp("--portability=", argv[i], 14) == 0) { - selected_gpu = static_cast(strtol(argv[i] + 14, nullptr, 10)); + results.selected_gpu = static_cast(strtol(argv[i] + 14, nullptr, 10)); } - output_category = OutputCategory::portability_json; + results.output_category = OutputCategory::portability_json; #endif // defined(VK_ENABLE_BETA_EXTENSIONS) } else if (strcmp(argv[i], "--summary") == 0) { - output_category = OutputCategory::summary; + results.output_category = OutputCategory::summary; } else if (strcmp(argv[i], "--html") == 0) { - output_category = OutputCategory::html; } else if (strcmp(argv[i], "--show-tool-props") == 0) { - show_tool_props = true; + results.show_tool_props = true; } else if (strcmp(argv[i], "--show-formats") == 0) { - show_formats = true; - } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { print_usage(argv[0]); - return 1; + return {}; } else { print_usage(argv[0]); - return 1; + return {}; + } + } + return results; +} +struct PrinterCreateDetails { + OutputType output_type = OutputType::text; + bool use_file_output = false; + std::string file_name = "vulkaninfo.txt"; + std::string start_string = ""; +}; + +PrinterCreateDetails get_printer_create_details(ParsedResults &parse_data, AppInstance &inst, AppGpu &selected_gpu) { + PrinterCreateDetails create{}; + + switch (parse_data.output_category) { + default: + case (OutputCategory::text): + // Default values are for the text output + break; + case (OutputCategory::html): + create.output_type = OutputType::html; + create.file_name = "vulkaninfo.html"; + create.use_file_output = true; + break; + case (OutputCategory::devsim_json): + create.output_type = OutputType::json; + create.start_string = std::string("{\n\t\"$schema\": \"https://schema.khronos.org/vulkan/devsim_1_0_0.json#\",\n") + + "\t\"comments\": {\n\t\t\"desc\": \"JSON configuration file describing GPU " + + std::to_string(parse_data.selected_gpu) + " (" + selected_gpu.props.deviceName + + "). Generated using the vulkaninfo program.\",\n\t\t\"vulkanApiVersion\": \"" + + VkVersionString(inst.vk_version) + "\"\n" + "\t}"; +#ifdef VK_USE_PLATFORM_IOS_MVK + create.file_name = "vulkaninfo.json"; + create.use_file_output = true; +#endif + break; +#if defined(VK_ENABLE_BETA_EXTENSIONS) + case (OutputCategory::portability_json): + create.output_type = OutputType::json; + create.start_string = + std::string( + "{\n\t\"$schema\": " + "\"https://schema.khronos.org/vulkan/devsim_VK_KHR_portability_subset-provisional-1.json#\",\n") + + "\t\"comments\": {\n\t\t\"desc\": \"JSON configuration file describing GPU " + + std::to_string(parse_data.selected_gpu) + "'s (" + selected_gpu.props.deviceName + + "( portability features and properties. Generated using the vulkaninfo " + "program.\",\n\t\t\"vulkanApiVersion\": " + "\"" + + VkVersionString(inst.vk_version) + "\"\n" + "\t}"; +#ifdef VK_USE_PLATFORM_IOS_MVK + create.file_name = "portability.json"; + create.use_file_output = true; +#endif + break; +#endif // defined(VK_ENABLE_BETA_EXTENSIONS) + + case (OutputCategory::vkconfig_output): + create.output_type = OutputType::vkconfig_output; +#ifdef WIN32 + create.file_name = std::string(parse_data.output_path) + "\\vulkaninfo.json"; +#else + create.file_name = std::string(parse_data.output_path) + "/vulkaninfo.json"; +#endif + create.use_file_output = true; + create.start_string = "{\n\t\"Vulkan Instance Version\": \"" + VkVersionString(inst.vk_version) + "\""; + break; + } + return create; +} + +void RunPrinter(Printer &p, ParsedResults parse_data, AppInstance &instance, std::vector> &gpus, + std::vector> &surfaces) { +#ifdef VK_USE_PLATFORM_IOS_MVK + p.SetAlwaysOpenDetails(true); +#endif + if (parse_data.output_category == OutputCategory::summary) { + DumpSummaryInstance(p, instance); + p.SetHeader(); + ObjectWrapper obj(p, "Devices"); + IndentWrapper indent(p); + for (auto &gpu : gpus) { + DumpSummaryGPU(p, *(gpu.get())); + } + } +#if defined(VK_ENABLE_BETA_EXTENSIONS) + else if (parse_data.output_category == OutputCategory::portability_json) { + DumpPortability(p, *(gpus.at(parse_data.selected_gpu).get())); +#endif // defined(VK_ENABLE_BETA_EXTENSIONS) + } else if (parse_data.output_category == OutputCategory::devsim_json) { + DumpLayers(p, instance.global_layers, gpus); + DumpGpuJson(p, *(gpus.at(parse_data.selected_gpu).get())); + } else { + // text, html, vkconfig_output + p.SetHeader(); + DumpExtensions(p, "Instance", instance.global_extensions); + p.AddNewline(); + + DumpLayers(p, instance.global_layers, gpus); + // Doesn't print anything if no surfaces are available + DumpPresentableSurfaces(p, instance, gpus, surfaces); + DumpGroups(p, instance); + + p.SetHeader(); + ObjectWrapper obj(p, "Device Properties and Extensions"); + IndentWrapper indent(p); + + for (auto &gpu : gpus) { + DumpGpu(p, *(gpu.get()), parse_data.show_tool_props, parse_data.show_formats); } } - std::vector> printers; +} + +#ifdef VK_USE_PLATFORM_IOS_MVK +// On iOS, we'll call this ourselves from a parent routine in the GUI +int vulkanInfoMain(int argc, char **argv) { +#else +int main(int argc, char **argv) { +#endif + + auto parsing_return = parse_arguments(argc, argv); + if (!parsing_return) return 1; + ParsedResults parse_data = parsing_return.value(); + +#ifdef _WIN32 + if (ConsoleIsExclusive()) ConsoleEnlarge(); + User32Handles local_user32_handles; + user32_handles = &local_user32_handles; + if (!local_user32_handles.load()) { + fprintf(stderr, "Failed to load user32.dll library!\n"); + if (parse_data.output_category == OutputCategory::text) wait_for_console_destroy(); + return 1; + } +#endif + + std::unique_ptr printer; std::ostream out(std::cout.rdbuf()); std::ofstream file_out; @@ -930,123 +1047,41 @@ int main(int argc, char **argv) { 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 a valid GPU index. "; - if (gpus.size() == 0) - std::cout << "There are no available GPUs.\n"; - else if (gpus.size() == 1) - std::cout << "The only available GPU selection is 0.\n"; - else - std::cout << "The available GPUs are in the range of 0 to " << gpus.size() - 1 << ".\n"; - return 0; - } - switch (output_category) { - default: - case (OutputCategory::text): - printers.push_back(std::unique_ptr(new Printer(OutputType::text, out, selected_gpu, instance.vk_version))); - break; - case (OutputCategory::html): - file_out = std::ofstream("vulkaninfo.html"); - printers.push_back( - std::unique_ptr(new Printer(OutputType::html, file_out, selected_gpu, instance.vk_version))); - break; - case (OutputCategory::devsim_json): { - std::string start_string = - std::string("{\n\t\"$schema\": \"https://schema.khronos.org/vulkan/devsim_1_0_0.json#\",\n") + - "\t\"comments\": {\n\t\t\"desc\": \"JSON configuration file describing GPU " + std::to_string(selected_gpu) + - " (" + gpus.at(selected_gpu)->props.deviceName + - "). Generated using the vulkaninfo program.\",\n\t\t\"vulkanApiVersion\": \"" + - VkVersionString(instance.vk_version) + "\"\n" + "\t}"; -#ifdef VK_USE_PLATFORM_IOS_MVK - file_out = std::ofstream("vulkaninfo.json"); - printers.push_back(std::unique_ptr( - new Printer(OutputType::json, file_out, selected_gpu, instance.vk_version, start_string))); -#else - printers.push_back( - std::unique_ptr(new Printer(OutputType::json, out, selected_gpu, instance.vk_version, start_string))); -#endif - } break; -#if defined(VK_ENABLE_BETA_EXTENSIONS) - case (OutputCategory::portability_json): - if (!gpus.at(selected_gpu)->CheckPhysicalDeviceExtensionIncluded(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) { - std::cerr << "Cannot create a json because the current selected GPU (" << selected_gpu - << ") does not support the VK_KHR_portability_subset extension.\n"; + if (parse_data.selected_gpu >= gpus.size()) { + if (parse_data.has_selected_gpu) { + std::cout << "The selected gpu (" << parse_data.selected_gpu << ") is not a valid GPU index. "; + if (gpus.size() == 0) { + std::cout << "vulkaninfo could not find any GPU's.\n"; + } + if (gpus.size() == 1) { + std::cout << "The only available GPU selection is 0.\n"; } else { - std::string start_string = - std::string( - "{\n\t\"$schema\": " - "\"https://schema.khronos.org/vulkan/devsim_VK_KHR_portability_subset-provisional-1.json#\",\n") + - "\t\"comments\": {\n\t\t\"desc\": \"JSON configuration file describing GPU " + - std::to_string(selected_gpu) + "'s (" + gpus.at(selected_gpu)->props.deviceName + - "( portability features and properties. Generated using the vulkaninfo " - "program.\",\n\t\t\"vulkanApiVersion\": " - "\"" + - VkVersionString(instance.vk_version) + "\"\n" + "\t}"; -#ifdef VK_USE_PLATFORM_IOS_MVK - portability_out = std::ofstream("portability.json"); - printers.push_back(std::unique_ptr( - new Printer(OutputType::json, portability_out, selected_gpu, instance.vk_version, start_string))); -#else - printers.push_back(std::unique_ptr( - new Printer(OutputType::json, out, selected_gpu, instance.vk_version, start_string))); -#endif + std::cout << "The available GPUs are in the range of 0 to " << gpus.size() - 1 << ".\n"; } - break; -#endif // defined(VK_ENABLE_BETA_EXTENSIONS) - case (OutputCategory::vkconfig_output): { -#ifdef WIN32 - file_out = std::ofstream(std::string(output_path) + "\\vulkaninfo.json"); -#else - file_out = std::ofstream(std::string(output_path) + "/vulkaninfo.json"); -#endif - std::string start_string = "{\n\t\"Vulkan Instance Version\": \"" + VkVersionString(instance.vk_version) + "\""; - printers.push_back(std::unique_ptr( - new Printer(OutputType::vkconfig_output, file_out, selected_gpu, instance.vk_version, start_string))); - break; + return 1; + } else if (parse_data.output_category == OutputCategory::devsim_json || + parse_data.output_category == OutputCategory::portability_json) { + std::cout << "vulkaninfo could not find any GPU's.\n"; } } - for (auto &p : printers) { -#ifdef VK_USE_PLATFORM_IOS_MVK - p->SetAlwaysOpenDetails(true); -#endif - if (output_category == OutputCategory::summary) { - DumpSummaryInstance(*p.get(), instance); - p->SetHeader(); - ObjectWrapper obj(*p, "Devices"); - IndentWrapper indent(*p); - for (auto &gpu : gpus) { - DumpSummaryGPU(*p.get(), *gpu.get()); - } - } else if (p->Type() == OutputType::json) { - if (output_category == OutputCategory::portability_json) { #if defined(VK_ENABLE_BETA_EXTENSIONS) - DumpPortability(*p.get(), *gpus.at(selected_gpu).get()); -#endif // defined(VK_ENABLE_BETA_EXTENSIONS) - } else if (output_category == OutputCategory::devsim_json) { - DumpLayers(*p.get(), instance.global_layers, gpus); - DumpGpuJson(*p.get(), *gpus.at(selected_gpu).get()); - } - } else { - // text, html, vkconfig_output - p->SetHeader(); - DumpExtensions(*p.get(), "Instance", instance.global_extensions); - p->AddNewline(); - - DumpLayers(*p.get(), instance.global_layers, gpus); - // Doesn't print anything if no surfaces are available - DumpPresentableSurfaces(*p.get(), instance, gpus, surfaces); - DumpGroups(*p.get(), instance); - - p->SetHeader(); - ObjectWrapper obj(*p, "Device Properties and Extensions"); - IndentWrapper indent(*p); + if (parse_data.output_category == OutputCategory::portability_json && + !gpus.at(parse_data.selected_gpu)->CheckPhysicalDeviceExtensionIncluded(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) { + std::cerr << "Cannot create a json because the current selected GPU (" << parse_data.selected_gpu + << ") does not support the VK_KHR_portability_subset extension.\n"; + return 1; + } +#endif - for (auto &gpu : gpus) { - DumpGpu(*p.get(), *gpu.get(), show_tool_props, show_formats); - } - } + auto printer_data = get_printer_create_details(parse_data, instance, *gpus.at(parse_data.selected_gpu)); + if (printer_data.use_file_output) { + file_out = std::ofstream(printer_data.file_name); } + printer = std::unique_ptr(new Printer(printer_data.output_type, printer_data.use_file_output ? file_out : out, + parse_data.selected_gpu, instance.vk_version, printer_data.start_string)); + + RunPrinter(*(printer.get()), parse_data, instance, gpus, surfaces); for (auto &surface_extension : instance.surface_extensions) { AppDestroySurface(instance, surface_extension.surface); @@ -1055,19 +1090,15 @@ int main(int argc, char **argv) { } 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(); - } + if (printer) { + printer->FinishOutput(); } } - // Call the printer's descrtuctor before the file handle gets closed - for (auto &p : printers) { - p.reset(nullptr); - } + // Call the printer's destructor before the file handle gets closed + printer.reset(nullptr); #ifdef _WIN32 - if (output_category == OutputCategory::text) wait_for_console_destroy(); + if (parse_data.output_category == OutputCategory::text) wait_for_console_destroy(); #endif return 0; -- cgit v1.2.3