vulkan_test_simple

diff src/main.c @ 0:8de4fe926882

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 28 Jun 2018 13:57:28 +0300
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/main.c	Thu Jun 28 13:57:28 2018 +0300
     1.3 @@ -0,0 +1,748 @@
     1.4 +#include <stdio.h>
     1.5 +#include <stdlib.h>
     1.6 +#include <string.h>
     1.7 +#include <stdint.h>
     1.8 +#include <errno.h>
     1.9 +#include <alloca.h>
    1.10 +#include <GLFW/glfw3.h>
    1.11 +
    1.12 +void keyb(GLFWwindow *win, int key, int sc, int act, int mods);
    1.13 +int init(void);
    1.14 +void destroy(void);
    1.15 +void draw(void);
    1.16 +
    1.17 +GLFWwindow *win;
    1.18 +int win_width = 800;
    1.19 +int win_height = 600;
    1.20 +int redraw_pending;
    1.21 +
    1.22 +int main(void)
    1.23 +{
    1.24 +	if(!glfwInit()) {
    1.25 +		fprintf(stderr, "glfw init failed\n");
    1.26 +		return 1;
    1.27 +	}
    1.28 +
    1.29 +	glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    1.30 +	win = glfwCreateWindow(win_width, win_height, "test", 0, 0);
    1.31 +	glfwSetKeyCallback(win, keyb);
    1.32 +
    1.33 +	if(init() == -1) {
    1.34 +		glfwDestroyWindow(win);
    1.35 +		glfwTerminate();
    1.36 +		return 1;
    1.37 +	}
    1.38 +
    1.39 +	redraw_pending = 1;
    1.40 +
    1.41 +	while(!glfwWindowShouldClose(win)) {
    1.42 +		glfwWaitEvents();
    1.43 +
    1.44 +		if(redraw_pending) {
    1.45 +			redraw_pending = 0;
    1.46 +			draw();
    1.47 +		}
    1.48 +	}
    1.49 +
    1.50 +	destroy();
    1.51 +	glfwDestroyWindow(win);
    1.52 +	glfwTerminate();
    1.53 +	return 0;
    1.54 +}
    1.55 +
    1.56 +void keyb(GLFWwindow *win, int key, int sc, int act, int mods)
    1.57 +{
    1.58 +	if(act == GLFW_PRESS) {
    1.59 +		switch(key) {
    1.60 +		case GLFW_KEY_ESCAPE:
    1.61 +			glfwSetWindowShouldClose(win, 1);
    1.62 +			break;
    1.63 +		}
    1.64 +	}
    1.65 +}
    1.66 +
    1.67 +/* -------------------------------------------------------------- */
    1.68 +int create_instance(void);
    1.69 +int create_surface(void);
    1.70 +int choose_phys_dev(void);
    1.71 +int create_device(void);
    1.72 +int create_swapchain(void);
    1.73 +int create_imgviews(void);
    1.74 +int create_rendpass(void);
    1.75 +int create_pipeline(void);
    1.76 +int create_framebuf(void);
    1.77 +int create_cmdpool(void);
    1.78 +int create_cmdbuf(void);
    1.79 +int create_semaphores(void);
    1.80 +VkShaderModule load_shader(const char *fname);
    1.81 +
    1.82 +VkInstance vk;
    1.83 +VkPhysicalDevice vkpdev;
    1.84 +int vkqfam_idx = -1;
    1.85 +VkDevice vkdev;
    1.86 +VkQueue vkq;
    1.87 +VkSurfaceKHR vksurf;
    1.88 +VkSurfaceCapabilitiesKHR vksurf_caps;
    1.89 +int vksurf_numfmt, vksurf_selfmt;
    1.90 +VkSurfaceFormatKHR *vksurf_fmt;
    1.91 +VkSwapchainKHR vksc;
    1.92 +int vksc_numimg;
    1.93 +VkImage *vksc_img;
    1.94 +VkExtent2D vksc_extent;
    1.95 +VkImageView *vksc_view;
    1.96 +VkRenderPass vkrpass;
    1.97 +VkPipelineLayout vkpipe_layout;
    1.98 +VkPipeline vkpipe;
    1.99 +VkFramebuffer *vksc_fb;
   1.100 +VkCommandPool vkcmdpool;
   1.101 +VkCommandBuffer *vksc_cmdbuf;
   1.102 +VkSemaphore sem_gotimg, sem_drawdone;
   1.103 +
   1.104 +int init(void)
   1.105 +{
   1.106 +	if(create_instance() == -1) return -1;
   1.107 +	if(create_surface() == -1) return -1;
   1.108 +	if(choose_phys_dev() == -1) return -1;
   1.109 +	if(create_device() == -1) return -1;
   1.110 +	if(create_swapchain() == -1) return -1;
   1.111 +	if(create_imgviews() == -1) return -1;
   1.112 +	if(create_rendpass() == -1) return -1;
   1.113 +	if(create_pipeline() == -1) return -1;
   1.114 +	if(create_framebuf() == -1) return -1;
   1.115 +	if(create_cmdpool() == -1) return -1;
   1.116 +	if(create_cmdbuf() == -1) return -1;
   1.117 +	if(create_semaphores() == -1) return -1;
   1.118 +	return 0;
   1.119 +}
   1.120 +
   1.121 +void destroy(void)
   1.122 +{
   1.123 +	int i;
   1.124 +
   1.125 +	if(sem_gotimg) vkDestroySemaphore(vkdev, sem_gotimg, 0);
   1.126 +	if(sem_drawdone) vkDestroySemaphore(vkdev, sem_drawdone, 0);
   1.127 +	if(vkcmdpool) vkDestroyCommandPool(vkdev, vkcmdpool, 0);
   1.128 +	if(vksc_fb) {
   1.129 +		for(i=0; i<vksc_numimg; i++) {
   1.130 +			vkDestroyFramebuffer(vkdev, vksc_fb[i], 0);
   1.131 +		}
   1.132 +	}
   1.133 +	if(vkpipe) vkDestroyPipeline(vkdev, vkpipe, 0);
   1.134 +	if(vkpipe_layout) vkDestroyPipelineLayout(vkdev, vkpipe_layout, 0);
   1.135 +	if(vkrpass) vkDestroyRenderPass(vkdev, vkrpass, 0);
   1.136 +	if(vksc_view) {
   1.137 +		for(i=0; i<vksc_numimg; i++) {
   1.138 +			vkDestroyImageView(vkdev, vksc_view[i], 0);
   1.139 +		}
   1.140 +	}
   1.141 +	if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
   1.142 +	if(vkdev) vkDestroyDevice(vkdev, 0);
   1.143 +	if(vksurf) vkDestroySurfaceKHR(vk, vksurf, 0);
   1.144 +	if(vk) vkDestroyInstance(vk, 0);
   1.145 +}
   1.146 +
   1.147 +void draw(void)
   1.148 +{
   1.149 +	uint32_t img_idx;
   1.150 +	VkSubmitInfo submit;
   1.151 +	VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
   1.152 +	VkPresentInfoKHR pres;
   1.153 +
   1.154 +	vkAcquireNextImageKHR(vkdev, vksc, UINT64_MAX, sem_gotimg, 0, &img_idx);
   1.155 +
   1.156 +	memset(&submit, 0, sizeof submit);
   1.157 +	submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
   1.158 +	submit.waitSemaphoreCount = 1;
   1.159 +	submit.pWaitSemaphores = &sem_gotimg;
   1.160 +	submit.pWaitDstStageMask = &wait_stages;
   1.161 +	submit.commandBufferCount = 1;
   1.162 +	submit.pCommandBuffers = vksc_cmdbuf + img_idx;
   1.163 +	submit.signalSemaphoreCount = 1;
   1.164 +	submit.pSignalSemaphores = &sem_drawdone;
   1.165 +
   1.166 +	if(vkQueueSubmit(vkq, 1, &submit, 0) != 0) {
   1.167 +		fprintf(stderr, "failed to submit draw commands\n");
   1.168 +		abort();
   1.169 +	}
   1.170 +
   1.171 +	memset(&pres, 0, sizeof pres);
   1.172 +	pres.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
   1.173 +	pres.waitSemaphoreCount = 1;
   1.174 +	pres.pWaitSemaphores = &sem_drawdone;
   1.175 +	pres.swapchainCount = 1;
   1.176 +	pres.pSwapchains = &vksc;
   1.177 +	pres.pImageIndices = &img_idx;
   1.178 +
   1.179 +	vkQueuePresentKHR(vkq, &pres);
   1.180 +}
   1.181 +
   1.182 +int create_instance(void)
   1.183 +{
   1.184 +	VkApplicationInfo appinf;
   1.185 +	VkInstanceCreateInfo iinf;
   1.186 +	uint32_t num_ext;
   1.187 +	const char **ext;
   1.188 +
   1.189 +	ext = glfwGetRequiredInstanceExtensions(&num_ext);
   1.190 +
   1.191 +	memset(&appinf, 0, sizeof appinf);
   1.192 +	appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
   1.193 +	appinf.pApplicationName = "test";
   1.194 +	appinf.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
   1.195 +	appinf.pEngineName = "fuckoff";
   1.196 +	appinf.engineVersion = VK_MAKE_VERSION(1, 0, 0);
   1.197 +	appinf.apiVersion = VK_API_VERSION_1_0;
   1.198 +
   1.199 +	memset(&iinf, 0, sizeof iinf);
   1.200 +	iinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
   1.201 +	iinf.pApplicationInfo = &appinf;
   1.202 +	iinf.enabledExtensionCount = num_ext;
   1.203 +	iinf.ppEnabledExtensionNames = ext;
   1.204 +
   1.205 +	if(vkCreateInstance(&iinf, 0, &vk) != 0) {
   1.206 +		fprintf(stderr, "failed to create instance\n");
   1.207 +		return -1;
   1.208 +	}
   1.209 +	return 0;
   1.210 +}
   1.211 +
   1.212 +int create_surface(void)
   1.213 +{
   1.214 +	if(glfwCreateWindowSurface(vk, win, 0, &vksurf) != 0) {
   1.215 +		fprintf(stderr, "failed to create window surface\n");
   1.216 +		return -1;
   1.217 +	}
   1.218 +	return 0;
   1.219 +}
   1.220 +
   1.221 +static int is_pdev_skookum(VkPhysicalDevice dev)
   1.222 +{
   1.223 +	uint32_t i, num_fmt, num_qfam, num_ext;
   1.224 +	VkQueueFamilyProperties *qfam;
   1.225 +	VkExtensionProperties *ext;
   1.226 +	VkPhysicalDeviceProperties prop;
   1.227 +	VkPhysicalDeviceFeatures feat;
   1.228 +	VkBool32 can_pres;
   1.229 +	int have_swap_ext;
   1.230 +
   1.231 +	vkGetPhysicalDeviceProperties(dev, &prop);
   1.232 +	vkGetPhysicalDeviceFeatures(dev, &feat);
   1.233 +
   1.234 +	/* check if we have the swapchain extension */
   1.235 +	vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, 0);
   1.236 +	ext = alloca(num_ext * sizeof *ext);
   1.237 +	vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, ext);
   1.238 +
   1.239 +	have_swap_ext = 0;
   1.240 +	for(i=0; i<num_ext; i++) {
   1.241 +		if(strcmp(ext[i].extensionName, "VK_KHR_swapchain") == 0) {
   1.242 +			have_swap_ext = 1;
   1.243 +			break;
   1.244 +		}
   1.245 +	}
   1.246 +	if(!have_swap_ext) {
   1.247 +		return 0;
   1.248 +	}
   1.249 +
   1.250 +	/* populate format and present modes arrays, and make sure we have some of each */
   1.251 +	vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
   1.252 +	if(!num_fmt || !(vksurf_fmt = malloc(num_fmt * sizeof *vksurf_fmt))) {
   1.253 +		return 0;
   1.254 +	}
   1.255 +	vksurf_numfmt = num_fmt;
   1.256 +	vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, vksurf_fmt);
   1.257 +
   1.258 +	vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
   1.259 +
   1.260 +	/* find a queue family which can do graphics and can present */
   1.261 +	vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
   1.262 +	qfam = alloca(num_qfam * sizeof *qfam);
   1.263 +	vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
   1.264 +
   1.265 +	vkqfam_idx = -1;
   1.266 +	for(i=0; i<num_qfam; i++) {
   1.267 +		vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, vksurf, &can_pres);
   1.268 +		if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
   1.269 +			vkqfam_idx = i;
   1.270 +			return 1;
   1.271 +		}
   1.272 +	}
   1.273 +
   1.274 +	free(vksurf_fmt);
   1.275 +	vksurf_fmt = 0;
   1.276 +	vksurf_numfmt = 0;
   1.277 +	return 0;
   1.278 +}
   1.279 +
   1.280 +static int choose_pixfmt(void)
   1.281 +{
   1.282 +	int i, j;
   1.283 +	static const VkFormat pref[] = {
   1.284 +		VK_FORMAT_B8G8R8_UNORM,
   1.285 +		VK_FORMAT_R8G8B8_UNORM,
   1.286 +		VK_FORMAT_B8G8R8A8_UNORM,
   1.287 +		VK_FORMAT_R8G8B8A8_UNORM
   1.288 +	};
   1.289 +
   1.290 +	vksurf_selfmt = 0;
   1.291 +	for(i=0; i<vksurf_numfmt; i++) {
   1.292 +		if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
   1.293 +			continue;
   1.294 +		}
   1.295 +		for(j=0; j<sizeof pref / sizeof *pref; j++) {
   1.296 +			if(vksurf_fmt[i].format == pref[j]) {
   1.297 +				vksurf_selfmt = i;
   1.298 +				return i;
   1.299 +			}
   1.300 +		}
   1.301 +	}
   1.302 +	return -1;
   1.303 +}
   1.304 +
   1.305 +int choose_phys_dev(void)
   1.306 +{
   1.307 +	uint32_t i, num_pdev;
   1.308 +	VkPhysicalDevice *pdev;
   1.309 +
   1.310 +	vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
   1.311 +	if(!num_pdev) {
   1.312 +		fprintf(stderr, "no vulkan devices found\n");
   1.313 +		return -1;
   1.314 +	}
   1.315 +	pdev = alloca(num_pdev * sizeof *pdev);
   1.316 +	vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
   1.317 +
   1.318 +	for(i=0; i<num_pdev; i++) {
   1.319 +		if(is_pdev_skookum(pdev[i])) {
   1.320 +			vkpdev = pdev[i];
   1.321 +			break;
   1.322 +		}
   1.323 +	}
   1.324 +	if(!vkpdev) {
   1.325 +		fprintf(stderr, "no skookum device found, vulkan can't chooch\n");
   1.326 +		return -1;
   1.327 +	}
   1.328 +
   1.329 +	choose_pixfmt();
   1.330 +	return 0;
   1.331 +}
   1.332 +
   1.333 +int create_device(void)
   1.334 +{
   1.335 +	static const float prio = 1.0f;
   1.336 +	VkDeviceQueueCreateInfo qinf;
   1.337 +	VkPhysicalDeviceFeatures feat;
   1.338 +	VkDeviceCreateInfo devinf;
   1.339 +
   1.340 +	static const char *extensions[] = {
   1.341 +		"VK_KHR_swapchain"
   1.342 +	};
   1.343 +
   1.344 +	memset(&feat, 0, sizeof feat);
   1.345 +
   1.346 +	memset(&qinf, 0, sizeof qinf);
   1.347 +	qinf.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
   1.348 +	qinf.queueFamilyIndex = vkqfam_idx;
   1.349 +	qinf.queueCount = 1;
   1.350 +	qinf.pQueuePriorities = &prio;
   1.351 +
   1.352 +	memset(&devinf, 0, sizeof devinf);
   1.353 +	devinf.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
   1.354 +	devinf.pQueueCreateInfos = &qinf;
   1.355 +	devinf.queueCreateInfoCount = 1;
   1.356 +	devinf.pEnabledFeatures = &feat;
   1.357 +	devinf.enabledExtensionCount = sizeof extensions / sizeof *extensions;
   1.358 +	devinf.ppEnabledExtensionNames = extensions;
   1.359 +
   1.360 +	if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
   1.361 +		fprintf(stderr, "failed to create vulkan device\n");
   1.362 +		return -1;
   1.363 +	}
   1.364 +
   1.365 +	vkGetDeviceQueue(vkdev, vkqfam_idx, 0, &vkq);
   1.366 +	return 0;
   1.367 +}
   1.368 +
   1.369 +int create_swapchain(void)
   1.370 +{
   1.371 +	uint32_t num;
   1.372 +	VkSwapchainCreateInfoKHR scinf;
   1.373 +
   1.374 +	vksc_extent.width = win_width;
   1.375 +	vksc_extent.height = win_height;
   1.376 +
   1.377 +	memset(&scinf, 0, sizeof scinf);
   1.378 +	scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
   1.379 +	scinf.surface = vksurf;
   1.380 +	scinf.minImageCount = 2;
   1.381 +	scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
   1.382 +	scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
   1.383 +	scinf.imageExtent = vksc_extent;
   1.384 +	scinf.imageArrayLayers = 1;
   1.385 +	scinf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
   1.386 +	scinf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
   1.387 +	scinf.preTransform = vksurf_caps.currentTransform;
   1.388 +	scinf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
   1.389 +	scinf.presentMode = VK_PRESENT_MODE_FIFO_KHR;
   1.390 +	scinf.clipped = VK_TRUE;
   1.391 +
   1.392 +	if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
   1.393 +		fprintf(stderr, "failed to create swapchain\n");
   1.394 +		return -1;
   1.395 +	}
   1.396 +
   1.397 +	vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
   1.398 +	if(!num || !(vksc_img = malloc(num * sizeof *vksc_img))) {
   1.399 +		fprintf(stderr, "failed to allocate swapchain image array (%d images)\n", vksc_numimg);
   1.400 +		return -1;
   1.401 +	}
   1.402 +	vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
   1.403 +	vksc_numimg = num;
   1.404 +
   1.405 +	return 0;
   1.406 +}
   1.407 +
   1.408 +int create_imgviews(void)
   1.409 +{
   1.410 +	int i;
   1.411 +	VkImageViewCreateInfo ivinf;
   1.412 +
   1.413 +	if(!(vksc_view = malloc(vksc_numimg * sizeof *vksc_view))) {
   1.414 +		fprintf(stderr, "failed to allocate image view array (%d images)\n", vksc_numimg);
   1.415 +		return -1;
   1.416 +	}
   1.417 +
   1.418 +	for(i=0; i<vksc_numimg; i++) {
   1.419 +		memset(&ivinf, 0, sizeof ivinf);
   1.420 +		ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
   1.421 +		ivinf.image = vksc_img[i];
   1.422 +		ivinf.format = vksurf_fmt[vksurf_selfmt].format;
   1.423 +		ivinf.components.r = ivinf.components.g = ivinf.components.b =
   1.424 +			ivinf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
   1.425 +		ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
   1.426 +		ivinf.subresourceRange.levelCount = 1;
   1.427 +		ivinf.subresourceRange.layerCount = 1;
   1.428 +
   1.429 +		if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
   1.430 +			fprintf(stderr, "failed to create image view for image %d\n", i);
   1.431 +			return -1;
   1.432 +		}
   1.433 +	}
   1.434 +	return 0;
   1.435 +}
   1.436 +
   1.437 +int create_rendpass(void)
   1.438 +{
   1.439 +	VkAttachmentDescription cat;
   1.440 +	VkAttachmentReference catref;
   1.441 +	VkSubpassDescription subpass;
   1.442 +	VkRenderPassCreateInfo pinf;
   1.443 +	VkSubpassDependency dep;
   1.444 +
   1.445 +	memset(&cat, 0, sizeof cat);
   1.446 +	cat.format = vksurf_fmt[vksurf_selfmt].format;
   1.447 +	cat.samples = VK_SAMPLE_COUNT_1_BIT;
   1.448 +	cat.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
   1.449 +	cat.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
   1.450 +	cat.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
   1.451 +	cat.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
   1.452 +	cat.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
   1.453 +	cat.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
   1.454 +
   1.455 +	memset(&catref, 0, sizeof catref);
   1.456 +	catref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
   1.457 +
   1.458 +	memset(&subpass, 0, sizeof subpass);
   1.459 +	subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
   1.460 +	subpass.colorAttachmentCount = 1;
   1.461 +	subpass.pColorAttachments = &catref;
   1.462 +
   1.463 +	memset(&dep, 0, sizeof dep);
   1.464 +	dep.srcSubpass = VK_SUBPASS_EXTERNAL;
   1.465 +	dep.dstSubpass = 0;
   1.466 +	dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
   1.467 +	dep.srcAccessMask = 0;
   1.468 +	dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
   1.469 +	dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
   1.470 +
   1.471 +	memset(&pinf, 0, sizeof pinf);
   1.472 +	pinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
   1.473 +	pinf.attachmentCount = 1;
   1.474 +	pinf.pAttachments = &cat;
   1.475 +	pinf.subpassCount = 1;
   1.476 +	pinf.pSubpasses = &subpass;
   1.477 +	pinf.dependencyCount = 1;
   1.478 +	pinf.pDependencies = &dep;
   1.479 +
   1.480 +	if(vkCreateRenderPass(vkdev, &pinf, 0, &vkrpass) != 0) {
   1.481 +		fprintf(stderr, "failed to create render pass\n");
   1.482 +		return -1;
   1.483 +	}
   1.484 +	return 0;
   1.485 +}
   1.486 +
   1.487 +int create_pipeline(void)
   1.488 +{
   1.489 +	int i;
   1.490 +	VkShaderModule sdr[2];
   1.491 +	VkPipelineShaderStageCreateInfo ssinf[2];
   1.492 +	VkPipelineVertexInputStateCreateInfo vinp;
   1.493 +	VkPipelineInputAssemblyStateCreateInfo vasm;
   1.494 +	VkViewport vport;
   1.495 +	VkRect2D scissor;
   1.496 +	VkPipelineViewportStateCreateInfo vp;
   1.497 +	VkPipelineRasterizationStateCreateInfo rast;
   1.498 +	VkPipelineMultisampleStateCreateInfo msaa;
   1.499 +	VkPipelineColorBlendAttachmentState bat;
   1.500 +	VkPipelineColorBlendStateCreateInfo blend;
   1.501 +	VkPipelineLayoutCreateInfo lay;
   1.502 +	VkGraphicsPipelineCreateInfo pinf;
   1.503 +
   1.504 +	if(!(sdr[0] = load_shader("vertex.glsl")) || !(sdr[1] = load_shader("pixel.glsl"))) {
   1.505 +		return -1;
   1.506 +	}
   1.507 +	memset(ssinf, 0, sizeof ssinf);
   1.508 +	for(i=0; i<2; i++) {
   1.509 +		ssinf[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
   1.510 +		ssinf[i].stage = i == 0 ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
   1.511 +		ssinf[i].module = sdr[i];
   1.512 +		ssinf[i].pName = "main";
   1.513 +	}
   1.514 +
   1.515 +	memset(&vinp, 0, sizeof vinp);
   1.516 +	vinp.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
   1.517 +
   1.518 +	memset(&vasm, 0, sizeof vasm);
   1.519 +	vasm.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
   1.520 +	vasm.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
   1.521 +
   1.522 +	vport.x = vport.y = 0;
   1.523 +	vport.width = vksc_extent.width;
   1.524 +	vport.height = vksc_extent.height;
   1.525 +	vport.minDepth = 0.0f;
   1.526 +	vport.maxDepth = 1.0f;
   1.527 +
   1.528 +	scissor.offset.x = scissor.offset.y = 0;
   1.529 +	scissor.extent = vksc_extent;
   1.530 +
   1.531 +	memset(&vp, 0, sizeof vp);
   1.532 +	vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
   1.533 +	vp.viewportCount = 1;
   1.534 +	vp.pViewports = &vport;
   1.535 +	vp.scissorCount = 1;
   1.536 +	vp.pScissors = &scissor;
   1.537 +
   1.538 +	memset(&rast, 0, sizeof rast);
   1.539 +	rast.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
   1.540 +	rast.polygonMode = VK_POLYGON_MODE_FILL;
   1.541 +	rast.lineWidth = 1.0f;
   1.542 +	rast.cullMode = VK_CULL_MODE_BACK_BIT;
   1.543 +	rast.frontFace = VK_FRONT_FACE_CLOCKWISE;
   1.544 +
   1.545 +	memset(&msaa, 0, sizeof msaa);
   1.546 +	msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
   1.547 +	msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
   1.548 +	msaa.minSampleShading = 1.0f;
   1.549 +
   1.550 +	memset(&bat, 0, sizeof bat);
   1.551 +	bat.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
   1.552 +		VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
   1.553 +
   1.554 +	memset(&blend, 0, sizeof blend);
   1.555 +	blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
   1.556 +	blend.attachmentCount = 1;
   1.557 +	blend.pAttachments = &bat;
   1.558 +
   1.559 +
   1.560 +	memset(&lay, 0, sizeof lay);
   1.561 +	lay.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
   1.562 +
   1.563 +	if(vkCreatePipelineLayout(vkdev, &lay, 0, &vkpipe_layout) != 0) {
   1.564 +		fprintf(stderr, "failed to create a pipeline layout\n");
   1.565 +		return -1;
   1.566 +	}
   1.567 +
   1.568 +	memset(&pinf, 0, sizeof pinf);
   1.569 +	pinf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
   1.570 +	pinf.stageCount = 2;
   1.571 +	pinf.pStages = ssinf;
   1.572 +	pinf.pVertexInputState = &vinp;
   1.573 +	pinf.pInputAssemblyState = &vasm;
   1.574 +	pinf.pViewportState = &vp;
   1.575 +	pinf.pRasterizationState = &rast;
   1.576 +	pinf.pMultisampleState = &msaa;
   1.577 +	pinf.pColorBlendState = &blend;
   1.578 +	pinf.layout = vkpipe_layout;
   1.579 +	pinf.renderPass = vkrpass;
   1.580 +	pinf.basePipelineIndex = -1;
   1.581 +
   1.582 +	if(vkCreateGraphicsPipelines(vkdev, 0, 1, &pinf, 0, &vkpipe) != 0) {
   1.583 +		fprintf(stderr, "failed to create graphics pipeline\n");
   1.584 +		return -1;
   1.585 +	}
   1.586 +
   1.587 +	for(i=0; i<2; i++) {
   1.588 +		vkDestroyShaderModule(vkdev, sdr[i], 0);
   1.589 +	}
   1.590 +	return 0;
   1.591 +}
   1.592 +
   1.593 +int create_framebuf(void)
   1.594 +{
   1.595 +	int i;
   1.596 +	VkFramebufferCreateInfo fbinf;
   1.597 +
   1.598 +	if(!(vksc_fb = malloc(vksc_numimg * sizeof *vksc_fb))) {
   1.599 +		fprintf(stderr, "failed to allocate array for swap chain framebuffers\n");
   1.600 +		return -1;
   1.601 +	}
   1.602 +
   1.603 +	for(i=0; i<vksc_numimg; i++) {
   1.604 +		memset(&fbinf, 0, sizeof fbinf);
   1.605 +		fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
   1.606 +		fbinf.renderPass = vkrpass;
   1.607 +		fbinf.attachmentCount = 1;
   1.608 +		fbinf.pAttachments = vksc_view + i;
   1.609 +		fbinf.width = vksc_extent.width;
   1.610 +		fbinf.height = vksc_extent.height;
   1.611 +		fbinf.layers = 1;
   1.612 +
   1.613 +		if(vkCreateFramebuffer(vkdev, &fbinf, 0, vksc_fb + i) != 0) {
   1.614 +			fprintf(stderr, "failed to create framebuffer\n");
   1.615 +			return -1;
   1.616 +		}
   1.617 +	}
   1.618 +
   1.619 +	return 0;
   1.620 +}
   1.621 +
   1.622 +int create_cmdpool(void)
   1.623 +{
   1.624 +	VkCommandPoolCreateInfo cpinf;
   1.625 +
   1.626 +	memset(&cpinf, 0, sizeof cpinf);
   1.627 +	cpinf.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
   1.628 +	cpinf.queueFamilyIndex = vkqfam_idx;
   1.629 +
   1.630 +	if(vkCreateCommandPool(vkdev, &cpinf, 0, &vkcmdpool) != 0) {
   1.631 +		fprintf(stderr, "failed to create command pool\n");
   1.632 +		return -1;
   1.633 +	}
   1.634 +	return 0;
   1.635 +}
   1.636 +
   1.637 +int create_cmdbuf(void)
   1.638 +{
   1.639 +	int i;
   1.640 +	VkCommandBufferAllocateInfo cbinf;
   1.641 +
   1.642 +	if(!(vksc_cmdbuf = malloc(vksc_numimg * sizeof *vksc_cmdbuf))) {
   1.643 +		fprintf(stderr, "failed to allocate array of command buffers\n");
   1.644 +		return -1;
   1.645 +	}
   1.646 +
   1.647 +	memset(&cbinf, 0, sizeof cbinf);
   1.648 +	cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
   1.649 +	cbinf.commandPool = vkcmdpool;
   1.650 +	cbinf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
   1.651 +	cbinf.commandBufferCount = vksc_numimg;
   1.652 +
   1.653 +	if(vkAllocateCommandBuffers(vkdev, &cbinf, vksc_cmdbuf) != 0) {
   1.654 +		fprintf(stderr, "failed to allocate command buffers\n");
   1.655 +		return -1;
   1.656 +	}
   1.657 +
   1.658 +	/* pre-record command buffers, because why the fuck not */
   1.659 +	for(i=0; i<vksc_numimg; i++) {
   1.660 +		VkCommandBufferBeginInfo cbegin;
   1.661 +		VkRenderPassBeginInfo rbegin;
   1.662 +		VkClearValue clear;
   1.663 +
   1.664 +		memset(&cbegin, 0, sizeof cbegin);
   1.665 +		cbegin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
   1.666 +		cbegin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
   1.667 +
   1.668 +		if(vkBeginCommandBuffer(vksc_cmdbuf[i], &cbegin) != 0) {
   1.669 +			fprintf(stderr, "failed to begin command buffer recording\n");
   1.670 +			return -1;
   1.671 +		}
   1.672 +
   1.673 +		clear.color.float32[0] = 0.2f;
   1.674 +		clear.color.float32[1] = 0.2f;
   1.675 +		clear.color.float32[2] = 0.2f;
   1.676 +		clear.color.float32[3] = 1.0f;
   1.677 +
   1.678 +		memset(&rbegin, 0, sizeof rbegin);
   1.679 +		rbegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
   1.680 +		rbegin.renderPass = vkrpass;
   1.681 +		rbegin.framebuffer = vksc_fb[i];
   1.682 +		rbegin.renderArea.extent = vksc_extent;
   1.683 +		rbegin.clearValueCount = 1;
   1.684 +		rbegin.pClearValues = &clear;
   1.685 +
   1.686 +		vkCmdBeginRenderPass(vksc_cmdbuf[i], &rbegin, VK_SUBPASS_CONTENTS_INLINE);
   1.687 +		vkCmdBindPipeline(vksc_cmdbuf[i], VK_PIPELINE_BIND_POINT_GRAPHICS, vkpipe);
   1.688 +		vkCmdDraw(vksc_cmdbuf[i], 3, 1, 0, 0);
   1.689 +		vkCmdEndRenderPass(vksc_cmdbuf[i]);
   1.690 +
   1.691 +		if(vkEndCommandBuffer(vksc_cmdbuf[i]) != 0) {
   1.692 +			fprintf(stderr, "failed to record command buffer\n");
   1.693 +			return -1;
   1.694 +		}
   1.695 +	}
   1.696 +	return 0;
   1.697 +}
   1.698 +
   1.699 +int create_semaphores(void)
   1.700 +{
   1.701 +	VkSemaphoreCreateInfo sinf;
   1.702 +
   1.703 +	memset(&sinf, 0, sizeof sinf);
   1.704 +	sinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
   1.705 +
   1.706 +	if(vkCreateSemaphore(vkdev, &sinf, 0, &sem_gotimg) != 0) {
   1.707 +		fprintf(stderr, "failed to create semaphore\n");
   1.708 +		return -1;
   1.709 +	}
   1.710 +	if(vkCreateSemaphore(vkdev, &sinf, 0, &sem_drawdone) != 0) {
   1.711 +		fprintf(stderr, "failed to create semaphore\n");
   1.712 +		return -1;
   1.713 +	}
   1.714 +	return 0;
   1.715 +}
   1.716 +
   1.717 +VkShaderModule load_shader(const char *fname)
   1.718 +{
   1.719 +	FILE *fp;
   1.720 +	long sz;
   1.721 +	void *buf;
   1.722 +	VkShaderModuleCreateInfo sinf;
   1.723 +	VkShaderModule sdr;
   1.724 +
   1.725 +	if(!(fp = fopen(fname, "rb"))) {
   1.726 +		fprintf(stderr, "failed to open shader: %s: %s\n", fname, strerror(errno));
   1.727 +		return 0;
   1.728 +	}
   1.729 +	fseek(fp, 0, SEEK_END);
   1.730 +	sz = ftell(fp);
   1.731 +	fseek(fp, 0, SEEK_SET);
   1.732 +
   1.733 +	buf = alloca(sz);
   1.734 +	if(fread(buf, 1, sz, fp) < sz) {
   1.735 +		fprintf(stderr, "unexpected EOF while reading shader: %s\n", fname);
   1.736 +		fclose(fp);
   1.737 +		return 0;
   1.738 +	}
   1.739 +	fclose(fp);
   1.740 +
   1.741 +	memset(&sinf, 0, sizeof sinf);
   1.742 +	sinf.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
   1.743 +	sinf.codeSize = sz;
   1.744 +	sinf.pCode = buf;
   1.745 +
   1.746 +	if(vkCreateShaderModule(vkdev, &sinf, 0, &sdr) != 0) {
   1.747 +		fprintf(stderr, "failed to create shader from %s\n", fname);
   1.748 +		return 0;
   1.749 +	}
   1.750 +	return sdr;
   1.751 +}