Added parsing of command line parameters and GPU selection
Command line syntax:
-h, --Help Print this information
-l, --List Print list of GPUs
-g S, --GPU S Select GPU with name containing S
-i N, --GPUIndex N Select GPU index N
Also improved error handling.
diff --git a/src/Common.cpp b/src/Common.cpp
index 20c0050..2dcbb68 100644
--- a/src/Common.cpp
+++ b/src/Common.cpp
@@ -204,6 +204,66 @@
return result;
}
+bool ConvertCharsToUnicode(std::wstring *outStr, const std::string &s, unsigned codePage)
+{
+ if (s.empty())
+ {
+ outStr->clear();
+ return true;
+ }
+
+ // Phase 1 - Get buffer size.
+ const int size = MultiByteToWideChar(codePage, 0, s.data(), (int)s.length(), NULL, 0);
+ if (size == 0)
+ {
+ outStr->clear();
+ return false;
+ }
+
+ // Phase 2 - Do conversion.
+ std::unique_ptr<wchar_t[]> buf(new wchar_t[(size_t)size]);
+ int result = MultiByteToWideChar(codePage, 0, s.data(), (int)s.length(), buf.get(), size);
+ if (result == 0)
+ {
+ outStr->clear();
+ return false;
+ }
+
+ outStr->assign(buf.get(), (size_t)size);
+ return true;
+}
+
+bool ConvertCharsToUnicode(std::wstring *outStr, const char *s, size_t sCharCount, unsigned codePage)
+{
+ if (sCharCount == 0)
+ {
+ outStr->clear();
+ return true;
+ }
+
+ assert(sCharCount <= (size_t)INT_MAX);
+
+ // Phase 1 - Get buffer size.
+ int size = MultiByteToWideChar(codePage, 0, s, (int)sCharCount, NULL, 0);
+ if (size == 0)
+ {
+ outStr->clear();
+ return false;
+ }
+
+ // Phase 2 - Do conversion.
+ std::unique_ptr<wchar_t[]> buf(new wchar_t[(size_t)size]);
+ int result = MultiByteToWideChar(codePage, 0, s, (int)sCharCount, buf.get(), size);
+ if (result == 0)
+ {
+ outStr->clear();
+ return false;
+ }
+
+ outStr->assign(buf.get(), (size_t)size);
+ return true;
+}
+
const wchar_t* PhysicalDeviceTypeToStr(VkPhysicalDeviceType type)
{
// Skipping common prefix VK_PHYSICAL_DEVICE_TYPE_
diff --git a/src/Common.h b/src/Common.h
index 20db651..a718234 100644
--- a/src/Common.h
+++ b/src/Common.h
@@ -323,6 +323,9 @@
void SaveFile(const wchar_t* filePath, const void* data, size_t dataSize);
std::wstring SizeToStr(size_t size);
+// As codePage use e.g. CP_ACP for native Windows 1-byte codepage or CP_UTF8.
+bool ConvertCharsToUnicode(std::wstring *outStr, const std::string &s, unsigned codePage);
+bool ConvertCharsToUnicode(std::wstring *outStr, const char *s, size_t sCharCount, unsigned codePage);
const wchar_t* PhysicalDeviceTypeToStr(VkPhysicalDeviceType type);
const wchar_t* VendorIDToStr(uint32_t vendorID);
diff --git a/src/VulkanSample.cpp b/src/VulkanSample.cpp
index e690f49..0d07cfb 100644
--- a/src/VulkanSample.cpp
+++ b/src/VulkanSample.cpp
@@ -27,6 +27,9 @@
#include "VmaUsage.h"
#include "Common.h"
#include <atomic>
+#include <Shlwapi.h>
+
+#pragma comment(lib, "shlwapi.lib")
static const char* const SHADER_PATH1 = "./";
static const char* const SHADER_PATH2 = "../bin/";
@@ -40,6 +43,15 @@
static void* const CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA = (void*)(intptr_t)43564544;
static const bool USE_CUSTOM_CPU_ALLOCATION_CALLBACKS = true;
+enum class ExitCode : int
+{
+ GPUList = 2,
+ Help = 1,
+ Success = 0,
+ RuntimeError = -1,
+ CommandLineError = -2,
+};
+
VkPhysicalDevice g_hPhysicalDevice;
VkDevice g_hDevice;
VmaAllocator g_hAllocator;
@@ -106,7 +118,6 @@
static PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT_Func;
static PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT_Func;
static PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT_Func;
-static VkDebugUtilsMessengerEXT g_DebugUtilsMessenger;
static VkQueue g_hGraphicsQueue;
VkQueue g_hSparseBindingQueue;
@@ -179,6 +190,63 @@
const VkAllocationCallbacks* g_Allocs;
+struct GPUSelection
+{
+ uint32_t Index = UINT32_MAX;
+ std::wstring Substring;
+};
+
+class VulkanUsage
+{
+public:
+ void Init();
+ ~VulkanUsage();
+ void PrintPhysicalDeviceList() const;
+ // If failed, returns VK_NULL_HANDLE.
+ VkPhysicalDevice SelectPhysicalDevice(const GPUSelection& GPUSelection) const;
+
+private:
+ VkDebugUtilsMessengerEXT m_DebugUtilsMessenger = VK_NULL_HANDLE;
+
+ void RegisterDebugCallbacks();
+ static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName);
+};
+
+struct CommandLineParameters
+{
+ bool m_Help = false;
+ bool m_List = false;
+ GPUSelection m_GPUSelection;
+
+ bool Parse(int argc, wchar_t** argv)
+ {
+ for(int i = 1; i < argc; ++i)
+ {
+ if(_wcsicmp(argv[i], L"-h") == 0 || _wcsicmp(argv[i], L"--Help") == 0)
+ {
+ m_Help = true;
+ }
+ else if(_wcsicmp(argv[i], L"-l") == 0 || _wcsicmp(argv[i], L"--List") == 0)
+ {
+ m_List = true;
+ }
+ else if((_wcsicmp(argv[i], L"-g") == 0 || _wcsicmp(argv[i], L"--GPU") == 0) && i + 1 < argc)
+ {
+ m_GPUSelection.Substring = argv[i + 1];
+ ++i;
+ }
+ else if((_wcsicmp(argv[i], L"-i") == 0 || _wcsicmp(argv[i], L"--GPUIndex") == 0) && i + 1 < argc)
+ {
+ m_GPUSelection.Index = _wtoi(argv[i + 1]);
+ ++i;
+ }
+ else
+ return false;
+ }
+ return true;
+ }
+} g_CommandLineParameters;
+
void SetDebugUtilsObjectName(VkObjectType type, uint64_t handle, const char* name)
{
if(vkSetDebugUtilsObjectNameEXT_Func == nullptr)
@@ -313,6 +381,223 @@
return result;
}
+static constexpr uint32_t GetVulkanApiVersion()
+{
+#if VMA_VULKAN_VERSION == 1002000
+ return VK_API_VERSION_1_2;
+#elif VMA_VULKAN_VERSION == 1001000
+ return VK_API_VERSION_1_1;
+#elif VMA_VULKAN_VERSION == 1000000
+ return VK_API_VERSION_1_0;
+#else
+#error Invalid VMA_VULKAN_VERSION.
+ return UINT32_MAX;
+#endif
+}
+
+void VulkanUsage::Init()
+{
+ g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
+
+ if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
+ {
+ g_Allocs = &g_CpuAllocationCallbacks;
+ }
+
+ uint32_t instanceLayerPropCount = 0;
+ ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
+ std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
+ if(instanceLayerPropCount > 0)
+ {
+ ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
+ }
+
+ if(g_EnableValidationLayer)
+ {
+ if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
+ {
+ wprintf(L"Layer \"%hs\" not supported.", VALIDATION_LAYER_NAME);
+ g_EnableValidationLayer = false;
+ }
+ }
+
+ uint32_t availableInstanceExtensionCount = 0;
+ ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, nullptr) );
+ std::vector<VkExtensionProperties> availableInstanceExtensions(availableInstanceExtensionCount);
+ if(availableInstanceExtensionCount > 0)
+ {
+ ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, availableInstanceExtensions.data()) );
+ }
+
+ std::vector<const char*> enabledInstanceExtensions;
+ enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
+ enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
+
+ std::vector<const char*> instanceLayers;
+ if(g_EnableValidationLayer)
+ {
+ instanceLayers.push_back(VALIDATION_LAYER_NAME);
+ }
+
+ for(const auto& extensionProperties : availableInstanceExtensions)
+ {
+ if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
+ {
+ if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
+ {
+ enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+ VK_KHR_get_physical_device_properties2_enabled = true;
+ }
+ }
+ else if(strcmp(extensionProperties.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
+ {
+ enabledInstanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ VK_EXT_debug_utils_enabled = true;
+ }
+ }
+
+ VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
+ appInfo.pApplicationName = APP_TITLE_A;
+ appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
+ appInfo.pEngineName = "Adam Sawicki Engine";
+ appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
+ appInfo.apiVersion = GetVulkanApiVersion();
+
+ VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
+ instInfo.pApplicationInfo = &appInfo;
+ instInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
+ instInfo.ppEnabledExtensionNames = enabledInstanceExtensions.data();
+ instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
+ instInfo.ppEnabledLayerNames = instanceLayers.data();
+
+ wprintf(L"Vulkan API version used: ");
+ switch(appInfo.apiVersion)
+ {
+ case VK_API_VERSION_1_0: wprintf(L"1.0\n"); break;
+ case VK_API_VERSION_1_1: wprintf(L"1.1\n"); break;
+ case VK_API_VERSION_1_2: wprintf(L"1.2\n"); break;
+ default: assert(0);
+ }
+
+ ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
+
+ if(VK_EXT_debug_utils_enabled)
+ {
+ RegisterDebugCallbacks();
+ }
+}
+
+VulkanUsage::~VulkanUsage()
+{
+ if(m_DebugUtilsMessenger)
+ {
+ vkDestroyDebugUtilsMessengerEXT_Func(g_hVulkanInstance, m_DebugUtilsMessenger, g_Allocs);
+ }
+
+ if(g_hVulkanInstance)
+ {
+ vkDestroyInstance(g_hVulkanInstance, g_Allocs);
+ g_hVulkanInstance = VK_NULL_HANDLE;
+ }
+}
+
+void VulkanUsage::PrintPhysicalDeviceList() const
+{
+ uint32_t deviceCount = 0;
+ ERR_GUARD_VULKAN(vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr));
+ std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
+ if(deviceCount > 0)
+ {
+ ERR_GUARD_VULKAN(vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()));
+ }
+
+ for(size_t i = 0; i < deviceCount; ++i)
+ {
+ VkPhysicalDeviceProperties props = {};
+ vkGetPhysicalDeviceProperties(physicalDevices[i], &props);
+ wprintf(L"Physical device %zu: %hs\n", i, props.deviceName);
+ }
+}
+
+VkPhysicalDevice VulkanUsage::SelectPhysicalDevice(const GPUSelection& GPUSelection) const
+{
+ uint32_t deviceCount = 0;
+ ERR_GUARD_VULKAN(vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr));
+ std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
+ if(deviceCount > 0)
+ {
+ ERR_GUARD_VULKAN(vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()));
+ }
+
+ if(GPUSelection.Index != UINT32_MAX)
+ {
+ // Cannot specify both index and name.
+ if(!GPUSelection.Substring.empty())
+ {
+ return VK_NULL_HANDLE;
+ }
+
+ return GPUSelection.Index < deviceCount ? physicalDevices[GPUSelection.Index] : VK_NULL_HANDLE;
+ }
+
+ if(!GPUSelection.Substring.empty())
+ {
+ VkPhysicalDevice result = VK_NULL_HANDLE;
+ std::wstring name;
+ for(uint32_t i = 0; i < deviceCount; ++i)
+ {
+ VkPhysicalDeviceProperties props = {};
+ vkGetPhysicalDeviceProperties(physicalDevices[i], &props);
+ if(ConvertCharsToUnicode(&name, props.deviceName, strlen(props.deviceName), CP_UTF8) &&
+ StrStrI(name.c_str(), GPUSelection.Substring.c_str()))
+ {
+ // Second matching device found - error.
+ if(result != VK_NULL_HANDLE)
+ {
+ return VK_NULL_HANDLE;
+ }
+ // First matching device found.
+ result = physicalDevices[i];
+ }
+ }
+ // Found or not, return it.
+ return result;
+ }
+
+ // Select first one.
+ return deviceCount > 0 ? physicalDevices[0] : VK_NULL_HANDLE;
+}
+
+void VulkanUsage::RegisterDebugCallbacks()
+{
+ vkCreateDebugUtilsMessengerEXT_Func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
+ g_hVulkanInstance, "vkCreateDebugUtilsMessengerEXT");
+ vkDestroyDebugUtilsMessengerEXT_Func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
+ g_hVulkanInstance, "vkDestroyDebugUtilsMessengerEXT");
+ vkSetDebugUtilsObjectNameEXT_Func = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(
+ g_hVulkanInstance, "vkSetDebugUtilsObjectNameEXT");
+ assert(vkCreateDebugUtilsMessengerEXT_Func);
+ assert(vkDestroyDebugUtilsMessengerEXT_Func);
+ assert(vkSetDebugUtilsObjectNameEXT_Func);
+
+ VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT };
+ messengerCreateInfo.messageSeverity = DEBUG_UTILS_MESSENGER_MESSAGE_SEVERITY;
+ messengerCreateInfo.messageType = DEBUG_UTILS_MESSENGER_MESSAGE_TYPE;
+ messengerCreateInfo.pfnUserCallback = MyDebugReportCallback;
+ ERR_GUARD_VULKAN( vkCreateDebugUtilsMessengerEXT_Func(g_hVulkanInstance, &messengerCreateInfo, g_Allocs, &m_DebugUtilsMessenger) );
+}
+
+bool VulkanUsage::IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
+{
+ const VkLayerProperties* propsEnd = pProps + propCount;
+ return std::find_if(
+ pProps,
+ propsEnd,
+ [pLayerName](const VkLayerProperties& prop) -> bool {
+ return strcmp(pLayerName, prop.layerName) == 0;
+ }) != propsEnd;
+}
+
struct Vertex
{
float pos[3];
@@ -575,44 +860,6 @@
mat4 ModelViewProj;
};
-static void RegisterDebugCallbacks()
-{
- vkCreateDebugUtilsMessengerEXT_Func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
- g_hVulkanInstance, "vkCreateDebugUtilsMessengerEXT");
- vkDestroyDebugUtilsMessengerEXT_Func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
- g_hVulkanInstance, "vkDestroyDebugUtilsMessengerEXT");
- vkSetDebugUtilsObjectNameEXT_Func = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(
- g_hVulkanInstance, "vkSetDebugUtilsObjectNameEXT");
- assert(vkCreateDebugUtilsMessengerEXT_Func);
- assert(vkDestroyDebugUtilsMessengerEXT_Func);
- assert(vkSetDebugUtilsObjectNameEXT_Func);
-
- VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT };
- messengerCreateInfo.messageSeverity = DEBUG_UTILS_MESSENGER_MESSAGE_SEVERITY;
- messengerCreateInfo.messageType = DEBUG_UTILS_MESSENGER_MESSAGE_TYPE;
- messengerCreateInfo.pfnUserCallback = MyDebugReportCallback;
- ERR_GUARD_VULKAN( vkCreateDebugUtilsMessengerEXT_Func(g_hVulkanInstance, &messengerCreateInfo, g_Allocs, &g_DebugUtilsMessenger) );
-}
-
-static void UnregisterDebugCallbacks()
-{
- if(g_DebugUtilsMessenger)
- {
- vkDestroyDebugUtilsMessengerEXT_Func(g_hVulkanInstance, g_DebugUtilsMessenger, g_Allocs);
- }
-}
-
-static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
-{
- const VkLayerProperties* propsEnd = pProps + propCount;
- return std::find_if(
- pProps,
- propsEnd,
- [pLayerName](const VkLayerProperties& prop) -> bool {
- return strcmp(pLayerName, prop.layerName) == 0;
- }) != propsEnd;
-}
-
static VkFormat FindSupportedFormat(
const std::vector<VkFormat>& candidates,
VkImageTiling tiling,
@@ -1110,20 +1357,6 @@
}
}
-static constexpr uint32_t GetVulkanApiVersion()
-{
-#if VMA_VULKAN_VERSION == 1002000
- return VK_API_VERSION_1_2;
-#elif VMA_VULKAN_VERSION == 1001000
- return VK_API_VERSION_1_1;
-#elif VMA_VULKAN_VERSION == 1000000
- return VK_API_VERSION_1_0;
-#else
- #error Invalid VMA_VULKAN_VERSION.
- return UINT32_MAX;
-#endif
-}
-
static void PrintEnabledFeatures()
{
wprintf(L"Enabled extensions and features:\n");
@@ -1522,93 +1755,6 @@
static void InitializeApplication()
{
- if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
- {
- g_Allocs = &g_CpuAllocationCallbacks;
- }
-
- uint32_t instanceLayerPropCount = 0;
- ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
- std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
- if(instanceLayerPropCount > 0)
- {
- ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
- }
-
- if(g_EnableValidationLayer)
- {
- if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
- {
- wprintf(L"Layer \"%hs\" not supported.", VALIDATION_LAYER_NAME);
- g_EnableValidationLayer = false;
- }
- }
-
- uint32_t availableInstanceExtensionCount = 0;
- ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, nullptr) );
- std::vector<VkExtensionProperties> availableInstanceExtensions(availableInstanceExtensionCount);
- if(availableInstanceExtensionCount > 0)
- {
- ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, availableInstanceExtensions.data()) );
- }
-
- std::vector<const char*> enabledInstanceExtensions;
- enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
- enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
-
- std::vector<const char*> instanceLayers;
- if(g_EnableValidationLayer)
- {
- instanceLayers.push_back(VALIDATION_LAYER_NAME);
- }
-
- for(const auto& extensionProperties : availableInstanceExtensions)
- {
- if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
- {
- if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
- {
- enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
- VK_KHR_get_physical_device_properties2_enabled = true;
- }
- }
- else if(strcmp(extensionProperties.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
- {
- enabledInstanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
- VK_EXT_debug_utils_enabled = true;
- }
- }
-
- VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
- appInfo.pApplicationName = APP_TITLE_A;
- appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
- appInfo.pEngineName = "Adam Sawicki Engine";
- appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
- appInfo.apiVersion = GetVulkanApiVersion();
-
- VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
- instInfo.pApplicationInfo = &appInfo;
- instInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
- instInfo.ppEnabledExtensionNames = enabledInstanceExtensions.data();
- instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
- instInfo.ppEnabledLayerNames = instanceLayers.data();
-
- wprintf(L"Vulkan API version used: ");
- switch(appInfo.apiVersion)
- {
- case VK_API_VERSION_1_0: wprintf(L"1.0\n"); break;
- case VK_API_VERSION_1_1: wprintf(L"1.1\n"); break;
- case VK_API_VERSION_1_2: wprintf(L"1.2\n"); break;
- default: assert(0);
- }
-
- ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
-
- if(VK_EXT_debug_utils_enabled)
- {
- RegisterDebugCallbacks();
- }
-
// Create VkSurfaceKHR.
VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
surfaceInfo.hinstance = g_hAppInstance;
@@ -1616,17 +1762,6 @@
VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
assert(result == VK_SUCCESS);
- // Find physical device
-
- uint32_t deviceCount = 0;
- ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
- assert(deviceCount > 0);
-
- std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
- ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
-
- g_hPhysicalDevice = physicalDevices[0];
-
// Query for device extensions
uint32_t physicalDeviceExtensionPropertyCount = 0;
@@ -2102,14 +2237,6 @@
vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
g_hSurface = VK_NULL_HANDLE;
}
-
- UnregisterDebugCallbacks();
-
- if(g_hVulkanInstance != VK_NULL_HANDLE)
- {
- vkDestroyInstance(g_hVulkanInstance, g_Allocs);
- g_hVulkanInstance = VK_NULL_HANDLE;
- }
}
static void PrintAllocatorStats()
@@ -2272,6 +2399,18 @@
}
}
+#define CATCH_PRINT_ERROR(extraCatchCode) \
+ catch(const std::exception& ex) \
+ { \
+ fwprintf(stderr, L"ERROR: %hs\n", ex.what()); \
+ extraCatchCode \
+ } \
+ catch(...) \
+ { \
+ fwprintf(stderr, L"UNKNOWN ERROR.\n"); \
+ extraCatchCode \
+ }
+
static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
@@ -2279,12 +2418,20 @@
case WM_CREATE:
// This is intentionally assigned here because we are now inside CreateWindow, before it returns.
g_hWnd = hWnd;
- InitializeApplication();
+ try
+ {
+ InitializeApplication();
+ }
+ CATCH_PRINT_ERROR(return -1;)
//PrintAllocatorStats();
return 0;
case WM_DESTROY:
- FinalizeApplication();
+ try
+ {
+ FinalizeApplication();
+ }
+ CATCH_PRINT_ERROR(;)
PostQuitMessage(0);
return 0;
@@ -2296,11 +2443,21 @@
case WM_SIZE:
if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
- HandlePossibleSizeChange();
+ {
+ try
+ {
+ HandlePossibleSizeChange();
+ }
+ CATCH_PRINT_ERROR(DestroyWindow(hWnd);)
+ }
return 0;
case WM_EXITSIZEMOVE:
- HandlePossibleSizeChange();
+ try
+ {
+ HandlePossibleSizeChange();
+ }
+ CATCH_PRINT_ERROR(DestroyWindow(hWnd);)
return 0;
case WM_KEYDOWN:
@@ -2314,17 +2471,18 @@
{
Test();
}
- catch(const std::exception& ex)
- {
- printf("ERROR: %s\n", ex.what());
- }
+ CATCH_PRINT_ERROR(;)
break;
case 'S':
try
{
if(g_SparseBindingEnabled)
{
- TestSparseBinding();
+ try
+ {
+ TestSparseBinding();
+ }
+ CATCH_PRINT_ERROR(;)
}
else
{
@@ -2346,10 +2504,24 @@
return DefWindowProc(hWnd, msg, wParam, lParam);
}
-int main()
+static void PrintLogo()
{
- g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
+ wprintf(L"%s\n", APP_TITLE_W);
+}
+static void PrintHelp()
+{
+ wprintf(
+ L"Command line syntax:\n"
+ L"-h, --Help Print this information\n"
+ L"-l, --List Print list of GPUs\n"
+ L"-g S, --GPU S Select GPU with name containing S\n"
+ L"-i N, --GPUIndex N Select GPU index N\n"
+ );
+}
+
+int MainWindow()
+{
WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
wndClassDesc.hbrBackground = NULL;
@@ -2387,11 +2559,51 @@
DrawFrame();
}
- TEST(g_CpuAllocCount.load() == 0);
-
- return 0;
+ return (int)msg.wParam;;
}
+int Main2(int argc, wchar_t** argv)
+{
+ PrintLogo();
+
+ if(!g_CommandLineParameters.Parse(argc, argv))
+ {
+ wprintf(L"ERROR: Invalid command line syntax.\n");
+ PrintHelp();
+ return (int)ExitCode::CommandLineError;
+ }
+
+ if(g_CommandLineParameters.m_Help)
+ {
+ PrintHelp();
+ return (int)ExitCode::Help;
+ }
+
+ VulkanUsage vulkanUsage;
+ vulkanUsage.Init();
+
+ if(g_CommandLineParameters.m_List)
+ {
+ vulkanUsage.PrintPhysicalDeviceList();
+ return (int)ExitCode::GPUList;
+ }
+
+ g_hPhysicalDevice = vulkanUsage.SelectPhysicalDevice(g_CommandLineParameters.m_GPUSelection);
+ TEST(g_hPhysicalDevice);
+
+ return MainWindow();
+}
+
+int wmain(int argc, wchar_t** argv)
+{
+ try
+ {
+ return Main2(argc, argv);
+ TEST(g_CpuAllocCount.load() == 0);
+ }
+ CATCH_PRINT_ERROR(return (int)ExitCode::RuntimeError;)
+}
+
#else // #ifdef _WIN32
#include "VmaUsage.h"