diff options
| author | Charles Giessen <charles@lunarg.com> | 2021-06-18 16:30:10 -0600 |
|---|---|---|
| committer | Charles Giessen <46324611+charles-lunarg@users.noreply.github.com> | 2021-11-29 13:03:31 -0700 |
| commit | b991aa399063a9f2388dadfd2f425754d20f747f (patch) | |
| tree | 6209e8f4ac76d786a8e992937efa600b1fef3265 | |
| parent | ed290a0f0ac7bd364aed9937a842af39031c49fa (diff) | |
| download | usermoji-b991aa399063a9f2388dadfd2f425754d20f747f.tar.xz | |
vulkaninfo: Refactor Win32 function loading
The only reason there were global booleans to decide which output to use was due to the macro
WAIT_FOR_CONSOLE_DESTROY. This commit restructures how the win32 function loading operates so
that such globals are no longer necessary. It introduces an OutputCategory enum to declare which
output format to use.
| -rw-r--r-- | vulkaninfo/vulkaninfo.cpp | 169 | ||||
| -rw-r--r-- | vulkaninfo/vulkaninfo.h | 160 |
2 files changed, 153 insertions, 176 deletions
diff --git a/vulkaninfo/vulkaninfo.cpp b/vulkaninfo/vulkaninfo.cpp index 79acf5f4..2a681b42 100644 --- a/vulkaninfo/vulkaninfo.cpp +++ b/vulkaninfo/vulkaninfo.cpp @@ -29,19 +29,6 @@ #include "vulkaninfo.hpp" -#ifdef _WIN32 -// Initialize User32 pointers -PFN_AdjustWindowRect User32Handles::pfnAdjustWindowRect = nullptr; -PFN_CreateWindowExA User32Handles::pfnCreateWindowExA = nullptr; -PFN_DefWindowProcA User32Handles::pfnDefWindowProcA = nullptr; -PFN_DestroyWindow User32Handles::pfnDestroyWindow = nullptr; -PFN_LoadIconA User32Handles::pfnLoadIconA = nullptr; -PFN_RegisterClassExA User32Handles::pfnRegisterClassExA = nullptr; - -HMODULE User32Handles::user32DllHandle = nullptr; - -#endif - // =========== Dump Functions ========= // void DumpExtensions(Printer &p, std::string layer_name, std::vector<VkExtensionProperties> extensions, bool do_indent) { @@ -812,6 +799,18 @@ static void ConsoleEnlarge() { } #endif +// Global configuration +enum class OutputCategory { + text, + html, + devsim_json, + vkconfig_output, +#if defined(VK_ENABLE_BETA_EXTENSIONS) + portability_json, +#endif + summary +}; + void print_usage(const char *argv0) { std::cout << "\nvulkaninfo - Summarize Vulkan information in relation to the current environment.\n\n"; std::cout << "USAGE: " << argv0 << " [options]\n\n"; @@ -846,51 +845,47 @@ 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(); - if (!LoadUser32Dll()) { + User32Handles local_user32_handles; + user32_handles = &local_user32_handles; + if (local_user32_handles.load()) { fprintf(stderr, "Failed to load user32.dll library!\n"); - WAIT_FOR_CONSOLE_DESTROY; + if (output_category == OutputCategory::text) wait_for_console_destroy(); exit(1); } #endif - uint32_t selected_gpu = 0; - bool show_tool_props = false; - bool show_formats = false; - char *output_path = nullptr; - // Combinations of output: html only, html AND json, json only, human readable only for (int i = 1; i < argc; ++i) { // A internal-use-only format for communication with the Vulkan Configurator tool // Usage "--vkconfig_output <path>" if (0 == strcmp("--vkconfig_output", argv[i]) && argc > (i + 1)) { - human_readable_output = false; - vkconfig_output = true; + output_category = OutputCategory::vkconfig_output; 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<uint32_t>(strtol(argv[i] + 7, nullptr, 10)); } - human_readable_output = false; - json_output = true; - portability_json = false; + 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<uint32_t>(strtol(argv[i] + 14, nullptr, 10)); } - human_readable_output = false; - portability_json = true; - json_output = false; + output_category = OutputCategory::portability_json; #endif // defined(VK_ENABLE_BETA_EXTENSIONS) } else if (strcmp(argv[i], "--summary") == 0) { - summary = true; + output_category = OutputCategory::summary; } else if (strcmp(argv[i], "--html") == 0) { - human_readable_output = false; - html_output = true; + output_category = OutputCategory::html; } else if (strcmp(argv[i], "--show-tool-props") == 0) { show_tool_props = true; } else if (strcmp(argv[i], "--show-formats") == 0) { @@ -905,10 +900,7 @@ int main(int argc, char **argv) { } std::vector<std::unique_ptr<Printer>> printers; std::ostream out(std::cout.rdbuf()); - std::ofstream json_out; - std::ofstream portability_out; - std::ofstream html_out; - std::ofstream vkconfig_out; + std::ofstream file_out; // if any essential vulkan call fails, it throws an exception try { @@ -950,73 +942,77 @@ int main(int argc, char **argv) { std::cout << "The available GPUs are in the range of 0 to " << gpus.size() - 1 << ".\n"; return 0; } - - if (human_readable_output) { - printers.push_back(std::unique_ptr<Printer>(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<Printer>(new Printer(OutputType::html, html_out, selected_gpu, instance.vk_version))); - } - if (json_output) { - 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 - json_out = std::ofstream("vulkaninfo.json"); - printers.push_back( - std::unique_ptr<Printer>(new Printer(OutputType::json, json_out, selected_gpu, instance.vk_version, start_string))); -#else - printers.push_back( - std::unique_ptr<Printer>(new Printer(OutputType::json, out, selected_gpu, instance.vk_version, start_string))); -#endif - } -#if defined(VK_ENABLE_BETA_EXTENSIONS) - if (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"; - } else { + switch (output_category) { + default: + case (OutputCategory::text): + printers.push_back(std::unique_ptr<Printer>(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<Printer>(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_VK_KHR_portability_subset-provisional-1.json#\",\n") + + 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) + - "'s (" + gpus.at(selected_gpu)->props.deviceName + - "( portability features and properties. Generated using the vulkaninfo program.\",\n\t\t\"vulkanApiVersion\": " - "\"" + + " (" + 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 - portability_out = std::ofstream("portability.json"); + file_out = std::ofstream("vulkaninfo.json"); printers.push_back(std::unique_ptr<Printer>( - new Printer(OutputType::json, portability_out, selected_gpu, instance.vk_version, start_string))); + new Printer(OutputType::json, file_out, selected_gpu, instance.vk_version, start_string))); #else printers.push_back( std::unique_ptr<Printer>(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"; + } 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<Printer>( + new Printer(OutputType::json, portability_out, selected_gpu, instance.vk_version, start_string))); +#else + printers.push_back(std::unique_ptr<Printer>( + new Printer(OutputType::json, out, selected_gpu, instance.vk_version, start_string))); +#endif + } + break; #endif // defined(VK_ENABLE_BETA_EXTENSIONS) - if (vkconfig_output) { + case (OutputCategory::vkconfig_output): { #ifdef WIN32 - vkconfig_out = std::ofstream(std::string(output_path) + "\\vulkaninfo.json"); + file_out = std::ofstream(std::string(output_path) + "\\vulkaninfo.json"); #else - vkconfig_out = std::ofstream(std::string(output_path) + "/vulkaninfo.json"); + 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<Printer>( - new Printer(OutputType::vkconfig_output, vkconfig_out, selected_gpu, instance.vk_version, start_string))); + std::string start_string = "{\n\t\"Vulkan Instance Version\": \"" + VkVersionString(instance.vk_version) + "\""; + printers.push_back(std::unique_ptr<Printer>( + new Printer(OutputType::vkconfig_output, file_out, selected_gpu, instance.vk_version, start_string))); + break; + } } for (auto &p : printers) { #ifdef VK_USE_PLATFORM_IOS_MVK p->SetAlwaysOpenDetails(true); #endif - if (summary) { + if (output_category == OutputCategory::summary) { DumpSummaryInstance(*p.get(), instance); p->SetHeader(); ObjectWrapper obj(*p, "Devices"); @@ -1025,11 +1021,11 @@ int main(int argc, char **argv) { DumpSummaryGPU(*p.get(), *gpu.get()); } } else if (p->Type() == OutputType::json) { - if (portability_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 (json_output) { + } else if (output_category == OutputCategory::devsim_json) { DumpLayers(*p.get(), instance.global_layers, gpus); DumpGpuJson(*p.get(), *gpus.at(selected_gpu).get()); } @@ -1081,9 +1077,8 @@ int main(int argc, char **argv) { p.reset(nullptr); } - WAIT_FOR_CONSOLE_DESTROY; #ifdef _WIN32 - FreeUser32Dll(); + if (output_category == OutputCategory::text) wait_for_console_destroy(); #endif return 0; diff --git a/vulkaninfo/vulkaninfo.h b/vulkaninfo/vulkaninfo.h index 6dcb9f1c..31f8c594 100644 --- a/vulkaninfo/vulkaninfo.h +++ b/vulkaninfo/vulkaninfo.h @@ -108,14 +108,6 @@ struct VulkanException : std::runtime_error { }; #define THROW_VK_ERR(func_name, err) throw VulkanException(func_name, __FILE__, __LINE__, err); -// Global configuration (Used by Windows WAIT_FOR_CONSOLE_DESTROY MACRO) -bool human_readable_output = true; -bool html_output = false; -bool json_output = false; -bool vkconfig_output = false; -bool portability_json = false; -bool summary = false; - #ifdef _WIN32 #define strdup _strdup @@ -127,80 +119,70 @@ static int ConsoleIsExclusive(void) { DWORD num_pids = GetConsoleProcessList(pids, ARRAYSIZE(pids)); return num_pids <= 1; } - -#define WAIT_FOR_CONSOLE_DESTROY \ - do { \ - if (ConsoleIsExclusive() && human_readable_output) Sleep(INFINITE); \ - } while (0) -#else -#define WAIT_FOR_CONSOLE_DESTROY -#endif - -#ifdef _WIN32 - -#define _CALL_PFN(pfn, ...) (pfn) -#define CALL_PFN(fncName) _CALL_PFN(User32Handles::pfn##fncName) - -#define _CHECK_PFN(pfn, fncName) \ - do { \ - if (pfn == nullptr) { \ - fprintf(stderr, "Failed to get %s function address!\n", fncName); \ - WAIT_FOR_CONSOLE_DESTROY; \ - exit(1); \ - } \ - } while (false) - -#define _SET_PFN(dllHandle, pfnType, pfn, fncName) \ - do { \ - pfn = reinterpret_cast<pfnType>(GetProcAddress(dllHandle, fncName)); \ - _CHECK_PFN(pfn, fncName); \ - } while (false) - -#define SET_PFN(dllHandle, fncName) _SET_PFN(User32Handles::dllHandle, PFN_##fncName, User32Handles::pfn##fncName, #fncName) +void wait_for_console_destroy() { + if (ConsoleIsExclusive()) Sleep(INFINITE); +} // User32 function declarations -typedef WINUSERAPI BOOL(WINAPI *PFN_AdjustWindowRect)(_Inout_ LPRECT, _In_ DWORD, _In_ BOOL); -typedef WINUSERAPI HWND(WINAPI *PFN_CreateWindowExA)(_In_ DWORD, _In_opt_ LPCSTR, _In_opt_ LPCSTR, _In_ DWORD, _In_ int, _In_ int, - _In_ int, _In_ int, _In_opt_ HWND, _In_opt_ HMENU, _In_opt_ HINSTANCE, - _In_opt_ LPVOID); -typedef WINUSERAPI LRESULT(WINAPI *PFN_DefWindowProcA)(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM); -typedef WINUSERAPI BOOL(WINAPI *PFN_DestroyWindow)(_In_ HWND); -typedef WINUSERAPI HICON(WINAPI *PFN_LoadIconA)(_In_opt_ HINSTANCE, _In_ LPCSTR); -typedef WINUSERAPI ATOM(WINAPI *PFN_RegisterClassExA)(_In_ CONST WNDCLASSEXA *); +using PFN_AdjustWindowRect = WINUSERAPI BOOL(WINAPI *)(_Inout_ LPRECT, _In_ DWORD, _In_ BOOL); +using PFN_CreateWindowExA = WINUSERAPI HWND(WINAPI *)(_In_ DWORD, _In_opt_ LPCSTR, _In_opt_ LPCSTR, _In_ DWORD, _In_ int, _In_ int, + _In_ int, _In_ int, _In_opt_ HWND, _In_opt_ HMENU, _In_opt_ HINSTANCE, + _In_opt_ LPVOID); +using PFN_DefWindowProcA = WINUSERAPI LRESULT(WINAPI *)(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM); +using PFN_DestroyWindow = WINUSERAPI BOOL(WINAPI *)(_In_ HWND); +using PFN_LoadIconA = WINUSERAPI HICON(WINAPI *)(_In_opt_ HINSTANCE, _In_ LPCSTR); +using PFN_RegisterClassExA = WINUSERAPI ATOM(WINAPI *)(_In_ CONST WNDCLASSEXA *); struct User32Handles { - // User32 function pointers - static PFN_AdjustWindowRect pfnAdjustWindowRect; - static PFN_CreateWindowExA pfnCreateWindowExA; - static PFN_DefWindowProcA pfnDefWindowProcA; - static PFN_DestroyWindow pfnDestroyWindow; - static PFN_LoadIconA pfnLoadIconA; - static PFN_RegisterClassExA pfnRegisterClassExA; - // User32 dll handle - static HMODULE user32DllHandle; -}; + HMODULE user32DllHandle = nullptr; -bool LoadUser32Dll() { - User32Handles::user32DllHandle = LoadLibraryExA("user32.dll", nullptr, 0); - if (User32Handles::user32DllHandle != NULL) { - SET_PFN(user32DllHandle, AdjustWindowRect); - SET_PFN(user32DllHandle, CreateWindowExA); - SET_PFN(user32DllHandle, DefWindowProcA); - SET_PFN(user32DllHandle, DestroyWindow); - SET_PFN(user32DllHandle, LoadIconA); - SET_PFN(user32DllHandle, RegisterClassExA); + // User32 function pointers + PFN_AdjustWindowRect pfnAdjustWindowRect = nullptr; + PFN_CreateWindowExA pfnCreateWindowExA = nullptr; + PFN_DefWindowProcA pfnDefWindowProcA = nullptr; + PFN_DestroyWindow pfnDestroyWindow = nullptr; + PFN_LoadIconA pfnLoadIconA = nullptr; + PFN_RegisterClassExA pfnRegisterClassExA = nullptr; + + User32Handles() noexcept {} + ~User32Handles() noexcept { + if (user32DllHandle != nullptr) { + FreeLibrary(user32DllHandle); + } + } + // Don't allow moving of this class + User32Handles(User32Handles const &) = delete; + User32Handles &operator=(User32Handles const &) = delete; + User32Handles(User32Handles &&) = delete; + User32Handles &operator=(User32Handles &&) = delete; + + bool load() { + user32DllHandle = LoadLibraryExA("user32.dll", nullptr, 0); + if (user32DllHandle == nullptr) return false; + if (!load_function(pfnAdjustWindowRect, "AdjustWindowRect")) return false; + if (!load_function(pfnCreateWindowExA, "CreateWindowExA")) return false; + if (!load_function(pfnDefWindowProcA, "DefWindowProcA")) return false; + if (!load_function(pfnDestroyWindow, "DestroyWindow")) return false; + if (!load_function(pfnLoadIconA, "LoadIconA")) return false; + if (!load_function(pfnRegisterClassExA, "RegisterClassExA")) return false; return true; } - return false; -} -void FreeUser32Dll() { - if (User32Handles::user32DllHandle != nullptr) { - FreeLibrary(User32Handles::user32DllHandle); - User32Handles::user32DllHandle = nullptr; + private: + template <typename T> + bool load_function(T &function_pointer, const char *function_name) { + function_pointer = reinterpret_cast<T>(GetProcAddress(user32DllHandle, function_name)); + if (function_pointer == nullptr) { + fprintf(stderr, "Failed to load function: %s\n", function_name); + return false; + } + return true; } -} +}; + +// Global user handles function used in windows callback and code +User32Handles *user32_handles; #endif // _WIN32 const char *app_short_name = "vulkaninfo"; @@ -756,7 +738,7 @@ struct AppInstance { // MS-Windows event handling function: LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - return (CALL_PFN(DefWindowProcA)(hWnd, uMsg, wParam, lParam)); + return user32_handles->pfnDefWindowProcA(hWnd, uMsg, wParam, lParam); } static void AppCreateWin32Window(AppInstance &inst) { @@ -771,33 +753,33 @@ static void AppCreateWin32Window(AppInstance &inst) { win_class.cbClsExtra = 0; win_class.cbWndExtra = 0; win_class.hInstance = inst.h_instance; - win_class.hIcon = CALL_PFN(LoadIconA)(nullptr, IDI_APPLICATION); + win_class.hIcon = user32_handles->pfnLoadIconA(nullptr, IDI_APPLICATION); win_class.hCursor = LoadCursor(nullptr, IDC_ARROW); win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); win_class.lpszMenuName = nullptr; win_class.lpszClassName = app_short_name; win_class.hInstance = inst.h_instance; - win_class.hIconSm = CALL_PFN(LoadIconA)(nullptr, IDI_WINLOGO); + win_class.hIconSm = user32_handles->pfnLoadIconA(nullptr, IDI_WINLOGO); // Register window class: - if (!CALL_PFN(RegisterClassExA)(&win_class)) { + if (!user32_handles->pfnRegisterClassExA(&win_class)) { // It didn't work, so try to give a useful error: THROW_ERR("Failed to register the window class!"); } // Create window with the registered class: RECT wr = {0, 0, inst.width, inst.height}; - CALL_PFN(AdjustWindowRect)(&wr, WS_OVERLAPPEDWINDOW, FALSE); - inst.h_wnd = CALL_PFN(CreateWindowExA)(0, - app_short_name, // class name - app_short_name, // app name - // WS_VISIBLE | WS_SYSMENU | - WS_OVERLAPPEDWINDOW, // window style - 100, 100, // x/y coords - wr.right - wr.left, // width - wr.bottom - wr.top, // height - nullptr, // handle to parent - nullptr, // handle to menu - inst.h_instance, // hInstance - nullptr); // no extra parameters + user32_handles->pfnAdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); + inst.h_wnd = user32_handles->pfnCreateWindowExA(0, + app_short_name, // class name + app_short_name, // app name + // WS_VISIBLE | WS_SYSMENU | + WS_OVERLAPPEDWINDOW, // window style + 100, 100, // x/y coords + wr.right - wr.left, // width + wr.bottom - wr.top, // height + nullptr, // handle to parent + nullptr, // handle to menu + inst.h_instance, // hInstance + nullptr); // no extra parameters if (!inst.h_wnd) { // It didn't work, so try to give a useful error: THROW_ERR("Failed to create a window!"); |
