win32_vkdemo.c (8346B)
1 #include "vkdemo.h" 2 3 #include "vkdemo.c" 4 5 #define WIN32_LEAN_AND_MEAN 1 6 #include <windows.h> 7 8 #include <vulkan/vulkan_win32.h> 9 10 static void 11 win32_process_messages(void); 12 13 LRESULT CALLBACK 14 win32_window_proc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam); 15 16 static VKAPI_ATTR VkBool32 VKAPI_CALL 17 vk_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, 18 VkDebugUtilsMessageTypeFlagsEXT type, 19 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, 20 void *user_data); 21 22 static bool win32_running; 23 static HWND win32_window; 24 25 int WINAPI 26 WinMain(HINSTANCE instance, HINSTANCE prev_instance, PSTR cmdline, int cmdshown) 27 { 28 (void) instance; 29 (void) prev_instance; 30 (void) cmdline; 31 (void) cmdshown; 32 33 const char classname[] = "vkdemo_wndcls"; 34 35 // https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa 36 WNDCLASSEXA cls = { 37 .cbSize = sizeof(WNDCLASSEXA), 38 .style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW, 39 .lpfnWndProc = win32_window_proc, 40 .hInstance = instance, 41 .lpszClassName = classname, 42 }; 43 44 // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerclassexa 45 RegisterClassExA(&cls); 46 47 // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexa 48 win32_window = CreateWindowExA( 49 0, 50 classname, 51 "vkdemo", 52 WS_OVERLAPPEDWINDOW, 53 CW_USEDEFAULT, 54 CW_USEDEFAULT, 55 CW_USEDEFAULT, 56 CW_USEDEFAULT, 57 NULL, 58 NULL, 59 instance, 60 NULL); 61 62 if (!win32_window) { 63 fprintf(stderr, "Failed to create Win32 window!\n"); 64 return 1; 65 } 66 67 const uint64_t vkdemo_permanent_memory_cap = 128 * MiB; 68 const uint64_t vkdemo_temporary_memory_cap = 128 * MiB; 69 70 uint64_t alloc_size = vkdemo_permanent_memory_cap + vkdemo_temporary_memory_cap; 71 void *vkdemo_memory_alloc = VirtualAlloc(0, alloc_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 72 if (!vkdemo_memory_alloc) { 73 fprintf(stderr, "Failed to allocate memory for vkdemo!\n"); 74 return 1; 75 } 76 77 struct vkdemo_memory vkdemo_memory = { 78 .permanent = { 79 .ptr = vkdemo_memory_alloc, 80 .cap = vkdemo_permanent_memory_cap, 81 }, 82 83 .temporary = { 84 .ptr = (uint8_t *) vkdemo_memory_alloc + vkdemo_permanent_memory_cap, 85 .cap = vkdemo_temporary_memory_cap, 86 }, 87 }; 88 89 { 90 // NOTE: debug code to display available extensions and layers 91 uint32_t extension_count; 92 vkEnumerateInstanceExtensionProperties(NULL, &extension_count, NULL); 93 94 fprintf(stderr, "Extension count: %" PRIu32 "\n", extension_count); 95 96 VkExtensionProperties *extensions = _alloca(extension_count * sizeof *extensions); 97 vkEnumerateInstanceExtensionProperties(NULL, &extension_count, extensions); 98 99 for (uint32_t i = 0; i < extension_count; i++) 100 fprintf(stderr, "\t%s\n", extensions[i].extensionName); 101 102 uint32_t layer_count; 103 vkEnumerateInstanceLayerProperties(&layer_count, NULL); 104 105 fprintf(stderr, "Layer count: %" PRIu32 "\n", layer_count); 106 107 VkLayerProperties *layers = _alloca(layer_count * sizeof *layers); 108 vkEnumerateInstanceLayerProperties(&layer_count, layers); 109 110 for (uint32_t i = 0; i < layer_count; i++) 111 fprintf(stderr, "\t%s\n", layers[i].layerName); 112 } 113 114 VkApplicationInfo app_info = { 115 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 116 .pApplicationName = "vkdemo", 117 .applicationVersion = VK_MAKE_VERSION(1, 0, 0), 118 .pEngineName = "No Engine", 119 .engineVersion = VK_MAKE_VERSION(1, 0, 0), 120 .apiVersion = VK_API_VERSION_1_0, 121 }; 122 123 const char *instance_extensions[] = { 124 VK_KHR_SURFACE_EXTENSION_NAME, 125 VK_KHR_WIN32_SURFACE_EXTENSION_NAME, 126 VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, 127 VK_EXT_DEBUG_UTILS_EXTENSION_NAME, 128 }; 129 130 const char *instance_layers[] = { 131 "VK_LAYER_KHRONOS_validation", 132 }; 133 134 uint32_t debug_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT 135 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT 136 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT 137 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; 138 139 uint32_t debug_type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT 140 | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT 141 | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; 142 143 VkDebugUtilsMessengerCreateInfoEXT debug_info = { 144 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 145 .messageSeverity = debug_severity, 146 .messageType = debug_type, 147 .pfnUserCallback = vk_debug_callback, 148 .pUserData = NULL, 149 }; 150 151 VkInstanceCreateInfo instance_info = { 152 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 153 .pApplicationInfo = &app_info, 154 .enabledExtensionCount = ARRLEN(instance_extensions), 155 .ppEnabledExtensionNames = instance_extensions, 156 .enabledLayerCount = ARRLEN(instance_layers), 157 .ppEnabledLayerNames = instance_layers, 158 .pNext = &debug_info, 159 }; 160 161 VkInstance vk_instance; 162 if (vkCreateInstance(&instance_info, NULL, &vk_instance) != VK_SUCCESS) { 163 fprintf(stderr, "Failed to create Vulkan instance!\n"); 164 return 1; 165 } 166 167 PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_utils_messenger_ext = 168 (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(vk_instance, "vkCreateDebugUtilsMessengerEXT"); 169 if (!vk_create_debug_utils_messenger_ext) { 170 fprintf(stderr, "Failed to get proc address of vkCreateDebugUtilsMessengerEXT!\n"); 171 return 1; 172 } 173 174 VkDebugUtilsMessengerEXT vk_debug_messenger; 175 if (vk_create_debug_utils_messenger_ext(vk_instance, &debug_info, NULL, &vk_debug_messenger) != VK_SUCCESS) { 176 fprintf(stderr, "Failed to create Vulkan debug messenger!\n"); 177 return 1; 178 } 179 180 VkWin32SurfaceCreateInfoKHR win32_surface_info = { 181 .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 182 .hwnd = win32_window, 183 .hinstance = instance, 184 }; 185 186 VkSurfaceKHR vk_surface; 187 if (vkCreateWin32SurfaceKHR(vk_instance, &win32_surface_info, NULL, &vk_surface) != VK_SUCCESS) { 188 fprintf(stderr, "Failed to create Vulkan win32 surface!\n"); 189 return 1; 190 } 191 192 RECT rect; 193 GetClientRect(win32_window, &rect); 194 if (!vkdemo_init(&vkdemo_memory, vk_instance, vk_surface, rect.right - rect.left, rect.bottom - rect.top)) { 195 fprintf(stderr, "Failed to initialise vkdemo!\n"); 196 return 1; 197 } 198 199 ShowWindow(win32_window, 1); 200 201 LARGE_INTEGER perf_frequency, start_perf_count, end_perf_count; 202 QueryPerformanceFrequency(&perf_frequency); 203 204 win32_running = true; 205 while (win32_running) { 206 QueryPerformanceCounter(&start_perf_count); 207 uint64_t start_cycles = __rdtsc(); 208 209 win32_process_messages(); 210 211 vkdemo_update(&vkdemo_memory); 212 213 GetClientRect(win32_window, &rect); 214 vkdemo_render(&vkdemo_memory, rect.right - rect.left, rect.bottom - rect.top); 215 216 uint64_t end_cycles = __rdtsc(); 217 QueryPerformanceCounter(&end_perf_count); 218 219 const uint64_t micros = 1000 * 1000; 220 uint64_t elapsed_micros = (end_perf_count.QuadPart - start_perf_count.QuadPart) * micros / perf_frequency.QuadPart; 221 uint64_t elapsed_cycles = end_cycles - start_cycles; 222 223 char buf[256]; 224 snprintf(buf, sizeof buf, "Frame Timings: %" PRIu64 "us, %" PRIu64 " Cy\n", elapsed_micros, elapsed_cycles); 225 OutputDebugString(buf); 226 } 227 228 vkdemo_free(&vkdemo_memory); 229 230 vkDestroySurfaceKHR(vk_instance, vk_surface, NULL); 231 232 PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_utils_messenger_ext = 233 (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(vk_instance, "vkDestroyDebugUtilsMessengerEXT"); 234 if (!vk_destroy_debug_utils_messenger_ext) { 235 fprintf(stderr, "Failed to get proc address of vkDestroyDebugUtilsMessengerEXT!\n"); 236 return 1; 237 } 238 239 vk_destroy_debug_utils_messenger_ext(vk_instance, vk_debug_messenger, NULL); 240 241 vkDestroyInstance(vk_instance, NULL); 242 243 return 0; 244 } 245 246 static void 247 win32_process_messages(void) 248 { 249 MSG msg; 250 while (PeekMessageA(&msg, win32_window, 0, 0, PM_REMOVE)) { 251 switch (msg.message) { 252 default: 253 break; 254 } 255 256 TranslateMessage(&msg); 257 DispatchMessageA(&msg); 258 } 259 } 260 261 LRESULT CALLBACK 262 win32_window_proc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) 263 { 264 switch (msg) { 265 case WM_QUIT: 266 case WM_DESTROY: { 267 win32_running = false; 268 } break; 269 270 default: 271 return DefWindowProcA(window, msg, wparam, lparam); 272 } 273 274 return 0; 275 } 276 277 static VKAPI_ATTR VkBool32 VKAPI_CALL 278 vk_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, 279 VkDebugUtilsMessageTypeFlagsEXT type, 280 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, 281 void *user_data) 282 { 283 (void) severity; 284 (void) type; 285 (void) user_data; 286 287 fprintf(stderr, "validation layer: %s\n", callback_data->pMessage); 288 289 return VK_FALSE; 290 }