vulkan_test_simple

changeset 0:8de4fe926882

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 28 Jun 2018 13:57:28 +0300
parents
children d5a3f6912f4d
files .hgignore Makefile pixel.glsl src/main.c vertex.glsl
diffstat 5 files changed, 810 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Thu Jun 28 13:57:28 2018 +0300
     1.3 @@ -0,0 +1,5 @@
     1.4 +\.o$
     1.5 +\.swp$
     1.6 +\.d$
     1.7 +\.spv$
     1.8 +^test$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Thu Jun 28 13:57:28 2018 +0300
     2.3 @@ -0,0 +1,21 @@
     2.4 +src = $(wildcard src/*.c)
     2.5 +obj = $(src:.c=.o)
     2.6 +bin = test
     2.7 +
     2.8 +def = -DGLFW_INCLUDE_VULKAN
     2.9 +
    2.10 +CFLAGS = -pedantic -Wall -g $(def)
    2.11 +LDFLAGS = -lvulkan -lglfw
    2.12 +
    2.13 +$(bin): $(obj) vertex.spv pixel.spv
    2.14 +	$(CC) -o $@ $(obj) $(LDFLAGS)
    2.15 +
    2.16 +vertex.spv: vertex.glsl
    2.17 +	glslangValidator -o $@ -S vert -V $<
    2.18 +
    2.19 +pixel.spv: pixel.glsl
    2.20 +	glslangValidator -o $@ -S frag -V $<
    2.21 +
    2.22 +.PHONY: clean
    2.23 +clean:
    2.24 +	rm -f $(obj) $(bin) *.spv
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/pixel.glsl	Thu Jun 28 13:57:28 2018 +0300
     3.3 @@ -0,0 +1,10 @@
     3.4 +#version 450
     3.5 +#extension GL_ARB_separate_shader_objects : enable
     3.6 +
     3.7 +layout(location = 0) in vec3 incol;
     3.8 +layout(location = 0) out vec4 outcol;
     3.9 +
    3.10 +void main()
    3.11 +{
    3.12 +	outcol = vec4(incol, 1.0);
    3.13 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/main.c	Thu Jun 28 13:57:28 2018 +0300
     4.3 @@ -0,0 +1,748 @@
     4.4 +#include <stdio.h>
     4.5 +#include <stdlib.h>
     4.6 +#include <string.h>
     4.7 +#include <stdint.h>
     4.8 +#include <errno.h>
     4.9 +#include <alloca.h>
    4.10 +#include <GLFW/glfw3.h>
    4.11 +
    4.12 +void keyb(GLFWwindow *win, int key, int sc, int act, int mods);
    4.13 +int init(void);
    4.14 +void destroy(void);
    4.15 +void draw(void);
    4.16 +
    4.17 +GLFWwindow *win;
    4.18 +int win_width = 800;
    4.19 +int win_height = 600;
    4.20 +int redraw_pending;
    4.21 +
    4.22 +int main(void)
    4.23 +{
    4.24 +	if(!glfwInit()) {
    4.25 +		fprintf(stderr, "glfw init failed\n");
    4.26 +		return 1;
    4.27 +	}
    4.28 +
    4.29 +	glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    4.30 +	win = glfwCreateWindow(win_width, win_height, "test", 0, 0);
    4.31 +	glfwSetKeyCallback(win, keyb);
    4.32 +
    4.33 +	if(init() == -1) {
    4.34 +		glfwDestroyWindow(win);
    4.35 +		glfwTerminate();
    4.36 +		return 1;
    4.37 +	}
    4.38 +
    4.39 +	redraw_pending = 1;
    4.40 +
    4.41 +	while(!glfwWindowShouldClose(win)) {
    4.42 +		glfwWaitEvents();
    4.43 +
    4.44 +		if(redraw_pending) {
    4.45 +			redraw_pending = 0;
    4.46 +			draw();
    4.47 +		}
    4.48 +	}
    4.49 +
    4.50 +	destroy();
    4.51 +	glfwDestroyWindow(win);
    4.52 +	glfwTerminate();
    4.53 +	return 0;
    4.54 +}
    4.55 +
    4.56 +void keyb(GLFWwindow *win, int key, int sc, int act, int mods)
    4.57 +{
    4.58 +	if(act == GLFW_PRESS) {
    4.59 +		switch(key) {
    4.60 +		case GLFW_KEY_ESCAPE:
    4.61 +			glfwSetWindowShouldClose(win, 1);
    4.62 +			break;
    4.63 +		}
    4.64 +	}
    4.65 +}
    4.66 +
    4.67 +/* -------------------------------------------------------------- */
    4.68 +int create_instance(void);
    4.69 +int create_surface(void);
    4.70 +int choose_phys_dev(void);
    4.71 +int create_device(void);
    4.72 +int create_swapchain(void);
    4.73 +int create_imgviews(void);
    4.74 +int create_rendpass(void);
    4.75 +int create_pipeline(void);
    4.76 +int create_framebuf(void);
    4.77 +int create_cmdpool(void);
    4.78 +int create_cmdbuf(void);
    4.79 +int create_semaphores(void);
    4.80 +VkShaderModule load_shader(const char *fname);
    4.81 +
    4.82 +VkInstance vk;
    4.83 +VkPhysicalDevice vkpdev;
    4.84 +int vkqfam_idx = -1;
    4.85 +VkDevice vkdev;
    4.86 +VkQueue vkq;
    4.87 +VkSurfaceKHR vksurf;
    4.88 +VkSurfaceCapabilitiesKHR vksurf_caps;
    4.89 +int vksurf_numfmt, vksurf_selfmt;
    4.90 +VkSurfaceFormatKHR *vksurf_fmt;
    4.91 +VkSwapchainKHR vksc;
    4.92 +int vksc_numimg;
    4.93 +VkImage *vksc_img;
    4.94 +VkExtent2D vksc_extent;
    4.95 +VkImageView *vksc_view;
    4.96 +VkRenderPass vkrpass;
    4.97 +VkPipelineLayout vkpipe_layout;
    4.98 +VkPipeline vkpipe;
    4.99 +VkFramebuffer *vksc_fb;
   4.100 +VkCommandPool vkcmdpool;
   4.101 +VkCommandBuffer *vksc_cmdbuf;
   4.102 +VkSemaphore sem_gotimg, sem_drawdone;
   4.103 +
   4.104 +int init(void)
   4.105 +{
   4.106 +	if(create_instance() == -1) return -1;
   4.107 +	if(create_surface() == -1) return -1;
   4.108 +	if(choose_phys_dev() == -1) return -1;
   4.109 +	if(create_device() == -1) return -1;
   4.110 +	if(create_swapchain() == -1) return -1;
   4.111 +	if(create_imgviews() == -1) return -1;
   4.112 +	if(create_rendpass() == -1) return -1;
   4.113 +	if(create_pipeline() == -1) return -1;
   4.114 +	if(create_framebuf() == -1) return -1;
   4.115 +	if(create_cmdpool() == -1) return -1;
   4.116 +	if(create_cmdbuf() == -1) return -1;
   4.117 +	if(create_semaphores() == -1) return -1;
   4.118 +	return 0;
   4.119 +}
   4.120 +
   4.121 +void destroy(void)
   4.122 +{
   4.123 +	int i;
   4.124 +
   4.125 +	if(sem_gotimg) vkDestroySemaphore(vkdev, sem_gotimg, 0);
   4.126 +	if(sem_drawdone) vkDestroySemaphore(vkdev, sem_drawdone, 0);
   4.127 +	if(vkcmdpool) vkDestroyCommandPool(vkdev, vkcmdpool, 0);
   4.128 +	if(vksc_fb) {
   4.129 +		for(i=0; i<vksc_numimg; i++) {
   4.130 +			vkDestroyFramebuffer(vkdev, vksc_fb[i], 0);
   4.131 +		}
   4.132 +	}
   4.133 +	if(vkpipe) vkDestroyPipeline(vkdev, vkpipe, 0);
   4.134 +	if(vkpipe_layout) vkDestroyPipelineLayout(vkdev, vkpipe_layout, 0);
   4.135 +	if(vkrpass) vkDestroyRenderPass(vkdev, vkrpass, 0);
   4.136 +	if(vksc_view) {
   4.137 +		for(i=0; i<vksc_numimg; i++) {
   4.138 +			vkDestroyImageView(vkdev, vksc_view[i], 0);
   4.139 +		}
   4.140 +	}
   4.141 +	if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
   4.142 +	if(vkdev) vkDestroyDevice(vkdev, 0);
   4.143 +	if(vksurf) vkDestroySurfaceKHR(vk, vksurf, 0);
   4.144 +	if(vk) vkDestroyInstance(vk, 0);
   4.145 +}
   4.146 +
   4.147 +void draw(void)
   4.148 +{
   4.149 +	uint32_t img_idx;
   4.150 +	VkSubmitInfo submit;
   4.151 +	VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
   4.152 +	VkPresentInfoKHR pres;
   4.153 +
   4.154 +	vkAcquireNextImageKHR(vkdev, vksc, UINT64_MAX, sem_gotimg, 0, &img_idx);
   4.155 +
   4.156 +	memset(&submit, 0, sizeof submit);
   4.157 +	submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
   4.158 +	submit.waitSemaphoreCount = 1;
   4.159 +	submit.pWaitSemaphores = &sem_gotimg;
   4.160 +	submit.pWaitDstStageMask = &wait_stages;
   4.161 +	submit.commandBufferCount = 1;
   4.162 +	submit.pCommandBuffers = vksc_cmdbuf + img_idx;
   4.163 +	submit.signalSemaphoreCount = 1;
   4.164 +	submit.pSignalSemaphores = &sem_drawdone;
   4.165 +
   4.166 +	if(vkQueueSubmit(vkq, 1, &submit, 0) != 0) {
   4.167 +		fprintf(stderr, "failed to submit draw commands\n");
   4.168 +		abort();
   4.169 +	}
   4.170 +
   4.171 +	memset(&pres, 0, sizeof pres);
   4.172 +	pres.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
   4.173 +	pres.waitSemaphoreCount = 1;
   4.174 +	pres.pWaitSemaphores = &sem_drawdone;
   4.175 +	pres.swapchainCount = 1;
   4.176 +	pres.pSwapchains = &vksc;
   4.177 +	pres.pImageIndices = &img_idx;
   4.178 +
   4.179 +	vkQueuePresentKHR(vkq, &pres);
   4.180 +}
   4.181 +
   4.182 +int create_instance(void)
   4.183 +{
   4.184 +	VkApplicationInfo appinf;
   4.185 +	VkInstanceCreateInfo iinf;
   4.186 +	uint32_t num_ext;
   4.187 +	const char **ext;
   4.188 +
   4.189 +	ext = glfwGetRequiredInstanceExtensions(&num_ext);
   4.190 +
   4.191 +	memset(&appinf, 0, sizeof appinf);
   4.192 +	appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
   4.193 +	appinf.pApplicationName = "test";
   4.194 +	appinf.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
   4.195 +	appinf.pEngineName = "fuckoff";
   4.196 +	appinf.engineVersion = VK_MAKE_VERSION(1, 0, 0);
   4.197 +	appinf.apiVersion = VK_API_VERSION_1_0;
   4.198 +
   4.199 +	memset(&iinf, 0, sizeof iinf);
   4.200 +	iinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
   4.201 +	iinf.pApplicationInfo = &appinf;
   4.202 +	iinf.enabledExtensionCount = num_ext;
   4.203 +	iinf.ppEnabledExtensionNames = ext;
   4.204 +
   4.205 +	if(vkCreateInstance(&iinf, 0, &vk) != 0) {
   4.206 +		fprintf(stderr, "failed to create instance\n");
   4.207 +		return -1;
   4.208 +	}
   4.209 +	return 0;
   4.210 +}
   4.211 +
   4.212 +int create_surface(void)
   4.213 +{
   4.214 +	if(glfwCreateWindowSurface(vk, win, 0, &vksurf) != 0) {
   4.215 +		fprintf(stderr, "failed to create window surface\n");
   4.216 +		return -1;
   4.217 +	}
   4.218 +	return 0;
   4.219 +}
   4.220 +
   4.221 +static int is_pdev_skookum(VkPhysicalDevice dev)
   4.222 +{
   4.223 +	uint32_t i, num_fmt, num_qfam, num_ext;
   4.224 +	VkQueueFamilyProperties *qfam;
   4.225 +	VkExtensionProperties *ext;
   4.226 +	VkPhysicalDeviceProperties prop;
   4.227 +	VkPhysicalDeviceFeatures feat;
   4.228 +	VkBool32 can_pres;
   4.229 +	int have_swap_ext;
   4.230 +
   4.231 +	vkGetPhysicalDeviceProperties(dev, &prop);
   4.232 +	vkGetPhysicalDeviceFeatures(dev, &feat);
   4.233 +
   4.234 +	/* check if we have the swapchain extension */
   4.235 +	vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, 0);
   4.236 +	ext = alloca(num_ext * sizeof *ext);
   4.237 +	vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, ext);
   4.238 +
   4.239 +	have_swap_ext = 0;
   4.240 +	for(i=0; i<num_ext; i++) {
   4.241 +		if(strcmp(ext[i].extensionName, "VK_KHR_swapchain") == 0) {
   4.242 +			have_swap_ext = 1;
   4.243 +			break;
   4.244 +		}
   4.245 +	}
   4.246 +	if(!have_swap_ext) {
   4.247 +		return 0;
   4.248 +	}
   4.249 +
   4.250 +	/* populate format and present modes arrays, and make sure we have some of each */
   4.251 +	vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
   4.252 +	if(!num_fmt || !(vksurf_fmt = malloc(num_fmt * sizeof *vksurf_fmt))) {
   4.253 +		return 0;
   4.254 +	}
   4.255 +	vksurf_numfmt = num_fmt;
   4.256 +	vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, vksurf_fmt);
   4.257 +
   4.258 +	vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
   4.259 +
   4.260 +	/* find a queue family which can do graphics and can present */
   4.261 +	vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
   4.262 +	qfam = alloca(num_qfam * sizeof *qfam);
   4.263 +	vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
   4.264 +
   4.265 +	vkqfam_idx = -1;
   4.266 +	for(i=0; i<num_qfam; i++) {
   4.267 +		vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, vksurf, &can_pres);
   4.268 +		if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
   4.269 +			vkqfam_idx = i;
   4.270 +			return 1;
   4.271 +		}
   4.272 +	}
   4.273 +
   4.274 +	free(vksurf_fmt);
   4.275 +	vksurf_fmt = 0;
   4.276 +	vksurf_numfmt = 0;
   4.277 +	return 0;
   4.278 +}
   4.279 +
   4.280 +static int choose_pixfmt(void)
   4.281 +{
   4.282 +	int i, j;
   4.283 +	static const VkFormat pref[] = {
   4.284 +		VK_FORMAT_B8G8R8_UNORM,
   4.285 +		VK_FORMAT_R8G8B8_UNORM,
   4.286 +		VK_FORMAT_B8G8R8A8_UNORM,
   4.287 +		VK_FORMAT_R8G8B8A8_UNORM
   4.288 +	};
   4.289 +
   4.290 +	vksurf_selfmt = 0;
   4.291 +	for(i=0; i<vksurf_numfmt; i++) {
   4.292 +		if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
   4.293 +			continue;
   4.294 +		}
   4.295 +		for(j=0; j<sizeof pref / sizeof *pref; j++) {
   4.296 +			if(vksurf_fmt[i].format == pref[j]) {
   4.297 +				vksurf_selfmt = i;
   4.298 +				return i;
   4.299 +			}
   4.300 +		}
   4.301 +	}
   4.302 +	return -1;
   4.303 +}
   4.304 +
   4.305 +int choose_phys_dev(void)
   4.306 +{
   4.307 +	uint32_t i, num_pdev;
   4.308 +	VkPhysicalDevice *pdev;
   4.309 +
   4.310 +	vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
   4.311 +	if(!num_pdev) {
   4.312 +		fprintf(stderr, "no vulkan devices found\n");
   4.313 +		return -1;
   4.314 +	}
   4.315 +	pdev = alloca(num_pdev * sizeof *pdev);
   4.316 +	vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
   4.317 +
   4.318 +	for(i=0; i<num_pdev; i++) {
   4.319 +		if(is_pdev_skookum(pdev[i])) {
   4.320 +			vkpdev = pdev[i];
   4.321 +			break;
   4.322 +		}
   4.323 +	}
   4.324 +	if(!vkpdev) {
   4.325 +		fprintf(stderr, "no skookum device found, vulkan can't chooch\n");
   4.326 +		return -1;
   4.327 +	}
   4.328 +
   4.329 +	choose_pixfmt();
   4.330 +	return 0;
   4.331 +}
   4.332 +
   4.333 +int create_device(void)
   4.334 +{
   4.335 +	static const float prio = 1.0f;
   4.336 +	VkDeviceQueueCreateInfo qinf;
   4.337 +	VkPhysicalDeviceFeatures feat;
   4.338 +	VkDeviceCreateInfo devinf;
   4.339 +
   4.340 +	static const char *extensions[] = {
   4.341 +		"VK_KHR_swapchain"
   4.342 +	};
   4.343 +
   4.344 +	memset(&feat, 0, sizeof feat);
   4.345 +
   4.346 +	memset(&qinf, 0, sizeof qinf);
   4.347 +	qinf.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
   4.348 +	qinf.queueFamilyIndex = vkqfam_idx;
   4.349 +	qinf.queueCount = 1;
   4.350 +	qinf.pQueuePriorities = &prio;
   4.351 +
   4.352 +	memset(&devinf, 0, sizeof devinf);
   4.353 +	devinf.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
   4.354 +	devinf.pQueueCreateInfos = &qinf;
   4.355 +	devinf.queueCreateInfoCount = 1;
   4.356 +	devinf.pEnabledFeatures = &feat;
   4.357 +	devinf.enabledExtensionCount = sizeof extensions / sizeof *extensions;
   4.358 +	devinf.ppEnabledExtensionNames = extensions;
   4.359 +
   4.360 +	if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
   4.361 +		fprintf(stderr, "failed to create vulkan device\n");
   4.362 +		return -1;
   4.363 +	}
   4.364 +
   4.365 +	vkGetDeviceQueue(vkdev, vkqfam_idx, 0, &vkq);
   4.366 +	return 0;
   4.367 +}
   4.368 +
   4.369 +int create_swapchain(void)
   4.370 +{
   4.371 +	uint32_t num;
   4.372 +	VkSwapchainCreateInfoKHR scinf;
   4.373 +
   4.374 +	vksc_extent.width = win_width;
   4.375 +	vksc_extent.height = win_height;
   4.376 +
   4.377 +	memset(&scinf, 0, sizeof scinf);
   4.378 +	scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
   4.379 +	scinf.surface = vksurf;
   4.380 +	scinf.minImageCount = 2;
   4.381 +	scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
   4.382 +	scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
   4.383 +	scinf.imageExtent = vksc_extent;
   4.384 +	scinf.imageArrayLayers = 1;
   4.385 +	scinf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
   4.386 +	scinf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
   4.387 +	scinf.preTransform = vksurf_caps.currentTransform;
   4.388 +	scinf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
   4.389 +	scinf.presentMode = VK_PRESENT_MODE_FIFO_KHR;
   4.390 +	scinf.clipped = VK_TRUE;
   4.391 +
   4.392 +	if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
   4.393 +		fprintf(stderr, "failed to create swapchain\n");
   4.394 +		return -1;
   4.395 +	}
   4.396 +
   4.397 +	vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
   4.398 +	if(!num || !(vksc_img = malloc(num * sizeof *vksc_img))) {
   4.399 +		fprintf(stderr, "failed to allocate swapchain image array (%d images)\n", vksc_numimg);
   4.400 +		return -1;
   4.401 +	}
   4.402 +	vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
   4.403 +	vksc_numimg = num;
   4.404 +
   4.405 +	return 0;
   4.406 +}
   4.407 +
   4.408 +int create_imgviews(void)
   4.409 +{
   4.410 +	int i;
   4.411 +	VkImageViewCreateInfo ivinf;
   4.412 +
   4.413 +	if(!(vksc_view = malloc(vksc_numimg * sizeof *vksc_view))) {
   4.414 +		fprintf(stderr, "failed to allocate image view array (%d images)\n", vksc_numimg);
   4.415 +		return -1;
   4.416 +	}
   4.417 +
   4.418 +	for(i=0; i<vksc_numimg; i++) {
   4.419 +		memset(&ivinf, 0, sizeof ivinf);
   4.420 +		ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
   4.421 +		ivinf.image = vksc_img[i];
   4.422 +		ivinf.format = vksurf_fmt[vksurf_selfmt].format;
   4.423 +		ivinf.components.r = ivinf.components.g = ivinf.components.b =
   4.424 +			ivinf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
   4.425 +		ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
   4.426 +		ivinf.subresourceRange.levelCount = 1;
   4.427 +		ivinf.subresourceRange.layerCount = 1;
   4.428 +
   4.429 +		if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
   4.430 +			fprintf(stderr, "failed to create image view for image %d\n", i);
   4.431 +			return -1;
   4.432 +		}
   4.433 +	}
   4.434 +	return 0;
   4.435 +}
   4.436 +
   4.437 +int create_rendpass(void)
   4.438 +{
   4.439 +	VkAttachmentDescription cat;
   4.440 +	VkAttachmentReference catref;
   4.441 +	VkSubpassDescription subpass;
   4.442 +	VkRenderPassCreateInfo pinf;
   4.443 +	VkSubpassDependency dep;
   4.444 +
   4.445 +	memset(&cat, 0, sizeof cat);
   4.446 +	cat.format = vksurf_fmt[vksurf_selfmt].format;
   4.447 +	cat.samples = VK_SAMPLE_COUNT_1_BIT;
   4.448 +	cat.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
   4.449 +	cat.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
   4.450 +	cat.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
   4.451 +	cat.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
   4.452 +	cat.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
   4.453 +	cat.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
   4.454 +
   4.455 +	memset(&catref, 0, sizeof catref);
   4.456 +	catref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
   4.457 +
   4.458 +	memset(&subpass, 0, sizeof subpass);
   4.459 +	subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
   4.460 +	subpass.colorAttachmentCount = 1;
   4.461 +	subpass.pColorAttachments = &catref;
   4.462 +
   4.463 +	memset(&dep, 0, sizeof dep);
   4.464 +	dep.srcSubpass = VK_SUBPASS_EXTERNAL;
   4.465 +	dep.dstSubpass = 0;
   4.466 +	dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
   4.467 +	dep.srcAccessMask = 0;
   4.468 +	dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
   4.469 +	dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
   4.470 +
   4.471 +	memset(&pinf, 0, sizeof pinf);
   4.472 +	pinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
   4.473 +	pinf.attachmentCount = 1;
   4.474 +	pinf.pAttachments = &cat;
   4.475 +	pinf.subpassCount = 1;
   4.476 +	pinf.pSubpasses = &subpass;
   4.477 +	pinf.dependencyCount = 1;
   4.478 +	pinf.pDependencies = &dep;
   4.479 +
   4.480 +	if(vkCreateRenderPass(vkdev, &pinf, 0, &vkrpass) != 0) {
   4.481 +		fprintf(stderr, "failed to create render pass\n");
   4.482 +		return -1;
   4.483 +	}
   4.484 +	return 0;
   4.485 +}
   4.486 +
   4.487 +int create_pipeline(void)
   4.488 +{
   4.489 +	int i;
   4.490 +	VkShaderModule sdr[2];
   4.491 +	VkPipelineShaderStageCreateInfo ssinf[2];
   4.492 +	VkPipelineVertexInputStateCreateInfo vinp;
   4.493 +	VkPipelineInputAssemblyStateCreateInfo vasm;
   4.494 +	VkViewport vport;
   4.495 +	VkRect2D scissor;
   4.496 +	VkPipelineViewportStateCreateInfo vp;
   4.497 +	VkPipelineRasterizationStateCreateInfo rast;
   4.498 +	VkPipelineMultisampleStateCreateInfo msaa;
   4.499 +	VkPipelineColorBlendAttachmentState bat;
   4.500 +	VkPipelineColorBlendStateCreateInfo blend;
   4.501 +	VkPipelineLayoutCreateInfo lay;
   4.502 +	VkGraphicsPipelineCreateInfo pinf;
   4.503 +
   4.504 +	if(!(sdr[0] = load_shader("vertex.glsl")) || !(sdr[1] = load_shader("pixel.glsl"))) {
   4.505 +		return -1;
   4.506 +	}
   4.507 +	memset(ssinf, 0, sizeof ssinf);
   4.508 +	for(i=0; i<2; i++) {
   4.509 +		ssinf[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
   4.510 +		ssinf[i].stage = i == 0 ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
   4.511 +		ssinf[i].module = sdr[i];
   4.512 +		ssinf[i].pName = "main";
   4.513 +	}
   4.514 +
   4.515 +	memset(&vinp, 0, sizeof vinp);
   4.516 +	vinp.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
   4.517 +
   4.518 +	memset(&vasm, 0, sizeof vasm);
   4.519 +	vasm.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
   4.520 +	vasm.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
   4.521 +
   4.522 +	vport.x = vport.y = 0;
   4.523 +	vport.width = vksc_extent.width;
   4.524 +	vport.height = vksc_extent.height;
   4.525 +	vport.minDepth = 0.0f;
   4.526 +	vport.maxDepth = 1.0f;
   4.527 +
   4.528 +	scissor.offset.x = scissor.offset.y = 0;
   4.529 +	scissor.extent = vksc_extent;
   4.530 +
   4.531 +	memset(&vp, 0, sizeof vp);
   4.532 +	vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
   4.533 +	vp.viewportCount = 1;
   4.534 +	vp.pViewports = &vport;
   4.535 +	vp.scissorCount = 1;
   4.536 +	vp.pScissors = &scissor;
   4.537 +
   4.538 +	memset(&rast, 0, sizeof rast);
   4.539 +	rast.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
   4.540 +	rast.polygonMode = VK_POLYGON_MODE_FILL;
   4.541 +	rast.lineWidth = 1.0f;
   4.542 +	rast.cullMode = VK_CULL_MODE_BACK_BIT;
   4.543 +	rast.frontFace = VK_FRONT_FACE_CLOCKWISE;
   4.544 +
   4.545 +	memset(&msaa, 0, sizeof msaa);
   4.546 +	msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
   4.547 +	msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
   4.548 +	msaa.minSampleShading = 1.0f;
   4.549 +
   4.550 +	memset(&bat, 0, sizeof bat);
   4.551 +	bat.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
   4.552 +		VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
   4.553 +
   4.554 +	memset(&blend, 0, sizeof blend);
   4.555 +	blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
   4.556 +	blend.attachmentCount = 1;
   4.557 +	blend.pAttachments = &bat;
   4.558 +
   4.559 +
   4.560 +	memset(&lay, 0, sizeof lay);
   4.561 +	lay.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
   4.562 +
   4.563 +	if(vkCreatePipelineLayout(vkdev, &lay, 0, &vkpipe_layout) != 0) {
   4.564 +		fprintf(stderr, "failed to create a pipeline layout\n");
   4.565 +		return -1;
   4.566 +	}
   4.567 +
   4.568 +	memset(&pinf, 0, sizeof pinf);
   4.569 +	pinf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
   4.570 +	pinf.stageCount = 2;
   4.571 +	pinf.pStages = ssinf;
   4.572 +	pinf.pVertexInputState = &vinp;
   4.573 +	pinf.pInputAssemblyState = &vasm;
   4.574 +	pinf.pViewportState = &vp;
   4.575 +	pinf.pRasterizationState = &rast;
   4.576 +	pinf.pMultisampleState = &msaa;
   4.577 +	pinf.pColorBlendState = &blend;
   4.578 +	pinf.layout = vkpipe_layout;
   4.579 +	pinf.renderPass = vkrpass;
   4.580 +	pinf.basePipelineIndex = -1;
   4.581 +
   4.582 +	if(vkCreateGraphicsPipelines(vkdev, 0, 1, &pinf, 0, &vkpipe) != 0) {
   4.583 +		fprintf(stderr, "failed to create graphics pipeline\n");
   4.584 +		return -1;
   4.585 +	}
   4.586 +
   4.587 +	for(i=0; i<2; i++) {
   4.588 +		vkDestroyShaderModule(vkdev, sdr[i], 0);
   4.589 +	}
   4.590 +	return 0;
   4.591 +}
   4.592 +
   4.593 +int create_framebuf(void)
   4.594 +{
   4.595 +	int i;
   4.596 +	VkFramebufferCreateInfo fbinf;
   4.597 +
   4.598 +	if(!(vksc_fb = malloc(vksc_numimg * sizeof *vksc_fb))) {
   4.599 +		fprintf(stderr, "failed to allocate array for swap chain framebuffers\n");
   4.600 +		return -1;
   4.601 +	}
   4.602 +
   4.603 +	for(i=0; i<vksc_numimg; i++) {
   4.604 +		memset(&fbinf, 0, sizeof fbinf);
   4.605 +		fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
   4.606 +		fbinf.renderPass = vkrpass;
   4.607 +		fbinf.attachmentCount = 1;
   4.608 +		fbinf.pAttachments = vksc_view + i;
   4.609 +		fbinf.width = vksc_extent.width;
   4.610 +		fbinf.height = vksc_extent.height;
   4.611 +		fbinf.layers = 1;
   4.612 +
   4.613 +		if(vkCreateFramebuffer(vkdev, &fbinf, 0, vksc_fb + i) != 0) {
   4.614 +			fprintf(stderr, "failed to create framebuffer\n");
   4.615 +			return -1;
   4.616 +		}
   4.617 +	}
   4.618 +
   4.619 +	return 0;
   4.620 +}
   4.621 +
   4.622 +int create_cmdpool(void)
   4.623 +{
   4.624 +	VkCommandPoolCreateInfo cpinf;
   4.625 +
   4.626 +	memset(&cpinf, 0, sizeof cpinf);
   4.627 +	cpinf.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
   4.628 +	cpinf.queueFamilyIndex = vkqfam_idx;
   4.629 +
   4.630 +	if(vkCreateCommandPool(vkdev, &cpinf, 0, &vkcmdpool) != 0) {
   4.631 +		fprintf(stderr, "failed to create command pool\n");
   4.632 +		return -1;
   4.633 +	}
   4.634 +	return 0;
   4.635 +}
   4.636 +
   4.637 +int create_cmdbuf(void)
   4.638 +{
   4.639 +	int i;
   4.640 +	VkCommandBufferAllocateInfo cbinf;
   4.641 +
   4.642 +	if(!(vksc_cmdbuf = malloc(vksc_numimg * sizeof *vksc_cmdbuf))) {
   4.643 +		fprintf(stderr, "failed to allocate array of command buffers\n");
   4.644 +		return -1;
   4.645 +	}
   4.646 +
   4.647 +	memset(&cbinf, 0, sizeof cbinf);
   4.648 +	cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
   4.649 +	cbinf.commandPool = vkcmdpool;
   4.650 +	cbinf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
   4.651 +	cbinf.commandBufferCount = vksc_numimg;
   4.652 +
   4.653 +	if(vkAllocateCommandBuffers(vkdev, &cbinf, vksc_cmdbuf) != 0) {
   4.654 +		fprintf(stderr, "failed to allocate command buffers\n");
   4.655 +		return -1;
   4.656 +	}
   4.657 +
   4.658 +	/* pre-record command buffers, because why the fuck not */
   4.659 +	for(i=0; i<vksc_numimg; i++) {
   4.660 +		VkCommandBufferBeginInfo cbegin;
   4.661 +		VkRenderPassBeginInfo rbegin;
   4.662 +		VkClearValue clear;
   4.663 +
   4.664 +		memset(&cbegin, 0, sizeof cbegin);
   4.665 +		cbegin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
   4.666 +		cbegin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
   4.667 +
   4.668 +		if(vkBeginCommandBuffer(vksc_cmdbuf[i], &cbegin) != 0) {
   4.669 +			fprintf(stderr, "failed to begin command buffer recording\n");
   4.670 +			return -1;
   4.671 +		}
   4.672 +
   4.673 +		clear.color.float32[0] = 0.2f;
   4.674 +		clear.color.float32[1] = 0.2f;
   4.675 +		clear.color.float32[2] = 0.2f;
   4.676 +		clear.color.float32[3] = 1.0f;
   4.677 +
   4.678 +		memset(&rbegin, 0, sizeof rbegin);
   4.679 +		rbegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
   4.680 +		rbegin.renderPass = vkrpass;
   4.681 +		rbegin.framebuffer = vksc_fb[i];
   4.682 +		rbegin.renderArea.extent = vksc_extent;
   4.683 +		rbegin.clearValueCount = 1;
   4.684 +		rbegin.pClearValues = &clear;
   4.685 +
   4.686 +		vkCmdBeginRenderPass(vksc_cmdbuf[i], &rbegin, VK_SUBPASS_CONTENTS_INLINE);
   4.687 +		vkCmdBindPipeline(vksc_cmdbuf[i], VK_PIPELINE_BIND_POINT_GRAPHICS, vkpipe);
   4.688 +		vkCmdDraw(vksc_cmdbuf[i], 3, 1, 0, 0);
   4.689 +		vkCmdEndRenderPass(vksc_cmdbuf[i]);
   4.690 +
   4.691 +		if(vkEndCommandBuffer(vksc_cmdbuf[i]) != 0) {
   4.692 +			fprintf(stderr, "failed to record command buffer\n");
   4.693 +			return -1;
   4.694 +		}
   4.695 +	}
   4.696 +	return 0;
   4.697 +}
   4.698 +
   4.699 +int create_semaphores(void)
   4.700 +{
   4.701 +	VkSemaphoreCreateInfo sinf;
   4.702 +
   4.703 +	memset(&sinf, 0, sizeof sinf);
   4.704 +	sinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
   4.705 +
   4.706 +	if(vkCreateSemaphore(vkdev, &sinf, 0, &sem_gotimg) != 0) {
   4.707 +		fprintf(stderr, "failed to create semaphore\n");
   4.708 +		return -1;
   4.709 +	}
   4.710 +	if(vkCreateSemaphore(vkdev, &sinf, 0, &sem_drawdone) != 0) {
   4.711 +		fprintf(stderr, "failed to create semaphore\n");
   4.712 +		return -1;
   4.713 +	}
   4.714 +	return 0;
   4.715 +}
   4.716 +
   4.717 +VkShaderModule load_shader(const char *fname)
   4.718 +{
   4.719 +	FILE *fp;
   4.720 +	long sz;
   4.721 +	void *buf;
   4.722 +	VkShaderModuleCreateInfo sinf;
   4.723 +	VkShaderModule sdr;
   4.724 +
   4.725 +	if(!(fp = fopen(fname, "rb"))) {
   4.726 +		fprintf(stderr, "failed to open shader: %s: %s\n", fname, strerror(errno));
   4.727 +		return 0;
   4.728 +	}
   4.729 +	fseek(fp, 0, SEEK_END);
   4.730 +	sz = ftell(fp);
   4.731 +	fseek(fp, 0, SEEK_SET);
   4.732 +
   4.733 +	buf = alloca(sz);
   4.734 +	if(fread(buf, 1, sz, fp) < sz) {
   4.735 +		fprintf(stderr, "unexpected EOF while reading shader: %s\n", fname);
   4.736 +		fclose(fp);
   4.737 +		return 0;
   4.738 +	}
   4.739 +	fclose(fp);
   4.740 +
   4.741 +	memset(&sinf, 0, sizeof sinf);
   4.742 +	sinf.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
   4.743 +	sinf.codeSize = sz;
   4.744 +	sinf.pCode = buf;
   4.745 +
   4.746 +	if(vkCreateShaderModule(vkdev, &sinf, 0, &sdr) != 0) {
   4.747 +		fprintf(stderr, "failed to create shader from %s\n", fname);
   4.748 +		return 0;
   4.749 +	}
   4.750 +	return sdr;
   4.751 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/vertex.glsl	Thu Jun 28 13:57:28 2018 +0300
     5.3 @@ -0,0 +1,26 @@
     5.4 +#version 450
     5.5 +#extension GL_ARB_separate_shader_objects : enable
     5.6 +
     5.7 +out gl_PerVertex {
     5.8 +	vec4 gl_Position;
     5.9 +};
    5.10 +
    5.11 +layout(location = 0) out vec3 color;
    5.12 +
    5.13 +vec2 vpos[3] = vec2[](
    5.14 +	vec2(0.0, -0.5),
    5.15 +	vec2(0.5, 0.5),
    5.16 +	vec2(-0.5, 0.5)
    5.17 +);
    5.18 +
    5.19 +vec3 vcol[3] = vec3[](
    5.20 +	vec3(1.0, 0.0, 0.0),
    5.21 +	vec3(0.0, 1.0, 0.0),
    5.22 +	vec3(0.0, 0.0, 1.0)
    5.23 +);
    5.24 +
    5.25 +void main()
    5.26 +{
    5.27 +	gl_Position = vec4(vpos[gl_VertexIndex], 0.0, 1.0);
    5.28 +	color = vcol[gl_VertexIndex];
    5.29 +}