2 * Copyright (c) 2015-2020 The Khronos Group Inc.
3 * Copyright (c) 2015-2020 Valve Corporation
4 * Copyright (c) 2015-2020 LunarG, Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
19 * Author: David Pinedo <david@lunarg.com>
20 * Author: Mark Lobodzinski <mark@lunarg.com>
21 * Author: Rene Lindsay <rene@lunarg.com>
22 * Author: Jeremy Kniager <jeremyk@lunarg.com>
23 * Author: Shannon McPherson <shannon@lunarg.com>
24 * Author: Bob Ellison <bob@lunarg.com>
25 * Author: Charles Giessen <charles@lunarg.com>
38 #include <unordered_map>
50 #ifndef _POSIX_C_SOURCE
51 #define _POSIX_C_SOURCE 200809L
54 #define strndup(p, n) strdup(p)
63 #if defined(__linux__) || defined(__APPLE__)
67 #if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
68 #include <X11/Xutil.h>
71 #if defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)
72 #include "metal_view.h"
75 #include <vulkan/vulkan.h>
77 static const char *VkResultString(VkResult err);
79 // General error: Get file + line and a short message
80 struct FileLineException : std::runtime_error {
81 FileLineException(const std::string &arg, const char *file, int line) : runtime_error(arg) {
82 msg = std::string(file) + ":" + std::to_string(line) + ": " + arg;
84 ~FileLineException() throw() {}
85 const char *what() const throw() { return msg.c_str(); }
90 #define THROW_ERR(arg) throw FileLineException(arg, __FILE__, __LINE__);
92 // Vulkan function error: Get name of function, file, line, and the error code returned by the function
93 struct VulkanException : std::runtime_error {
94 VulkanException(const std::string &function, const char *file, int line, VkResult err) : runtime_error(function) {
95 msg = std::string(file) + ":" + std::to_string(line) + ":" + function + " failed with " + VkResultString(err);
97 ~VulkanException() throw() {}
98 const char *what() const throw() { return msg.c_str(); }
103 #define THROW_VK_ERR(func_name, err) throw VulkanException(func_name, __FILE__, __LINE__, err);
105 // global configuration
106 bool human_readable_output = true;
107 bool html_output = false;
108 bool json_output = false;
109 bool vkconfig_output = false;
113 #define strdup _strdup
115 // Returns nonzero if the console is used only for this process. Will return
116 // zero if another process (such as cmd.exe) is also attached.
117 static int ConsoleIsExclusive(void) {
119 DWORD num_pids = GetConsoleProcessList(pids, ARRAYSIZE(pids));
120 return num_pids <= 1;
123 #define WAIT_FOR_CONSOLE_DESTROY \
125 if (ConsoleIsExclusive() && human_readable_output) Sleep(INFINITE); \
128 #define WAIT_FOR_CONSOLE_DESTROY
133 #define _CALL_PFN(pfn, ...) (pfn)
134 #define CALL_PFN(fncName) _CALL_PFN(User32Handles::pfn##fncName)
136 #define _CHECK_PFN(pfn, fncName) \
138 if (pfn == nullptr) { \
139 fprintf(stderr, "Failed to get %s function address!\n", fncName); \
140 WAIT_FOR_CONSOLE_DESTROY; \
145 #define _SET_PFN(dllHandle, pfnType, pfn, fncName) \
147 pfn = reinterpret_cast<pfnType>(GetProcAddress(dllHandle, fncName)); \
148 _CHECK_PFN(pfn, fncName); \
151 #define SET_PFN(dllHandle, fncName) _SET_PFN(User32Handles::dllHandle, PFN_##fncName, User32Handles::pfn##fncName, #fncName)
153 // User32 function declarations
154 typedef WINUSERAPI BOOL(WINAPI *PFN_AdjustWindowRect)(_Inout_ LPRECT, _In_ DWORD, _In_ BOOL);
155 typedef WINUSERAPI HWND(WINAPI *PFN_CreateWindowExA)(_In_ DWORD, _In_opt_ LPCSTR, _In_opt_ LPCSTR, _In_ DWORD, _In_ int, _In_ int,
156 _In_ int, _In_ int, _In_opt_ HWND, _In_opt_ HMENU, _In_opt_ HINSTANCE,
158 typedef WINUSERAPI LRESULT(WINAPI *PFN_DefWindowProcA)(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM);
159 typedef WINUSERAPI BOOL(WINAPI *PFN_DestroyWindow)(_In_ HWND);
160 typedef WINUSERAPI HICON(WINAPI *PFN_LoadIconA)(_In_opt_ HINSTANCE, _In_ LPCSTR);
161 typedef WINUSERAPI ATOM(WINAPI *PFN_RegisterClassExA)(_In_ CONST WNDCLASSEXA *);
163 struct User32Handles {
164 // User32 function pointers
165 static PFN_AdjustWindowRect pfnAdjustWindowRect;
166 static PFN_CreateWindowExA pfnCreateWindowExA;
167 static PFN_DefWindowProcA pfnDefWindowProcA;
168 static PFN_DestroyWindow pfnDestroyWindow;
169 static PFN_LoadIconA pfnLoadIconA;
170 static PFN_RegisterClassExA pfnRegisterClassExA;
173 static HMODULE user32DllHandle;
176 bool LoadUser32Dll() {
177 User32Handles::user32DllHandle = LoadLibraryExA("user32.dll", nullptr, 0);
178 if (User32Handles::user32DllHandle != NULL) {
179 SET_PFN(user32DllHandle, AdjustWindowRect);
180 SET_PFN(user32DllHandle, CreateWindowExA);
181 SET_PFN(user32DllHandle, DefWindowProcA);
182 SET_PFN(user32DllHandle, DestroyWindow);
183 SET_PFN(user32DllHandle, LoadIconA);
184 SET_PFN(user32DllHandle, RegisterClassExA);
190 void FreeUser32Dll() {
191 if (User32Handles::user32DllHandle != nullptr) {
192 FreeLibrary(User32Handles::user32DllHandle);
193 User32Handles::user32DllHandle = nullptr;
198 const char *app_short_name = "vulkaninfo";
200 std::vector<const char *> get_c_str_array(std::vector<std::string> const &vec) {
201 std::vector<const char *> ret;
202 for (auto &str : vec) ret.push_back(str.c_str());
206 static const char *VkDebugReportFlagsEXTString(const VkDebugReportFlagsEXT flags) {
208 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
210 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
212 case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
214 case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
216 case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
222 static VKAPI_ATTR VkBool32 VKAPI_CALL DbgCallback(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType,
223 uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix,
224 const char *pMsg, void *pUserData) {
225 std::cerr << VkDebugReportFlagsEXTString(msgFlags) << ": [" << pLayerPrefix << "] Code " << msgCode << " : " << pMsg << "\n";
227 // True is reserved for layer developers, and MAY mean calls are not distributed down the layer chain after validation
228 // error. False SHOULD always be returned by apps:
232 // Helper for robustly executing the two-call pattern
233 template <typename T, typename F, typename... Ts>
234 auto GetVectorInit(const char *func_name, F &&f, T init, Ts &&... ts) -> std::vector<T> {
236 std::vector<T> results;
239 err = f(ts..., &count, nullptr);
240 if (err) THROW_VK_ERR(func_name, err);
241 results.resize(count, init);
242 err = f(ts..., &count, results.data());
243 results.resize(count);
244 } while (err == VK_INCOMPLETE);
245 if (err) THROW_VK_ERR(func_name, err);
249 template <typename T, typename F, typename... Ts>
250 auto GetVector(const char *func_name, F &&f, Ts &&... ts) -> std::vector<T> {
251 return GetVectorInit(func_name, f, T(), ts...);
254 // ----------- Instance Setup ------- //
256 VkResult Initialize() {
257 #if defined(__linux__)
258 library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
259 if (!library) library = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL);
260 #elif defined(_WIN32)
261 library = LoadLibrary(TEXT("vulkan-1.dll"));
263 #if !defined(__APPLE__)
264 if (library == 0) return VK_ERROR_INITIALIZATION_FAILED;
269 #if defined(__linux__)
271 #elif defined(_WIN32)
272 FreeLibrary(library);
274 #if !defined(__APPLE__)
279 #if defined(__APPLE__)
280 #define APPLE_FP(name) name
282 #define APPLE_FP(nama) nullptr
285 // Function pointers, loaded from the dll
286 PFN_vkCreateInstance fp_vkCreateInstance = APPLE_FP(vkCreateInstance);
287 PFN_vkEnumerateInstanceExtensionProperties fp_vkEnumerateInstanceExtensionProperties =
288 APPLE_FP(vkEnumerateInstanceExtensionProperties);
289 PFN_vkEnumerateInstanceLayerProperties fp_vkEnumerateInstanceLayerProperties = APPLE_FP(vkEnumerateInstanceLayerProperties);
290 PFN_vkDestroyInstance fp_vkDestroyInstance = APPLE_FP(vkDestroyInstance);
291 PFN_vkEnumeratePhysicalDevices fp_vkEnumeratePhysicalDevices = APPLE_FP(vkEnumeratePhysicalDevices);
292 PFN_vkGetPhysicalDeviceFeatures fp_vkGetPhysicalDeviceFeatures = APPLE_FP(vkGetPhysicalDeviceFeatures);
293 PFN_vkGetPhysicalDeviceFormatProperties fp_vkGetPhysicalDeviceFormatProperties = APPLE_FP(vkGetPhysicalDeviceFormatProperties);
294 PFN_vkGetPhysicalDeviceImageFormatProperties fp_vkGetPhysicalDeviceImageFormatProperties =
295 APPLE_FP(vkGetPhysicalDeviceImageFormatProperties);
296 PFN_vkGetPhysicalDeviceProperties fp_vkGetPhysicalDeviceProperties = APPLE_FP(vkGetPhysicalDeviceProperties);
297 PFN_vkGetPhysicalDeviceQueueFamilyProperties fp_vkGetPhysicalDeviceQueueFamilyProperties =
298 APPLE_FP(vkGetPhysicalDeviceQueueFamilyProperties);
299 PFN_vkGetPhysicalDeviceMemoryProperties fp_vkGetPhysicalDeviceMemoryProperties = APPLE_FP(vkGetPhysicalDeviceMemoryProperties);
300 PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = APPLE_FP(vkGetInstanceProcAddr);
301 PFN_vkGetDeviceProcAddr fp_vkGetDeviceProcAddr = APPLE_FP(vkGetDeviceProcAddr);
302 PFN_vkCreateDevice fp_vkCreateDevice = APPLE_FP(vkCreateDevice);
303 PFN_vkDestroyDevice fp_vkDestroyDevice = APPLE_FP(vkDestroyDevice);
304 PFN_vkEnumerateDeviceExtensionProperties fp_vkEnumerateDeviceExtensionProperties =
305 APPLE_FP(vkEnumerateDeviceExtensionProperties);
306 PFN_vkGetDeviceQueue fp_vkGetDeviceQueue = APPLE_FP(vkGetDeviceQueue);
307 PFN_vkCreateImage fp_vkCreateImage = APPLE_FP(vkCreateImage);
308 PFN_vkDestroyImage fp_vkDestroyImage = APPLE_FP(vkDestroyImage);
309 PFN_vkGetBufferMemoryRequirements fp_vkGetBufferMemoryRequirements = APPLE_FP(vkGetBufferMemoryRequirements);
310 PFN_vkGetImageMemoryRequirements fp_vkGetImageMemoryRequirements = APPLE_FP(vkGetImageMemoryRequirements);
311 PFN_vkGetImageSparseMemoryRequirements fp_vkGetImageSparseMemoryRequirements = APPLE_FP(vkGetImageSparseMemoryRequirements);
312 PFN_vkEnumerateInstanceVersion fp_vkEnumerateInstanceVersion = APPLE_FP(vkEnumerateInstanceVersion);
313 PFN_vkEnumeratePhysicalDeviceGroups fp_vkEnumeratePhysicalDeviceGroups = APPLE_FP(vkEnumeratePhysicalDeviceGroups);
314 PFN_vkGetPhysicalDeviceFeatures2 fp_vkGetPhysicalDeviceFeatures2 = APPLE_FP(vkGetPhysicalDeviceFeatures2);
315 PFN_vkGetPhysicalDeviceProperties2 fp_vkGetPhysicalDeviceProperties2 = APPLE_FP(vkGetPhysicalDeviceProperties2);
316 PFN_vkGetPhysicalDeviceFormatProperties2 fp_vkGetPhysicalDeviceFormatProperties2 =
317 APPLE_FP(vkGetPhysicalDeviceFormatProperties2);
318 PFN_vkGetPhysicalDeviceQueueFamilyProperties2 fp_vkGetPhysicalDeviceQueueFamilyProperties2 =
319 APPLE_FP(vkGetPhysicalDeviceQueueFamilyProperties2);
320 PFN_vkGetPhysicalDeviceMemoryProperties2 fp_vkGetPhysicalDeviceMemoryProperties2 =
321 APPLE_FP(vkGetPhysicalDeviceMemoryProperties2);
322 PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = APPLE_FP(vkDestroySurfaceKHR);
324 #ifdef VK_USE_PLATFORM_XLIB_KHR
325 PFN_vkCreateXlibSurfaceKHR fp_vkCreateXlibSurfaceKHR = APPLE_FP(vkCreateXlibSurfaceKHR);
326 #endif // VK_USE_PLATFORM_XLIB_KHR
327 #ifdef VK_USE_PLATFORM_XLIB_KHR
328 PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR fp_vkGetPhysicalDeviceXlibPresentationSupportKHR =
329 APPLE_FP(vkGetPhysicalDeviceXlibPresentationSupportKHR);
330 #endif // VK_USE_PLATFORM_XLIB_KHR
331 #ifdef VK_USE_PLATFORM_XCB_KHR
332 PFN_vkCreateXcbSurfaceKHR fp_vkCreateXcbSurfaceKHR = APPLE_FP(vkCreateXcbSurfaceKHR);
333 #endif // VK_USE_PLATFORM_XCB_KHR
334 #ifdef VK_USE_PLATFORM_XCB_KHR
335 PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR fp_vkGetPhysicalDeviceXcbPresentationSupportKHR =
336 APPLE_FP(vkGetPhysicalDeviceXcbPresentationSupportKHR);
337 #endif // VK_USE_PLATFORM_XCB_KHR
338 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
339 PFN_vkCreateWaylandSurfaceKHR fp_vkCreateWaylandSurfaceKHR = APPLE_FP(vkCreateWaylandSurfaceKHR);
340 #endif // VK_USE_PLATFORM_WAYLAND_KHR
341 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
342 PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR fp_vkGetPhysicalDeviceWaylandPresentationSupportKHR =
343 APPLE_FP(vkGetPhysicalDeviceWaylandPresentationSupportKHR);
344 #endif // VK_USE_PLATFORM_WAYLAND_KHR
345 #ifdef VK_USE_PLATFORM_ANDROID_KHR
346 PFN_vkCreateAndroidSurfaceKHR fp_vkCreateAndroidSurfaceKHR = APPLE_FP(vkCreateAndroidSurfaceKHR);
347 #endif // VK_USE_PLATFORM_ANDROID_KHR
348 #ifdef VK_USE_PLATFORM_WIN32_KHR
349 PFN_vkCreateWin32SurfaceKHR fp_vkCreateWin32SurfaceKHR = APPLE_FP(vkCreateWin32SurfaceKHR);
350 #endif // VK_USE_PLATFORM_WIN32_KHR
351 #ifdef VK_USE_PLATFORM_WIN32_KHR
352 PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR fp_vkGetPhysicalDeviceWin32PresentationSupportKHR =
353 APPLE_FP(vkGetPhysicalDeviceWin32PresentationSupportKHR);
354 #endif // VK_USE_PLATFORM_WIN32_KHR
355 #ifdef VK_USE_PLATFORM_MACOS_MVK
356 PFN_vkCreateMacOSSurfaceMVK fp_vkCreateMacOSSurfaceMVK = APPLE_FP(vkCreateMacOSSurfaceMVK);
357 #endif // VK_USE_PLATFORM_MACOS_MVK
358 #ifdef VK_USE_PLATFORM_METAL_EXT
359 PFN_vkCreateMetalSurfaceEXT fp_vkCreateMetalSurfaceEXT = APPLE_FP(vkCreateMetalSurfaceEXT);
360 #endif // VK_USE_PLATFORM_METAL_EXT
361 void InitializeDispatchPointers() {
362 Load(fp_vkCreateInstance, "vkCreateInstance");
363 Load(fp_vkDestroyInstance, "vkDestroyInstance");
364 Load(fp_vkEnumeratePhysicalDevices, "vkEnumeratePhysicalDevices");
365 Load(fp_vkGetPhysicalDeviceFeatures, "vkGetPhysicalDeviceFeatures");
366 Load(fp_vkGetPhysicalDeviceFormatProperties, "vkGetPhysicalDeviceFormatProperties");
367 Load(fp_vkGetPhysicalDeviceImageFormatProperties, "vkGetPhysicalDeviceImageFormatProperties");
368 Load(fp_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties");
369 Load(fp_vkGetPhysicalDeviceQueueFamilyProperties, "vkGetPhysicalDeviceQueueFamilyProperties");
370 Load(fp_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties");
371 Load(fp_vkGetInstanceProcAddr, "vkGetInstanceProcAddr");
372 Load(fp_vkGetDeviceProcAddr, "vkGetDeviceProcAddr");
373 Load(fp_vkCreateDevice, "vkCreateDevice");
374 Load(fp_vkDestroyDevice, "vkDestroyDevice");
375 Load(fp_vkEnumerateInstanceExtensionProperties, "vkEnumerateInstanceExtensionProperties");
376 Load(fp_vkEnumerateDeviceExtensionProperties, "vkEnumerateDeviceExtensionProperties");
377 Load(fp_vkEnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties");
378 Load(fp_vkGetDeviceQueue, "vkGetDeviceQueue");
379 Load(fp_vkCreateImage, "vkCreateImage");
380 Load(fp_vkDestroyImage, "vkDestroyImage");
381 Load(fp_vkGetBufferMemoryRequirements, "vkGetBufferMemoryRequirements");
382 Load(fp_vkGetImageMemoryRequirements, "vkGetImageMemoryRequirements");
383 Load(fp_vkGetImageSparseMemoryRequirements, "vkGetImageSparseMemoryRequirements");
384 Load(fp_vkEnumerateInstanceVersion, "vkEnumerateInstanceVersion");
385 Load(fp_vkEnumeratePhysicalDeviceGroups, "vkEnumeratePhysicalDeviceGroups");
386 Load(fp_vkGetPhysicalDeviceFeatures2, "vkGetPhysicalDeviceFeatures2");
387 Load(fp_vkGetPhysicalDeviceProperties2, "vkGetPhysicalDeviceProperties2");
388 Load(fp_vkGetPhysicalDeviceFormatProperties2, "vkGetPhysicalDeviceFormatProperties2");
389 Load(fp_vkGetPhysicalDeviceQueueFamilyProperties2, "vkGetPhysicalDeviceQueueFamilyProperties2");
390 Load(fp_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2");
391 Load(fp_vkDestroySurfaceKHR, "vkDestroySurfaceKHR");
393 #ifdef VK_USE_PLATFORM_XLIB_KHR
394 Load(fp_vkCreateXlibSurfaceKHR, "vkCreateXlibSurfaceKHR");
395 #endif // VK_USE_PLATFORM_XLIB_KHR
396 #ifdef VK_USE_PLATFORM_XLIB_KHR
397 Load(fp_vkGetPhysicalDeviceXlibPresentationSupportKHR, "vkGetPhysicalDeviceXlibPresentationSupportKHR");
398 #endif // VK_USE_PLATFORM_XLIB_KHR
399 #ifdef VK_USE_PLATFORM_XCB_KHR
400 Load(fp_vkCreateXcbSurfaceKHR, "vkCreateXcbSurfaceKHR");
401 #endif // VK_USE_PLATFORM_XCB_KHR
402 #ifdef VK_USE_PLATFORM_XCB_KHR
403 Load(fp_vkGetPhysicalDeviceXcbPresentationSupportKHR, "vkGetPhysicalDeviceXcbPresentationSupportKHR");
404 #endif // VK_USE_PLATFORM_XCB_KHR
405 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
406 Load(fp_vkCreateWaylandSurfaceKHR, "vkCreateWaylandSurfaceKHR");
407 #endif // VK_USE_PLATFORM_WAYLAND_KHR
408 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
409 Load(fp_vkGetPhysicalDeviceWaylandPresentationSupportKHR, "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
410 #endif // VK_USE_PLATFORM_WAYLAND_KHR
411 #ifdef VK_USE_PLATFORM_ANDROID_KHR
412 Load(fp_vkCreateAndroidSurfaceKHR, "vkCreateAndroidSurfaceKHR");
413 #endif // VK_USE_PLATFORM_ANDROID_KHR
414 #ifdef VK_USE_PLATFORM_WIN32_KHR
415 Load(fp_vkCreateWin32SurfaceKHR, "vkCreateWin32SurfaceKHR");
416 #endif // VK_USE_PLATFORM_WIN32_KHR
417 #ifdef VK_USE_PLATFORM_WIN32_KHR
418 Load(fp_vkGetPhysicalDeviceWin32PresentationSupportKHR, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
419 #endif // VK_USE_PLATFORM_WIN32_KHR
420 #ifdef VK_USE_PLATFORM_MACOS_MVK
421 Load(fp_vkCreateMacOSSurfaceMVK, "vkCreateMacOSSurfaceMVK");
422 #endif // VK_USE_PLATFORM_MACOS_MVK
423 #ifdef VK_USE_PLATFORM_METAL_EXT
424 Load(fp_vkCreateMetalSurfaceEXT, "vkCreateMetalSurfaceEXT");
425 #endif // VK_USE_PLATFORM_METAL_EXT
429 template <typename T>
430 void Load(T &func_dest, const char *func_name) {
431 #if defined(__linux__)
432 func_dest = reinterpret_cast<T>(dlsym(library, func_name));
433 #elif defined(_WIN32)
434 func_dest = reinterpret_cast<T>(GetProcAddress(library, func_name));
437 #if defined(__linux__)
439 #elif defined(_WIN32)
444 struct ExtensionFunctions {
445 // Extension pointers, loaded after instance is created
446 PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
447 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
448 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
449 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
450 PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR;
451 PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR;
452 PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
453 PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR;
454 PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR;
455 PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
456 PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR;
457 PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR;
458 PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT;
459 PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR;
460 PFN_vkGetPhysicalDeviceToolPropertiesEXT vkGetPhysicalDeviceToolPropertiesEXT;
462 void LoadInstanceExtensionDispatchPointers(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, VkInstance instance) {
463 this->instance = instance;
464 this->vkGetInstanceProcAddr = vkGetInstanceProcAddr;
465 Load(vkGetPhysicalDeviceSurfaceSupportKHR, "vkGetPhysicalDeviceSurfaceSupportKHR");
466 Load(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
467 Load(vkGetPhysicalDeviceSurfaceFormatsKHR, "vkGetPhysicalDeviceSurfaceFormatsKHR");
468 Load(vkGetPhysicalDeviceSurfaceFormats2KHR, "vkGetPhysicalDeviceSurfaceFormats2KHR");
469 Load(vkGetPhysicalDeviceSurfacePresentModesKHR, "vkGetPhysicalDeviceSurfacePresentModesKHR");
470 Load(vkGetDeviceGroupPresentCapabilitiesKHR, "vkGetDeviceGroupPresentCapabilitiesKHR");
471 Load(vkGetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2KHR");
472 Load(vkGetPhysicalDeviceFormatProperties2KHR, "vkGetPhysicalDeviceFormatProperties2KHR");
473 Load(vkGetPhysicalDeviceQueueFamilyProperties2KHR, "vkGetPhysicalDeviceQueueFamilyProperties2KHR");
474 Load(vkGetPhysicalDeviceFeatures2KHR, "vkGetPhysicalDeviceFeatures2KHR");
475 Load(vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR");
476 Load(vkGetPhysicalDeviceSurfaceCapabilities2KHR, "vkGetPhysicalDeviceSurfaceCapabilities2KHR");
477 Load(vkGetPhysicalDeviceSurfaceCapabilities2EXT, "vkGetPhysicalDeviceSurfaceCapabilities2EXT");
478 Load(vkEnumeratePhysicalDeviceGroupsKHR, "vkEnumeratePhysicalDeviceGroupsKHR");
479 Load(vkGetPhysicalDeviceToolPropertiesEXT, "vkGetPhysicalDeviceToolPropertiesEXT");
483 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
485 template <typename T>
486 void Load(T &dest, const char *name) {
487 dest = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name));
490 struct VkStructureHeader {
491 VkStructureType sType;
492 VkStructureHeader *pNext;
495 struct pNextChainBuildingBlockInfo {
496 VkStructureType sType;
500 void buildpNextChain(VkStructureHeader *first, const std::vector<pNextChainBuildingBlockInfo> &chain_info) {
501 VkStructureHeader *place = first;
503 for (uint32_t i = 0; i < chain_info.size(); i++) {
504 place->pNext = static_cast<VkStructureHeader *>(malloc(chain_info[i].mem_size));
506 THROW_ERR("buildpNextChain's malloc failed to allocate");
508 std::memset(place->pNext, 0, chain_info[i].mem_size);
509 place = place->pNext;
510 place->sType = chain_info[i].sType;
513 place->pNext = nullptr;
516 void freepNextChain(VkStructureHeader *first) {
517 VkStructureHeader *place = first;
518 VkStructureHeader *next = nullptr;
527 struct LayerExtensionList {
528 VkLayerProperties layer_properties{};
529 std::vector<VkExtensionProperties> extension_properties;
534 struct SurfaceExtension {
536 void (*create_window)(AppInstance &) = nullptr;
537 VkSurfaceKHR (*create_surface)(AppInstance &) = nullptr;
538 void (*destroy_window)(AppInstance &) = nullptr;
539 VkSurfaceKHR surface = VK_NULL_HANDLE;
540 VkBool32 supports_present = 0;
542 bool operator==(const SurfaceExtension &other) {
543 return name == other.name && surface == other.surface && supports_present == other.supports_present;
547 struct VulkanVersion {
557 uint32_t instance_version;
558 VulkanVersion vk_version;
560 ExtensionFunctions ext_funcs;
562 std::vector<LayerExtensionList> global_layers;
564 std::vector<VkExtensionProperties> global_extensions; // Instance Extensions
566 std::vector<std::string> inst_extensions;
568 std::vector<SurfaceExtension> surface_extensions;
570 int width = 256, height = 256;
572 VkSurfaceCapabilitiesKHR surface_capabilities;
574 #ifdef VK_USE_PLATFORM_WIN32_KHR
575 HINSTANCE h_instance; // Windows Instance
576 HWND h_wnd; // window handle
578 #ifdef VK_USE_PLATFORM_XCB_KHR
579 xcb_connection_t *xcb_connection;
580 xcb_screen_t *xcb_screen;
581 xcb_window_t xcb_window;
583 #ifdef VK_USE_PLATFORM_XLIB_KHR
584 Display *xlib_display;
587 #ifdef VK_USE_PLATFORM_MACOS_MVK
590 #ifdef VK_USE_PLATFORM_METAL_EXT
593 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
594 wl_display *wayland_display;
595 wl_surface *wayland_surface;
597 #ifdef VK_USE_PLATFORM_ANDROID_KHR // TODO
598 ANativeWindow *window;
601 VkResult dllErr = dll.Initialize();
602 if (dllErr != VK_SUCCESS) {
603 THROW_ERR("Failed to initialize: Vulkan loader is not installed, not found, or failed to load.");
605 dll.InitializeDispatchPointers();
607 if (!dll.fp_vkEnumerateInstanceVersion) {
608 instance_version = VK_API_VERSION_1_0;
610 const VkResult err = dll.fp_vkEnumerateInstanceVersion(&instance_version);
611 if (err) THROW_VK_ERR("vkEnumerateInstanceVersion", err);
614 // fallback to baked header version if loader returns 0 for the patch version
615 uint32_t patch_version = VK_VERSION_PATCH(instance_version);
616 if (patch_version == 0) patch_version = VK_VERSION_PATCH(VK_HEADER_VERSION);
617 vk_version = {VK_VERSION_MAJOR(instance_version), VK_VERSION_MINOR(instance_version), patch_version};
619 AppGetInstanceExtensions();
621 const VkDebugReportCallbackCreateInfoEXT dbg_info = {VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, nullptr,
622 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
625 const VkApplicationInfo app_info = {
626 VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, app_short_name, 1, nullptr, 0, instance_version};
628 AppCompileInstanceExtensionsToEnable();
630 std::vector<const char *> inst_exts;
631 for (auto &ext : inst_extensions) inst_exts.push_back(ext.c_str());
633 const VkInstanceCreateInfo inst_info = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, &dbg_info, 0, &app_info, 0, nullptr,
634 static_cast<uint32_t>(inst_exts.size()), inst_exts.data()};
636 VkResult err = dll.fp_vkCreateInstance(&inst_info, nullptr, &instance);
637 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
638 std::cerr << "Cannot create Vulkan instance.\n";
639 std::cerr << "This problem is often caused by a faulty installation of the Vulkan driver or attempting to use a GPU "
640 "that does not support Vulkan.\n";
641 THROW_VK_ERR("vkCreateInstance", err);
643 THROW_VK_ERR("vkCreateInstance", err);
645 ext_funcs.LoadInstanceExtensionDispatchPointers(dll.fp_vkGetInstanceProcAddr, instance);
649 if (dll.fp_vkDestroyInstance) dll.fp_vkDestroyInstance(instance, nullptr);
653 AppInstance(const AppInstance &) = delete;
654 const AppInstance &operator=(const AppInstance &) = delete;
656 bool CheckExtensionEnabled(std::string extension_to_check) {
657 for (auto &extension : inst_extensions) {
658 if (extension_to_check == extension) {
665 /* Gets a list of layer and instance extensions */
666 void AppGetInstanceExtensions() {
668 auto global_layer_properties =
669 GetVector<VkLayerProperties>("vkEnumerateInstanceLayerProperties", dll.fp_vkEnumerateInstanceLayerProperties);
670 global_layers.resize(global_layer_properties.size());
672 for (size_t i = 0; i < global_layer_properties.size(); i++) {
673 global_layers[i].layer_properties = global_layer_properties[i];
675 global_layers[i].extension_properties = AppGetGlobalLayerExtensions(global_layer_properties[i].layerName);
678 // Collect global extensions
679 // Gets instance extensions, if no layer was specified in the first paramteter
680 global_extensions = AppGetGlobalLayerExtensions(nullptr);
682 void AppCompileInstanceExtensionsToEnable() {
683 // Get all supported Instance extensions (excl. layer-provided ones)
684 for (auto &ext : global_extensions) {
685 inst_extensions.push_back(ext.extensionName);
689 void AddSurfaceExtension(SurfaceExtension ext) { surface_extensions.push_back(ext); }
691 std::vector<VkExtensionProperties> AppGetGlobalLayerExtensions(char *layer_name) {
692 return GetVector<VkExtensionProperties>("vkEnumerateInstanceExtensionProperties",
693 dll.fp_vkEnumerateInstanceExtensionProperties, layer_name);
696 std::vector<VkPhysicalDevice> FindPhysicalDevices() {
697 return GetVector<VkPhysicalDevice>("vkEnumerateInstanceExtensionProperties", dll.fp_vkEnumeratePhysicalDevices, instance);
701 // --------- Platform Specific Presentation Calls --------- //
703 //---------------------------Win32---------------------------
704 #ifdef VK_USE_PLATFORM_WIN32_KHR
706 // MS-Windows event handling function:
707 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
708 return (CALL_PFN(DefWindowProcA)(hWnd, uMsg, wParam, lParam));
711 static void AppCreateWin32Window(AppInstance &inst) {
712 inst.h_instance = GetModuleHandle(nullptr);
714 WNDCLASSEX win_class;
716 // Initialize the window class structure:
717 win_class.cbSize = sizeof(WNDCLASSEX);
718 win_class.style = CS_HREDRAW | CS_VREDRAW;
719 win_class.lpfnWndProc = WndProc;
720 win_class.cbClsExtra = 0;
721 win_class.cbWndExtra = 0;
722 win_class.hInstance = inst.h_instance;
723 win_class.hIcon = CALL_PFN(LoadIconA)(nullptr, IDI_APPLICATION);
724 win_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
725 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
726 win_class.lpszMenuName = nullptr;
727 win_class.lpszClassName = app_short_name;
728 win_class.hInstance = inst.h_instance;
729 win_class.hIconSm = CALL_PFN(LoadIconA)(nullptr, IDI_WINLOGO);
730 // Register window class:
731 if (!CALL_PFN(RegisterClassExA)(&win_class)) {
732 // It didn't work, so try to give a useful error:
733 THROW_ERR("Failed to register the window class!");
735 // Create window with the registered class:
736 RECT wr = {0, 0, inst.width, inst.height};
737 CALL_PFN(AdjustWindowRect)(&wr, WS_OVERLAPPEDWINDOW, FALSE);
738 inst.h_wnd = CALL_PFN(CreateWindowExA)(0,
739 app_short_name, // class name
740 app_short_name, // app name
741 // WS_VISIBLE | WS_SYSMENU |
742 WS_OVERLAPPEDWINDOW, // window style
743 100, 100, // x/y coords
744 wr.right - wr.left, // width
745 wr.bottom - wr.top, // height
746 nullptr, // handle to parent
747 nullptr, // handle to menu
748 inst.h_instance, // hInstance
749 nullptr); // no extra parameters
751 // It didn't work, so try to give a useful error:
752 THROW_ERR("Failed to create a window!");
756 static VkSurfaceKHR AppCreateWin32Surface(AppInstance &inst) {
757 VkWin32SurfaceCreateInfoKHR createInfo;
758 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
759 createInfo.pNext = nullptr;
760 createInfo.flags = 0;
761 createInfo.hinstance = inst.h_instance;
762 createInfo.hwnd = inst.h_wnd;
764 VkSurfaceKHR surface;
765 VkResult err = inst.dll.fp_vkCreateWin32SurfaceKHR(inst.instance, &createInfo, nullptr, &surface);
766 if (err) THROW_VK_ERR("vkCreateWin32SurfaceKHR", err);
770 static void AppDestroyWin32Window(AppInstance &inst) { CALL_PFN(DestroyWindow)(inst.h_wnd); }
771 #endif // VK_USE_PLATFORM_WIN32_KHR
772 //-----------------------------------------------------------
774 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
775 defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_WAYLAND_KHR) || \
776 defined(VK_USE_PLATFORM_ANDROID_KHR)
777 static void AppDestroySurface(AppInstance &inst, VkSurfaceKHR surface) { // same for all platforms
778 inst.dll.fp_vkDestroySurfaceKHR(inst.instance, surface, nullptr);
782 //----------------------------XCB----------------------------
784 #ifdef VK_USE_PLATFORM_XCB_KHR
785 static void AppCreateXcbWindow(AppInstance &inst) {
786 //--Init Connection--
787 const xcb_setup_t *setup;
788 xcb_screen_iterator_t iter;
791 // API guarantees non-null xcb_connection
792 inst.xcb_connection = xcb_connect(nullptr, &scr);
793 int conn_error = xcb_connection_has_error(inst.xcb_connection);
795 fprintf(stderr, "XCB failed to connect to the X server due to error:%d.\n", conn_error);
797 xcb_disconnect(inst.xcb_connection);
798 inst.xcb_connection = nullptr;
802 setup = xcb_get_setup(inst.xcb_connection);
803 iter = xcb_setup_roots_iterator(setup);
805 xcb_screen_next(&iter);
808 inst.xcb_screen = iter.data;
809 //-------------------
811 inst.xcb_window = xcb_generate_id(inst.xcb_connection);
812 xcb_create_window(inst.xcb_connection, XCB_COPY_FROM_PARENT, inst.xcb_window, inst.xcb_screen->root, 0, 0, inst.width,
813 inst.height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, inst.xcb_screen->root_visual, 0, nullptr);
815 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(inst.xcb_connection, 1, 12, "WM_PROTOCOLS");
816 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(inst.xcb_connection, cookie, 0);
820 static VkSurfaceKHR AppCreateXcbSurface(AppInstance &inst) {
821 if (!inst.xcb_connection) {
822 THROW_ERR("AppCreateXcbSurface failed to establish connection");
825 VkXcbSurfaceCreateInfoKHR xcb_createInfo;
826 xcb_createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
827 xcb_createInfo.pNext = nullptr;
828 xcb_createInfo.flags = 0;
829 xcb_createInfo.connection = inst.xcb_connection;
830 xcb_createInfo.window = inst.xcb_window;
832 VkSurfaceKHR surface;
833 VkResult err = inst.dll.fp_vkCreateXcbSurfaceKHR(inst.instance, &xcb_createInfo, nullptr, &surface);
834 if (err) THROW_VK_ERR("vkCreateXcbSurfaceKHR", err);
838 static void AppDestroyXcbWindow(AppInstance &inst) {
839 if (!inst.xcb_connection) {
840 return; // Nothing to destroy
843 xcb_destroy_window(inst.xcb_connection, inst.xcb_window);
844 xcb_disconnect(inst.xcb_connection);
846 #endif // VK_USE_PLATFORM_XCB_KHR
847 //-----------------------------------------------------------
849 //----------------------------XLib---------------------------
850 #ifdef VK_USE_PLATFORM_XLIB_KHR
851 static void AppCreateXlibWindow(AppInstance &inst) {
852 long visualMask = VisualScreenMask;
855 inst.xlib_display = XOpenDisplay(nullptr);
856 if (inst.xlib_display == nullptr) {
857 THROW_ERR("XLib failed to connect to the X server.\nExiting...");
860 XVisualInfo vInfoTemplate = {};
861 vInfoTemplate.screen = DefaultScreen(inst.xlib_display);
862 XVisualInfo *visualInfo = XGetVisualInfo(inst.xlib_display, visualMask, &vInfoTemplate, &numberOfVisuals);
863 inst.xlib_window = XCreateWindow(inst.xlib_display, RootWindow(inst.xlib_display, vInfoTemplate.screen), 0, 0, inst.width,
864 inst.height, 0, visualInfo->depth, InputOutput, visualInfo->visual, 0, nullptr);
866 XSync(inst.xlib_display, false);
870 static VkSurfaceKHR AppCreateXlibSurface(AppInstance &inst) {
871 VkXlibSurfaceCreateInfoKHR createInfo;
872 createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
873 createInfo.pNext = nullptr;
874 createInfo.flags = 0;
875 createInfo.dpy = inst.xlib_display;
876 createInfo.window = inst.xlib_window;
878 VkSurfaceKHR surface;
879 VkResult err = inst.dll.fp_vkCreateXlibSurfaceKHR(inst.instance, &createInfo, nullptr, &surface);
880 if (err) THROW_VK_ERR("vkCreateXlibSurfaceKHR", err);
884 static void AppDestroyXlibWindow(AppInstance &inst) {
885 XDestroyWindow(inst.xlib_display, inst.xlib_window);
886 XCloseDisplay(inst.xlib_display);
888 #endif // VK_USE_PLATFORM_XLIB_KHR
889 //-----------------------------------------------------------
891 //------------------------MACOS_MVK--------------------------
892 #ifdef VK_USE_PLATFORM_MACOS_MVK
893 static void AppCreateMacOSWindow(AppInstance &inst) {
894 inst.macos_window = CreateMetalView(inst.width, inst.height);
895 if (inst.macos_window == nullptr) {
896 THROW_ERR("Could not create a native Metal view.\nExiting...");
900 static VkSurfaceKHR AppCreateMacOSSurface(AppInstance &inst) {
901 VkMacOSSurfaceCreateInfoMVK createInfo;
902 createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
903 createInfo.pNext = nullptr;
904 createInfo.flags = 0;
905 createInfo.pView = inst.macos_window;
907 VkSurfaceKHR surface;
908 VkResult err = inst.dll.fp_vkCreateMacOSSurfaceMVK(inst.instance, &createInfo, nullptr, &surface);
909 if (err) THROW_VK_ERR("vkCreateMacOSSurfaceMVK", err);
913 static void AppDestroyMacOSWindow(AppInstance &inst) { DestroyMetalView(inst.macos_window); }
914 #endif // VK_USE_PLATFORM_MACOS_MVK
915 //-----------------------------------------------------------
917 //------------------------METAL_EXT--------------------------
918 #ifdef VK_USE_PLATFORM_METAL_EXT
919 static void AppCreateMetalWindow(AppInstance &inst) {
920 inst.metal_window = CreateMetalView(inst.width, inst.height);
921 if (inst.metal_window == nullptr) {
922 THROW_ERR("Could not create a native Metal view.\nExiting...");
926 static VkSurfaceKHR AppCreateMetalSurface(AppInstance &inst) {
927 VkMetalSurfaceCreateInfoEXT createInfo;
928 createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
929 createInfo.pNext = nullptr;
930 createInfo.flags = 0;
931 createInfo.pLayer = static_cast<CAMetalLayer *>(GetCAMetalLayerFromMetalView(inst.metal_window));
933 VkSurfaceKHR surface;
934 VkResult err = inst.dll.fp_vkCreateMetalSurfaceEXT(inst.instance, &createInfo, nullptr, &surface);
935 if (err) THROW_VK_ERR("vkCreateMetalSurfaceEXT", err);
939 static void AppDestroyMetalWindow(AppInstance &inst) { DestroyMetalView(inst.metal_window); }
940 #endif // VK_USE_PLATFORM_METAL_EXT
941 //-----------------------------------------------------------
943 //-------------------------WAYLAND---------------------------
944 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
945 static void wayland_registry_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface,
947 AppInstance &inst = *static_cast<AppInstance *>(data);
948 if (strcmp(interface, "wl_compositor") == 0) {
949 struct wl_compositor *compositor = (struct wl_compositor *)wl_registry_bind(registry, id, &wl_compositor_interface, 1);
950 inst.wayland_surface = wl_compositor_create_surface(compositor);
953 static void wayland_registry_global_remove(void *data, struct wl_registry *registry, uint32_t id) {}
954 static const struct wl_registry_listener wayland_registry_listener = {wayland_registry_global, wayland_registry_global_remove};
956 static void AppCreateWaylandWindow(AppInstance &inst) {
957 inst.wayland_display = wl_display_connect(nullptr);
958 struct wl_registry *registry = wl_display_get_registry(inst.wayland_display);
959 wl_registry_add_listener(wl_display_get_registry(inst.wayland_display), &wayland_registry_listener, static_cast<void *>(&inst));
960 wl_display_roundtrip(inst.wayland_display);
961 wl_registry_destroy(registry);
964 static VkSurfaceKHR AppCreateWaylandSurface(AppInstance &inst) {
965 VkWaylandSurfaceCreateInfoKHR createInfo;
966 createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
967 createInfo.pNext = nullptr;
968 createInfo.flags = 0;
969 createInfo.display = inst.wayland_display;
970 createInfo.surface = inst.wayland_surface;
972 VkSurfaceKHR surface;
973 VkResult err = inst.dll.fp_vkCreateWaylandSurfaceKHR(inst.instance, &createInfo, nullptr, &surface);
974 if (err) THROW_VK_ERR("vkCreateWaylandSurfaceKHR", err);
978 static void AppDestroyWaylandWindow(AppInstance &inst) { wl_display_disconnect(inst.wayland_display); }
979 #endif // VK_USE_PLATFORM_WAYLAND_KHR
980 //-----------------------------------------------------------
982 //-------------------------ANDROID---------------------------
983 #ifdef VK_USE_PLATFORM_ANDROID_KHR
984 static void AppCreateAndroidWindow(AppInstance &inst) {}
985 static VkSurfaceKHR AppCreateAndroidSurface(AppInstance &inst) {
986 VkAndroidSurfaceCreateInfoKHR createInfo;
987 createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
988 createInfo.pNext = NULL;
989 createInfo.flags = 0;
990 createInfo.window = (struct ANativeWindow *)(inst.window);
992 err = inst.dll.fp_vkCreateAndroidSurfaceKHR(inst.inst, &createInfo, NULL, &inst.surface);
993 THROW_VK_ERR("vkCreateAndroidSurfaceKHR", err);
995 static VkSurfaceKHR AppDestroyAndroidSurface(AppInstance &inst) {}
997 //-----------------------------------------------------------
999 // ------------ Setup Windows ------------- //
1001 void SetupWindowExtensions(AppInstance &inst) {
1002 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR)
1003 bool has_display = true;
1004 const char *display_var = getenv("DISPLAY");
1005 if (display_var == nullptr || strlen(display_var) == 0) {
1006 has_display = false;
1007 std::cerr << "'DISPLAY' environment variable not set... skipping surface info\n";
1011 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
1012 wl_display *wayland_display = wl_display_connect(nullptr);
1013 bool has_wayland_display = false;
1014 if (wayland_display != nullptr) {
1015 wl_display_disconnect(wayland_display);
1016 has_wayland_display = true;
1021 #ifdef VK_USE_PLATFORM_WIN32_KHR
1022 SurfaceExtension surface_ext_win32;
1023 if (inst.CheckExtensionEnabled(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) {
1024 surface_ext_win32.name = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
1025 surface_ext_win32.create_window = AppCreateWin32Window;
1026 surface_ext_win32.create_surface = AppCreateWin32Surface;
1027 surface_ext_win32.destroy_window = AppDestroyWin32Window;
1029 inst.AddSurfaceExtension(surface_ext_win32);
1033 #ifdef VK_USE_PLATFORM_XCB_KHR
1034 SurfaceExtension surface_ext_xcb;
1035 if (inst.CheckExtensionEnabled(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) {
1036 surface_ext_xcb.name = VK_KHR_XCB_SURFACE_EXTENSION_NAME;
1037 surface_ext_xcb.create_window = AppCreateXcbWindow;
1038 surface_ext_xcb.create_surface = AppCreateXcbSurface;
1039 surface_ext_xcb.destroy_window = AppDestroyXcbWindow;
1041 inst.AddSurfaceExtension(surface_ext_xcb);
1046 #ifdef VK_USE_PLATFORM_XLIB_KHR
1047 SurfaceExtension surface_ext_xlib;
1048 if (inst.CheckExtensionEnabled(VK_KHR_XLIB_SURFACE_EXTENSION_NAME)) {
1049 surface_ext_xlib.name = VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
1050 surface_ext_xlib.create_window = AppCreateXlibWindow;
1051 surface_ext_xlib.create_surface = AppCreateXlibSurface;
1052 surface_ext_xlib.destroy_window = AppDestroyXlibWindow;
1054 inst.AddSurfaceExtension(surface_ext_xlib);
1059 #ifdef VK_USE_PLATFORM_MACOS_MVK
1060 SurfaceExtension surface_ext_macos;
1061 if (inst.CheckExtensionEnabled(VK_MVK_MACOS_SURFACE_EXTENSION_NAME)) {
1062 surface_ext_macos.name = VK_MVK_MACOS_SURFACE_EXTENSION_NAME;
1063 surface_ext_macos.create_window = AppCreateMacOSWindow;
1064 surface_ext_macos.create_surface = AppCreateMacOSSurface;
1065 surface_ext_macos.destroy_window = AppDestroyMacOSWindow;
1067 inst.AddSurfaceExtension(surface_ext_macos);
1071 #ifdef VK_USE_PLATFORM_METAL_EXT
1072 SurfaceExtension surface_ext_metal;
1073 if (inst.CheckExtensionEnabled(VK_EXT_METAL_SURFACE_EXTENSION_NAME)) {
1074 surface_ext_metal.name = VK_EXT_METAL_SURFACE_EXTENSION_NAME;
1075 surface_ext_metal.create_window = AppCreateMetalWindow;
1076 surface_ext_metal.create_surface = AppCreateMetalSurface;
1077 surface_ext_metal.destroy_window = AppDestroyMetalWindow;
1079 inst.AddSurfaceExtension(surface_ext_metal);
1083 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
1084 SurfaceExtension surface_ext_wayland;
1085 if (inst.CheckExtensionEnabled(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME)) {
1086 surface_ext_wayland.name = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
1087 surface_ext_wayland.create_window = AppCreateWaylandWindow;
1088 surface_ext_wayland.create_surface = AppCreateWaylandSurface;
1089 surface_ext_wayland.destroy_window = AppDestroyWaylandWindow;
1090 if (has_wayland_display) {
1091 inst.AddSurfaceExtension(surface_ext_wayland);
1096 #ifdef VK_USE_PLATFORM_ANDROID_KHR
1097 SurfaceExtension surface_ext_android;
1098 if (inst.CheckExtensionEnabled(VK_ANDROID_SURFACE_EXTENSION_NAME)) {
1099 surface_ext_android.name = VK_ANDROID_SURFACE_EXTENSION_NAME;
1100 surface_ext_android.create_window = AppCreateAndroidWindow;
1101 surface_ext_android.create_surface = AppCreateAndroidSurface;
1102 surface_ext_android.destroy_window = AppDestroyAndroidWindow;
1104 inst.AddSurfaceExtension(surface_ext_android);
1109 // ---------- Surfaces -------------- //
1114 VkPhysicalDevice phys_device;
1115 SurfaceExtension surface_extension;
1117 std::vector<VkPresentModeKHR> surf_present_modes;
1119 std::vector<VkSurfaceFormatKHR> surf_formats;
1120 std::vector<VkSurfaceFormat2KHR> surf_formats2;
1122 VkSurfaceCapabilitiesKHR surface_capabilities{};
1123 VkSurfaceCapabilities2KHR surface_capabilities2_khr{};
1124 VkSurfaceCapabilities2EXT surface_capabilities2_ext{};
1126 AppSurface(AppInstance &inst, VkPhysicalDevice phys_device, SurfaceExtension surface_extension,
1127 std::vector<pNextChainBuildingBlockInfo> &sur_extension_pNextChain)
1129 phys_device(phys_device),
1130 surface_extension(surface_extension),
1131 surf_present_modes(GetVector<VkPresentModeKHR>("vkGetPhysicalDeviceSurfacePresentModesKHR",
1132 inst.ext_funcs.vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device,
1133 surface_extension.surface)) {
1134 const VkPhysicalDeviceSurfaceInfo2KHR surface_info2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr,
1135 surface_extension.surface};
1137 if (inst.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) {
1138 VkSurfaceFormat2KHR init;
1139 init.sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
1140 init.pNext = nullptr;
1141 surf_formats2 = GetVectorInit<VkSurfaceFormat2KHR>("vkGetPhysicalDeviceSurfaceFormats2KHR",
1142 inst.ext_funcs.vkGetPhysicalDeviceSurfaceFormats2KHR, init,
1143 phys_device, &surface_info2);
1145 surf_formats = GetVector<VkSurfaceFormatKHR>("vkGetPhysicalDeviceSurfaceFormatsKHR",
1146 inst.ext_funcs.vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device,
1147 surface_extension.surface);
1150 if (inst.CheckExtensionEnabled(VK_KHR_SURFACE_EXTENSION_NAME)) {
1151 VkResult err = inst.ext_funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_device, surface_extension.surface,
1152 &surface_capabilities);
1153 if (err) THROW_VK_ERR("vkGetPhysicalDeviceSurfaceCapabilitiesKHR", err);
1156 if (inst.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) {
1157 surface_capabilities2_khr.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
1158 buildpNextChain((VkStructureHeader *)&surface_capabilities2_khr, sur_extension_pNextChain);
1160 VkPhysicalDeviceSurfaceInfo2KHR surface_info;
1161 surface_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
1162 surface_info.pNext = nullptr;
1163 surface_info.surface = surface_extension.surface;
1166 inst.ext_funcs.vkGetPhysicalDeviceSurfaceCapabilities2KHR(phys_device, &surface_info, &surface_capabilities2_khr);
1167 if (err) THROW_VK_ERR("vkGetPhysicalDeviceSurfaceCapabilities2KHR", err);
1170 if (inst.CheckExtensionEnabled(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)) {
1171 surface_capabilities2_ext.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT;
1172 surface_capabilities2_ext.pNext = nullptr;
1173 VkResult err = inst.ext_funcs.vkGetPhysicalDeviceSurfaceCapabilities2EXT(phys_device, surface_extension.surface,
1174 &surface_capabilities2_ext);
1175 if (err) THROW_VK_ERR("vkGetPhysicalDeviceSurfaceCapabilities2EXT", err);
1180 if (inst.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) {
1181 freepNextChain(static_cast<VkStructureHeader *>(surface_capabilities2_khr.pNext));
1185 AppSurface(const AppSurface &) = delete;
1186 const AppSurface &operator=(const AppSurface &) = delete;
1189 // -------------------- Device Groups ------------------------//
1191 std::vector<VkPhysicalDeviceGroupProperties> GetGroups(AppInstance &inst) {
1192 if (inst.CheckExtensionEnabled(VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME)) {
1193 return GetVector<VkPhysicalDeviceGroupProperties>("vkEnumeratePhysicalDeviceGroupsKHR",
1194 inst.ext_funcs.vkEnumeratePhysicalDeviceGroupsKHR, inst.instance);
1199 std::vector<VkPhysicalDeviceProperties> GetGroupProps(AppInstance &inst, VkPhysicalDeviceGroupProperties group) {
1200 std::vector<VkPhysicalDeviceProperties> props(group.physicalDeviceCount);
1202 for (uint32_t i = 0; i < group.physicalDeviceCount; ++i) {
1203 inst.dll.fp_vkGetPhysicalDeviceProperties(group.physicalDevices[i], &props[i]);
1209 // The bool of the pair returns true if the extension VK_KHR_device_group is present
1210 std::pair<bool, VkDeviceGroupPresentCapabilitiesKHR> GetGroupCapabilities(AppInstance &inst,
1211 VkPhysicalDeviceGroupProperties group) {
1212 // Build create info for logical device made from all physical devices in this group.
1213 std::vector<std::string> extensions_list = {VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_DEVICE_GROUP_EXTENSION_NAME};
1214 VkDeviceGroupDeviceCreateInfoKHR dg_ci = {VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, nullptr,
1215 group.physicalDeviceCount, group.physicalDevices};
1217 float queue_priority = 1.0f;
1219 auto ext_list = get_c_str_array(extensions_list);
1221 VkDeviceQueueCreateInfo q_ci = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, nullptr, 0, 0, 1, &queue_priority};
1222 VkDeviceCreateInfo device_ci = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, &dg_ci, 0, 1, &q_ci, 0, nullptr,
1223 static_cast<uint32_t>(ext_list.size()), ext_list.data()};
1225 VkDevice logical_device = VK_NULL_HANDLE;
1227 VkResult err = inst.dll.fp_vkCreateDevice(group.physicalDevices[0], &device_ci, nullptr, &logical_device);
1228 if (err != VK_SUCCESS && err != VK_ERROR_EXTENSION_NOT_PRESENT) THROW_VK_ERR("vkCreateDevice", err);
1230 if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
1231 VkDeviceGroupPresentCapabilitiesKHR group_capabilities = {VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR, nullptr};
1232 inst.dll.fp_vkDestroyDevice(logical_device, nullptr);
1233 return std::pair<bool, VkDeviceGroupPresentCapabilitiesKHR>(false, group_capabilities);
1236 VkDeviceGroupPresentCapabilitiesKHR group_capabilities = {VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR, nullptr};
1238 // If the KHR_device_group extension is present, write the capabilities of the logical device into a struct for later
1240 err = inst.ext_funcs.vkGetDeviceGroupPresentCapabilitiesKHR(logical_device, &group_capabilities);
1241 if (err) THROW_VK_ERR("vkGetDeviceGroupPresentCapabilitiesKHR", err);
1243 inst.dll.fp_vkDestroyDevice(logical_device, nullptr);
1245 return std::pair<bool, VkDeviceGroupPresentCapabilitiesKHR>(true, group_capabilities);
1248 // -------------------- Device Setup ------------------- //
1250 const VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM;
1252 struct ImageTypeSupport {
1253 enum class Type { regular, sparse, transient } type = Type::regular;
1254 bool supported = false;
1255 uint32_t memoryTypeBits = 0;
1257 bool Compatible(uint32_t memtype_bit) { return supported && (memoryTypeBits & memtype_bit); }
1260 struct ImageTypeFormatInfo {
1262 std::vector<ImageTypeSupport> type_support;
1265 struct ImageTypeInfos {
1266 VkImageTiling tiling;
1267 std::vector<ImageTypeFormatInfo> formats;
1270 VkImageCreateInfo GetImageCreateInfo(VkFormat format, VkImageTiling tiling, VkImageCreateFlags flags, VkImageUsageFlags usages) {
1271 return {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1279 VK_SAMPLE_COUNT_1_BIT,
1282 VK_SHARING_MODE_EXCLUSIVE,
1285 VK_IMAGE_LAYOUT_UNDEFINED};
1288 ImageTypeSupport FillImageTypeSupport(AppInstance &inst, VkPhysicalDevice phys_device, VkDevice device,
1289 ImageTypeSupport::Type img_type, VkImageCreateInfo image_ci) {
1290 VkImageFormatProperties img_props;
1291 VkResult res = inst.dll.fp_vkGetPhysicalDeviceImageFormatProperties(
1292 phys_device, image_ci.format, image_ci.imageType, image_ci.tiling, image_ci.usage, image_ci.flags, &img_props);
1294 if (res == VK_SUCCESS) {
1295 ImageTypeSupport img_type_support{};
1296 img_type_support.type = img_type;
1297 img_type_support.supported = true;
1300 res = inst.dll.fp_vkCreateImage(device, &image_ci, nullptr, &dummy_img);
1301 if (res) THROW_VK_ERR("vkCreateImage", res);
1303 VkMemoryRequirements mem_req;
1304 inst.dll.fp_vkGetImageMemoryRequirements(device, dummy_img, &mem_req);
1305 img_type_support.memoryTypeBits = mem_req.memoryTypeBits;
1307 inst.dll.fp_vkDestroyImage(device, dummy_img, nullptr);
1308 return img_type_support;
1309 } else if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
1310 return {}; // default initialization has supported being false
1312 THROW_VK_ERR("vkGetPhysicalDeviceImageFormatProperties", res);
1316 struct pNextChainInfos {
1317 std::vector<pNextChainBuildingBlockInfo> phys_device_props2;
1318 std::vector<pNextChainBuildingBlockInfo> phys_device_mem_props2;
1319 std::vector<pNextChainBuildingBlockInfo> phys_device_features2;
1320 std::vector<pNextChainBuildingBlockInfo> surface_capabilities2;
1321 std::vector<pNextChainBuildingBlockInfo> format_properties2;
1324 struct FormatRange {
1325 // the Vulkan standard version that supports this format range, or 0 if non-standard
1326 uint32_t minimum_instance_version;
1328 // The name of the extension that supports this format range, or NULL if the range
1329 // is only part of the standard
1330 const char *extension_name;
1332 // The first and last supported formats within this range.
1333 VkFormat first_format;
1334 VkFormat last_format;
1340 VkPhysicalDevice phys_device;
1341 VulkanVersion api_version;
1343 VkPhysicalDeviceProperties props;
1344 VkPhysicalDeviceProperties2KHR props2;
1346 uint32_t queue_count;
1347 std::vector<VkQueueFamilyProperties> queue_props;
1348 std::vector<VkQueueFamilyProperties2KHR> queue_props2;
1350 VkPhysicalDeviceMemoryProperties memory_props;
1351 VkPhysicalDeviceMemoryProperties2KHR memory_props2;
1353 std::vector<ImageTypeInfos> memory_image_support_types;
1355 VkPhysicalDeviceFeatures features;
1356 VkPhysicalDeviceFeatures2KHR features2;
1357 VkPhysicalDevice limits;
1359 std::vector<VkExtensionProperties> device_extensions;
1362 VkPhysicalDeviceFeatures enabled_features;
1364 std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heapBudget;
1365 std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heapUsage;
1367 std::vector<FormatRange> supported_format_ranges;
1369 AppGpu(AppInstance &inst, uint32_t id, VkPhysicalDevice phys_device, pNextChainInfos chainInfos)
1370 : inst(inst), id(id), phys_device(phys_device) {
1371 inst.dll.fp_vkGetPhysicalDeviceProperties(phys_device, &props);
1373 // needs to find the minimum of the instance and device version, and use that to print the device info
1374 uint32_t gpu_version = props.apiVersion < inst.instance_version ? props.apiVersion : inst.instance_version;
1375 api_version = {VK_VERSION_MAJOR(gpu_version), VK_VERSION_MINOR(gpu_version), VK_VERSION_PATCH(gpu_version)};
1377 if (inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
1378 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
1379 buildpNextChain((VkStructureHeader *)&props2, chainInfos.phys_device_props2);
1381 inst.ext_funcs.vkGetPhysicalDeviceProperties2KHR(phys_device, &props2);
1383 /* get queue count */
1384 inst.dll.fp_vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &queue_count, nullptr);
1386 queue_props.resize(queue_count);
1388 inst.dll.fp_vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &queue_count, queue_props.data());
1390 if (inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
1391 queue_props2.resize(queue_count);
1393 for (size_t i = 0; i < queue_count; ++i) {
1394 queue_props2[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
1395 queue_props2[i].pNext = nullptr;
1398 inst.ext_funcs.vkGetPhysicalDeviceQueueFamilyProperties2KHR(phys_device, &queue_count, queue_props2.data());
1401 inst.dll.fp_vkGetPhysicalDeviceMemoryProperties(phys_device, &memory_props);
1403 inst.dll.fp_vkGetPhysicalDeviceFeatures(phys_device, &features);
1405 if (inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
1406 memory_props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR;
1407 buildpNextChain((VkStructureHeader *)&memory_props2, chainInfos.phys_device_mem_props2);
1409 inst.ext_funcs.vkGetPhysicalDeviceMemoryProperties2KHR(phys_device, &memory_props2);
1411 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
1412 buildpNextChain((VkStructureHeader *)&features2, chainInfos.phys_device_features2);
1414 inst.ext_funcs.vkGetPhysicalDeviceFeatures2KHR(phys_device, &features2);
1417 device_extensions = AppGetPhysicalDeviceLayerExtensions(nullptr);
1419 const float queue_priority = 1.0f;
1420 const VkDeviceQueueCreateInfo q_ci = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
1423 0, // just pick the first one and hope for the best
1426 enabled_features = VkPhysicalDeviceFeatures{0};
1427 const VkDeviceCreateInfo device_ci = {
1428 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, nullptr, 0, 1, &q_ci, 0, nullptr, 0, nullptr, &enabled_features};
1430 VkResult err = inst.dll.fp_vkCreateDevice(phys_device, &device_ci, nullptr, &dev);
1431 if (err) THROW_VK_ERR("vkCreateDevice", err);
1433 const std::vector<VkImageTiling> tilings = {VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_LINEAR};
1434 const std::vector<VkFormat> formats = {
1435 color_format, VK_FORMAT_D16_UNORM, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D32_SFLOAT,
1436 VK_FORMAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT};
1438 for (VkImageTiling tiling : tilings) {
1439 ImageTypeInfos image_type_infos;
1440 image_type_infos.tiling = tiling;
1442 for (VkFormat format : formats) {
1443 ImageTypeFormatInfo image_type_format_info;
1444 image_type_format_info.format = format;
1446 VkFormatProperties fmt_props;
1447 inst.dll.fp_vkGetPhysicalDeviceFormatProperties(phys_device, format, &fmt_props);
1448 if ((tiling == VK_IMAGE_TILING_OPTIMAL && fmt_props.optimalTilingFeatures == 0) ||
1449 (tiling == VK_IMAGE_TILING_LINEAR && fmt_props.linearTilingFeatures == 0)) {
1453 VkImageCreateInfo image_ci_regular = GetImageCreateInfo(format, tiling, 0, 0);
1454 VkImageCreateInfo image_ci_transient =
1455 GetImageCreateInfo(format, tiling, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, 0);
1456 VkImageCreateInfo image_ci_sparse = GetImageCreateInfo(format, tiling, 0, VK_IMAGE_CREATE_SPARSE_BINDING_BIT);
1458 if (tiling == VK_IMAGE_TILING_LINEAR) {
1459 if (format == color_format) {
1460 image_ci_regular.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1461 image_ci_transient.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1463 // linear tiling is only applicable to color image types
1467 if (format == color_format) {
1468 image_ci_regular.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1469 image_ci_transient.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1472 image_ci_regular.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1473 image_ci_transient.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1477 auto image_ts_regular =
1478 FillImageTypeSupport(inst, phys_device, dev, ImageTypeSupport::Type::regular, image_ci_regular);
1479 if (image_ts_regular.supported) {
1480 image_type_format_info.type_support.push_back(image_ts_regular);
1482 auto image_ts_transient =
1483 FillImageTypeSupport(inst, phys_device, dev, ImageTypeSupport::Type::transient, image_ci_transient);
1484 if (image_ts_transient.supported) {
1485 image_type_format_info.type_support.push_back(image_ts_transient);
1488 if (enabled_features.sparseBinding) {
1489 auto image_ts_sparse =
1490 FillImageTypeSupport(inst, phys_device, dev, ImageTypeSupport::Type::sparse, image_ci_sparse);
1491 if (image_ts_sparse.supported) {
1492 image_type_format_info.type_support.push_back(image_ts_sparse);
1495 image_type_infos.formats.push_back(image_type_format_info);
1497 memory_image_support_types.push_back(image_type_infos);
1502 struct VkStructureHeader *structure = NULL;
1503 if (inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
1504 structure = (struct VkStructureHeader *)memory_props2.pNext;
1507 if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT &&
1508 CheckPhysicalDeviceExtensionIncluded(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) {
1509 VkPhysicalDeviceMemoryBudgetPropertiesEXT *mem_budget_props =
1510 (VkPhysicalDeviceMemoryBudgetPropertiesEXT *)structure;
1511 for (uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; i++) {
1512 heapBudget[i] = mem_budget_props->heapBudget[i];
1513 heapUsage[i] = mem_budget_props->heapUsage[i];
1517 structure = (struct VkStructureHeader *)structure->pNext;
1520 // TODO buffer - memory type compatibility
1522 supported_format_ranges = {
1524 // Standard formats in Vulkan 1.0
1525 VK_MAKE_VERSION(1, 0, 0), NULL,
1526 static_cast<VkFormat>(0), // first core VkFormat
1527 static_cast<VkFormat>(184) // last core VkFormat
1530 // YCBCR extension, standard in Vulkan 1.1
1531 VK_MAKE_VERSION(1, 1, 0),
1532 VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
1533 VK_FORMAT_G8B8G8R8_422_UNORM,
1534 VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
1537 // PVRTC extension, not standardized
1539 VK_IMG_FORMAT_PVRTC_EXTENSION_NAME,
1540 VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,
1541 VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,
1544 // ASTC extension, not standardized
1546 VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME,
1547 VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT,
1548 VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT,
1553 inst.dll.fp_vkDestroyDevice(dev, nullptr);
1555 if (inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
1556 freepNextChain(static_cast<VkStructureHeader *>(features2.pNext));
1557 freepNextChain(static_cast<VkStructureHeader *>(props2.pNext));
1558 freepNextChain(static_cast<VkStructureHeader *>(memory_props2.pNext));
1562 AppGpu(const AppGpu &) = delete;
1563 const AppGpu &operator=(const AppGpu &) = delete;
1565 bool CheckPhysicalDeviceExtensionIncluded(std::string extension_to_check) {
1566 for (auto &extension : device_extensions) {
1567 if (extension_to_check == std::string(extension.extensionName)) {
1574 std::vector<VkExtensionProperties> AppGetPhysicalDeviceLayerExtensions(char *layer_name) {
1575 return GetVector<VkExtensionProperties>("vkEnumerateDeviceExtensionProperties",
1576 inst.dll.fp_vkEnumerateDeviceExtensionProperties, phys_device, layer_name);
1579 // Helper function to determine whether a format range is currently supported.
1580 bool FormatRangeSupported(FormatRange &format_range) {
1581 // True if standard and supported by both this instance and this GPU
1582 if (format_range.minimum_instance_version > 0 && inst.instance_version >= format_range.minimum_instance_version &&
1583 props.apiVersion >= format_range.minimum_instance_version) {
1587 // True if this extension is present
1588 if (format_range.extension_name != nullptr) {
1589 return inst.CheckExtensionEnabled(format_range.extension_name);
1592 // Otherwise, not supported.
1596 VkPhysicalDeviceProperties GetDeviceProperties() {
1597 if (inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
1598 return props2.properties;
1604 struct AppQueueFamilyProperties {
1605 VkQueueFamilyProperties props;
1606 uint32_t queue_index;
1607 bool is_present_platform_agnostic = true;
1608 VkBool32 platforms_support_present = VK_FALSE;
1610 AppQueueFamilyProperties(AppGpu &gpu, uint32_t queue_index) : queue_index(queue_index) {
1611 if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
1612 props = gpu.queue_props2[queue_index].queueFamilyProperties;
1614 props = gpu.queue_props[queue_index];
1617 for (auto &surface_ext : gpu.inst.surface_extensions) {
1618 VkResult err = gpu.inst.ext_funcs.vkGetPhysicalDeviceSurfaceSupportKHR(
1619 gpu.phys_device, queue_index, surface_ext.surface, &surface_ext.supports_present);
1620 if (err) THROW_VK_ERR("vkGetPhysicalDeviceSurfaceSupportKHR", err);
1622 const bool first = (surface_ext == gpu.inst.surface_extensions.at(0));
1623 if (!first && platforms_support_present != surface_ext.supports_present) {
1624 is_present_platform_agnostic = false;
1626 platforms_support_present = surface_ext.supports_present;
1631 std::vector<VkPhysicalDeviceToolPropertiesEXT> GetToolingInfo(AppGpu &gpu) {
1632 if (gpu.inst.ext_funcs.vkGetPhysicalDeviceToolPropertiesEXT == nullptr) return {};
1633 return GetVector<VkPhysicalDeviceToolPropertiesEXT>("vkGetPhysicalDeviceToolPropertiesEXT",
1634 gpu.inst.ext_funcs.vkGetPhysicalDeviceToolPropertiesEXT, gpu.phys_device);
1637 // --------- Format Properties ----------//
1644 bool operator==(const PropFlags &other) const {
1645 return (linear == other.linear && optimal == other.optimal && buffer == other.buffer);
1651 struct hash<PropFlags> {
1652 std::size_t operator()(const PropFlags &k) const {
1653 return ((std::hash<uint32_t>()(k.linear) ^ (std::hash<uint32_t>()(k.optimal) << 1)) >> 1) ^
1654 (std::hash<uint32_t>()(k.buffer) << 1);
1659 // Used to sort the formats into buckets by their properties.
1660 std::unordered_map<PropFlags, std::vector<VkFormat>> FormatPropMap(AppGpu &gpu) {
1661 std::unordered_map<PropFlags, std::vector<VkFormat>> map;
1662 for (auto fmtRange : gpu.supported_format_ranges) {
1663 for (int32_t fmt = fmtRange.first_format; fmt <= fmtRange.last_format; ++fmt) {
1664 VkFormatProperties props;
1665 gpu.inst.dll.fp_vkGetPhysicalDeviceFormatProperties(gpu.phys_device, static_cast<VkFormat>(fmt), &props);
1667 PropFlags pf = {props.linearTilingFeatures, props.optimalTilingFeatures, props.bufferFeatures};
1669 map[pf].push_back(static_cast<VkFormat>(fmt));
1675 VkFormatProperties2 GetFormatProperties2(AppGpu &gpu, VkFormat format, pNextChainInfos &chainInfos) {
1676 VkFormatProperties2 props;
1677 props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
1678 buildpNextChain((VkStructureHeader *)&props, chainInfos.format_properties2);
1679 gpu.inst.ext_funcs.vkGetPhysicalDeviceFormatProperties2KHR(gpu.phys_device, format, &props);