wintoys

wintoys.git
git clone git://git.lenczewski.org/wintoys.git
Log | Files | Refs | README

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 }