vulkan_test_simple

view src/main.c @ 1:d5a3f6912f4d

how the hell did this work?
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 12 Sep 2024 04:19:14 +0300
parents 8de4fe926882
children
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include <errno.h>
6 #include <alloca.h>
7 #include <GLFW/glfw3.h>
9 void keyb(GLFWwindow *win, int key, int sc, int act, int mods);
10 int init(void);
11 void destroy(void);
12 void draw(void);
14 GLFWwindow *win;
15 int win_width = 800;
16 int win_height = 600;
17 int redraw_pending;
19 int main(void)
20 {
21 if(!glfwInit()) {
22 fprintf(stderr, "glfw init failed\n");
23 return 1;
24 }
26 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
27 win = glfwCreateWindow(win_width, win_height, "test", 0, 0);
28 glfwSetKeyCallback(win, keyb);
30 if(init() == -1) {
31 glfwDestroyWindow(win);
32 glfwTerminate();
33 return 1;
34 }
36 redraw_pending = 1;
38 while(!glfwWindowShouldClose(win)) {
39 glfwWaitEvents();
41 if(redraw_pending) {
42 redraw_pending = 0;
43 draw();
44 }
45 }
47 destroy();
48 glfwDestroyWindow(win);
49 glfwTerminate();
50 return 0;
51 }
53 void keyb(GLFWwindow *win, int key, int sc, int act, int mods)
54 {
55 if(act == GLFW_PRESS) {
56 switch(key) {
57 case GLFW_KEY_ESCAPE:
58 glfwSetWindowShouldClose(win, 1);
59 break;
60 }
61 }
62 }
64 /* -------------------------------------------------------------- */
65 int create_instance(void);
66 int create_surface(void);
67 int choose_phys_dev(void);
68 int create_device(void);
69 int create_swapchain(void);
70 int create_imgviews(void);
71 int create_rendpass(void);
72 int create_pipeline(void);
73 int create_framebuf(void);
74 int create_cmdpool(void);
75 int create_cmdbuf(void);
76 int create_semaphores(void);
77 VkShaderModule load_shader(const char *fname);
79 VkInstance vk;
80 VkPhysicalDevice vkpdev;
81 int vkqfam_idx = -1;
82 VkDevice vkdev;
83 VkQueue vkq;
84 VkSurfaceKHR vksurf;
85 VkSurfaceCapabilitiesKHR vksurf_caps;
86 int vksurf_numfmt, vksurf_selfmt;
87 VkSurfaceFormatKHR *vksurf_fmt;
88 VkSwapchainKHR vksc;
89 int vksc_numimg;
90 VkImage *vksc_img;
91 VkExtent2D vksc_extent;
92 VkImageView *vksc_view;
93 VkRenderPass vkrpass;
94 VkPipelineLayout vkpipe_layout;
95 VkPipeline vkpipe;
96 VkFramebuffer *vksc_fb;
97 VkCommandPool vkcmdpool;
98 VkCommandBuffer *vksc_cmdbuf;
99 VkSemaphore sem_gotimg, sem_drawdone;
101 int init(void)
102 {
103 if(create_instance() == -1) return -1;
104 if(create_surface() == -1) return -1;
105 if(choose_phys_dev() == -1) return -1;
106 if(create_device() == -1) return -1;
107 if(create_swapchain() == -1) return -1;
108 if(create_imgviews() == -1) return -1;
109 if(create_rendpass() == -1) return -1;
110 if(create_pipeline() == -1) return -1;
111 if(create_framebuf() == -1) return -1;
112 if(create_cmdpool() == -1) return -1;
113 if(create_cmdbuf() == -1) return -1;
114 if(create_semaphores() == -1) return -1;
115 return 0;
116 }
118 void destroy(void)
119 {
120 int i;
122 if(sem_gotimg) vkDestroySemaphore(vkdev, sem_gotimg, 0);
123 if(sem_drawdone) vkDestroySemaphore(vkdev, sem_drawdone, 0);
124 if(vkcmdpool) vkDestroyCommandPool(vkdev, vkcmdpool, 0);
125 if(vksc_fb) {
126 for(i=0; i<vksc_numimg; i++) {
127 vkDestroyFramebuffer(vkdev, vksc_fb[i], 0);
128 }
129 }
130 if(vkpipe) vkDestroyPipeline(vkdev, vkpipe, 0);
131 if(vkpipe_layout) vkDestroyPipelineLayout(vkdev, vkpipe_layout, 0);
132 if(vkrpass) vkDestroyRenderPass(vkdev, vkrpass, 0);
133 if(vksc_view) {
134 for(i=0; i<vksc_numimg; i++) {
135 vkDestroyImageView(vkdev, vksc_view[i], 0);
136 }
137 }
138 if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
139 if(vkdev) vkDestroyDevice(vkdev, 0);
140 if(vksurf) vkDestroySurfaceKHR(vk, vksurf, 0);
141 if(vk) vkDestroyInstance(vk, 0);
142 }
144 void draw(void)
145 {
146 uint32_t img_idx;
147 VkSubmitInfo submit;
148 VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
149 VkPresentInfoKHR pres;
151 vkAcquireNextImageKHR(vkdev, vksc, UINT64_MAX, sem_gotimg, 0, &img_idx);
153 memset(&submit, 0, sizeof submit);
154 submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
155 submit.waitSemaphoreCount = 1;
156 submit.pWaitSemaphores = &sem_gotimg;
157 submit.pWaitDstStageMask = &wait_stages;
158 submit.commandBufferCount = 1;
159 submit.pCommandBuffers = vksc_cmdbuf + img_idx;
160 submit.signalSemaphoreCount = 1;
161 submit.pSignalSemaphores = &sem_drawdone;
163 if(vkQueueSubmit(vkq, 1, &submit, 0) != 0) {
164 fprintf(stderr, "failed to submit draw commands\n");
165 abort();
166 }
168 memset(&pres, 0, sizeof pres);
169 pres.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
170 pres.waitSemaphoreCount = 1;
171 pres.pWaitSemaphores = &sem_drawdone;
172 pres.swapchainCount = 1;
173 pres.pSwapchains = &vksc;
174 pres.pImageIndices = &img_idx;
176 vkQueuePresentKHR(vkq, &pres);
177 }
179 int create_instance(void)
180 {
181 VkApplicationInfo appinf;
182 VkInstanceCreateInfo iinf;
183 uint32_t num_ext;
184 const char **ext;
186 ext = glfwGetRequiredInstanceExtensions(&num_ext);
188 memset(&appinf, 0, sizeof appinf);
189 appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
190 appinf.pApplicationName = "test";
191 appinf.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
192 appinf.pEngineName = "fuckoff";
193 appinf.engineVersion = VK_MAKE_VERSION(1, 0, 0);
194 appinf.apiVersion = VK_API_VERSION_1_0;
196 memset(&iinf, 0, sizeof iinf);
197 iinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
198 iinf.pApplicationInfo = &appinf;
199 iinf.enabledExtensionCount = num_ext;
200 iinf.ppEnabledExtensionNames = ext;
202 if(vkCreateInstance(&iinf, 0, &vk) != 0) {
203 fprintf(stderr, "failed to create instance\n");
204 return -1;
205 }
206 return 0;
207 }
209 int create_surface(void)
210 {
211 if(glfwCreateWindowSurface(vk, win, 0, &vksurf) != 0) {
212 fprintf(stderr, "failed to create window surface\n");
213 return -1;
214 }
215 return 0;
216 }
218 static int is_pdev_skookum(VkPhysicalDevice dev)
219 {
220 uint32_t i, num_fmt, num_qfam, num_ext;
221 VkQueueFamilyProperties *qfam;
222 VkExtensionProperties *ext;
223 VkPhysicalDeviceProperties prop;
224 VkPhysicalDeviceFeatures feat;
225 VkBool32 can_pres;
226 int have_swap_ext;
228 vkGetPhysicalDeviceProperties(dev, &prop);
229 vkGetPhysicalDeviceFeatures(dev, &feat);
231 /* check if we have the swapchain extension */
232 vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, 0);
233 ext = alloca(num_ext * sizeof *ext);
234 vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, ext);
236 have_swap_ext = 0;
237 for(i=0; i<num_ext; i++) {
238 if(strcmp(ext[i].extensionName, "VK_KHR_swapchain") == 0) {
239 have_swap_ext = 1;
240 break;
241 }
242 }
243 if(!have_swap_ext) {
244 return 0;
245 }
247 /* populate format and present modes arrays, and make sure we have some of each */
248 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
249 if(!num_fmt || !(vksurf_fmt = malloc(num_fmt * sizeof *vksurf_fmt))) {
250 return 0;
251 }
252 vksurf_numfmt = num_fmt;
253 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, vksurf_fmt);
255 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
257 /* find a queue family which can do graphics and can present */
258 vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
259 qfam = alloca(num_qfam * sizeof *qfam);
260 vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
262 vkqfam_idx = -1;
263 for(i=0; i<num_qfam; i++) {
264 vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, vksurf, &can_pres);
265 if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
266 vkqfam_idx = i;
267 return 1;
268 }
269 }
271 free(vksurf_fmt);
272 vksurf_fmt = 0;
273 vksurf_numfmt = 0;
274 return 0;
275 }
277 static int choose_pixfmt(void)
278 {
279 int i, j;
280 static const VkFormat pref[] = {
281 VK_FORMAT_B8G8R8_UNORM,
282 VK_FORMAT_R8G8B8_UNORM,
283 VK_FORMAT_B8G8R8A8_UNORM,
284 VK_FORMAT_R8G8B8A8_UNORM
285 };
287 vksurf_selfmt = 0;
288 for(i=0; i<vksurf_numfmt; i++) {
289 if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
290 continue;
291 }
292 for(j=0; j<sizeof pref / sizeof *pref; j++) {
293 if(vksurf_fmt[i].format == pref[j]) {
294 vksurf_selfmt = i;
295 return i;
296 }
297 }
298 }
299 return -1;
300 }
302 int choose_phys_dev(void)
303 {
304 uint32_t i, num_pdev;
305 VkPhysicalDevice *pdev;
307 vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
308 if(!num_pdev) {
309 fprintf(stderr, "no vulkan devices found\n");
310 return -1;
311 }
312 pdev = alloca(num_pdev * sizeof *pdev);
313 vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
315 for(i=0; i<num_pdev; i++) {
316 if(is_pdev_skookum(pdev[i])) {
317 vkpdev = pdev[i];
318 break;
319 }
320 }
321 if(!vkpdev) {
322 fprintf(stderr, "no skookum device found, vulkan can't chooch\n");
323 return -1;
324 }
326 choose_pixfmt();
327 return 0;
328 }
330 int create_device(void)
331 {
332 static const float prio = 1.0f;
333 VkDeviceQueueCreateInfo qinf;
334 VkPhysicalDeviceFeatures feat;
335 VkDeviceCreateInfo devinf;
337 static const char *extensions[] = {
338 "VK_KHR_swapchain"
339 };
341 memset(&feat, 0, sizeof feat);
343 memset(&qinf, 0, sizeof qinf);
344 qinf.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
345 qinf.queueFamilyIndex = vkqfam_idx;
346 qinf.queueCount = 1;
347 qinf.pQueuePriorities = &prio;
349 memset(&devinf, 0, sizeof devinf);
350 devinf.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
351 devinf.pQueueCreateInfos = &qinf;
352 devinf.queueCreateInfoCount = 1;
353 devinf.pEnabledFeatures = &feat;
354 devinf.enabledExtensionCount = sizeof extensions / sizeof *extensions;
355 devinf.ppEnabledExtensionNames = extensions;
357 if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
358 fprintf(stderr, "failed to create vulkan device\n");
359 return -1;
360 }
362 vkGetDeviceQueue(vkdev, vkqfam_idx, 0, &vkq);
363 return 0;
364 }
366 int create_swapchain(void)
367 {
368 uint32_t num;
369 VkSwapchainCreateInfoKHR scinf;
371 vksc_extent.width = win_width;
372 vksc_extent.height = win_height;
374 memset(&scinf, 0, sizeof scinf);
375 scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
376 scinf.surface = vksurf;
377 scinf.minImageCount = 2;
378 scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
379 scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
380 scinf.imageExtent = vksc_extent;
381 scinf.imageArrayLayers = 1;
382 scinf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
383 scinf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
384 scinf.preTransform = vksurf_caps.currentTransform;
385 scinf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
386 scinf.presentMode = VK_PRESENT_MODE_FIFO_KHR;
387 scinf.clipped = VK_TRUE;
389 if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
390 fprintf(stderr, "failed to create swapchain\n");
391 return -1;
392 }
394 vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
395 if(!num || !(vksc_img = malloc(num * sizeof *vksc_img))) {
396 fprintf(stderr, "failed to allocate swapchain image array (%d images)\n", vksc_numimg);
397 return -1;
398 }
399 vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
400 vksc_numimg = num;
402 return 0;
403 }
405 int create_imgviews(void)
406 {
407 int i;
408 VkImageViewCreateInfo ivinf;
410 if(!(vksc_view = malloc(vksc_numimg * sizeof *vksc_view))) {
411 fprintf(stderr, "failed to allocate image view array (%d images)\n", vksc_numimg);
412 return -1;
413 }
415 for(i=0; i<vksc_numimg; i++) {
416 memset(&ivinf, 0, sizeof ivinf);
417 ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
418 ivinf.image = vksc_img[i];
419 ivinf.format = vksurf_fmt[vksurf_selfmt].format;
420 ivinf.components.r = ivinf.components.g = ivinf.components.b =
421 ivinf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
422 ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
423 ivinf.subresourceRange.levelCount = 1;
424 ivinf.subresourceRange.layerCount = 1;
425 ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
427 if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
428 fprintf(stderr, "failed to create image view for image %d\n", i);
429 return -1;
430 }
431 }
432 return 0;
433 }
435 int create_rendpass(void)
436 {
437 VkAttachmentDescription cat;
438 VkAttachmentReference catref;
439 VkSubpassDescription subpass;
440 VkRenderPassCreateInfo pinf;
441 VkSubpassDependency dep;
443 memset(&cat, 0, sizeof cat);
444 cat.format = vksurf_fmt[vksurf_selfmt].format;
445 cat.samples = VK_SAMPLE_COUNT_1_BIT;
446 cat.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
447 cat.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
448 cat.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
449 cat.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
450 cat.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
451 cat.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
453 memset(&catref, 0, sizeof catref);
454 catref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
456 memset(&subpass, 0, sizeof subpass);
457 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
458 subpass.colorAttachmentCount = 1;
459 subpass.pColorAttachments = &catref;
461 memset(&dep, 0, sizeof dep);
462 dep.srcSubpass = VK_SUBPASS_EXTERNAL;
463 dep.dstSubpass = 0;
464 dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
465 dep.srcAccessMask = 0;
466 dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
467 dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
469 memset(&pinf, 0, sizeof pinf);
470 pinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
471 pinf.attachmentCount = 1;
472 pinf.pAttachments = &cat;
473 pinf.subpassCount = 1;
474 pinf.pSubpasses = &subpass;
475 pinf.dependencyCount = 1;
476 pinf.pDependencies = &dep;
478 if(vkCreateRenderPass(vkdev, &pinf, 0, &vkrpass) != 0) {
479 fprintf(stderr, "failed to create render pass\n");
480 return -1;
481 }
482 return 0;
483 }
485 int create_pipeline(void)
486 {
487 int i;
488 VkShaderModule sdr[2];
489 VkPipelineShaderStageCreateInfo ssinf[2];
490 VkPipelineVertexInputStateCreateInfo vinp;
491 VkPipelineInputAssemblyStateCreateInfo vasm;
492 VkViewport vport;
493 VkRect2D scissor;
494 VkPipelineViewportStateCreateInfo vp;
495 VkPipelineRasterizationStateCreateInfo rast;
496 VkPipelineMultisampleStateCreateInfo msaa;
497 VkPipelineColorBlendAttachmentState bat;
498 VkPipelineColorBlendStateCreateInfo blend;
499 VkPipelineLayoutCreateInfo lay;
500 VkGraphicsPipelineCreateInfo pinf;
502 if(!(sdr[0] = load_shader("vertex.spv")) || !(sdr[1] = load_shader("pixel.spv"))) {
503 return -1;
504 }
505 memset(ssinf, 0, sizeof ssinf);
506 for(i=0; i<2; i++) {
507 ssinf[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
508 ssinf[i].stage = i == 0 ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
509 ssinf[i].module = sdr[i];
510 ssinf[i].pName = "main";
511 }
513 memset(&vinp, 0, sizeof vinp);
514 vinp.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
516 memset(&vasm, 0, sizeof vasm);
517 vasm.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
518 vasm.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
520 vport.x = vport.y = 0;
521 vport.width = vksc_extent.width;
522 vport.height = vksc_extent.height;
523 vport.minDepth = 0.0f;
524 vport.maxDepth = 1.0f;
526 scissor.offset.x = scissor.offset.y = 0;
527 scissor.extent = vksc_extent;
529 memset(&vp, 0, sizeof vp);
530 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
531 vp.viewportCount = 1;
532 vp.pViewports = &vport;
533 vp.scissorCount = 1;
534 vp.pScissors = &scissor;
536 memset(&rast, 0, sizeof rast);
537 rast.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
538 rast.polygonMode = VK_POLYGON_MODE_FILL;
539 rast.lineWidth = 1.0f;
540 rast.cullMode = VK_CULL_MODE_BACK_BIT;
541 rast.frontFace = VK_FRONT_FACE_CLOCKWISE;
543 memset(&msaa, 0, sizeof msaa);
544 msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
545 msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
546 msaa.minSampleShading = 1.0f;
548 memset(&bat, 0, sizeof bat);
549 bat.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
550 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
552 memset(&blend, 0, sizeof blend);
553 blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
554 blend.attachmentCount = 1;
555 blend.pAttachments = &bat;
558 memset(&lay, 0, sizeof lay);
559 lay.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
561 if(vkCreatePipelineLayout(vkdev, &lay, 0, &vkpipe_layout) != 0) {
562 fprintf(stderr, "failed to create a pipeline layout\n");
563 return -1;
564 }
566 memset(&pinf, 0, sizeof pinf);
567 pinf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
568 pinf.stageCount = 2;
569 pinf.pStages = ssinf;
570 pinf.pVertexInputState = &vinp;
571 pinf.pInputAssemblyState = &vasm;
572 pinf.pViewportState = &vp;
573 pinf.pRasterizationState = &rast;
574 pinf.pMultisampleState = &msaa;
575 pinf.pColorBlendState = &blend;
576 pinf.layout = vkpipe_layout;
577 pinf.renderPass = vkrpass;
578 pinf.basePipelineIndex = -1;
580 if(vkCreateGraphicsPipelines(vkdev, 0, 1, &pinf, 0, &vkpipe) != 0) {
581 fprintf(stderr, "failed to create graphics pipeline\n");
582 return -1;
583 }
585 for(i=0; i<2; i++) {
586 vkDestroyShaderModule(vkdev, sdr[i], 0);
587 }
588 return 0;
589 }
591 int create_framebuf(void)
592 {
593 int i;
594 VkFramebufferCreateInfo fbinf;
596 if(!(vksc_fb = malloc(vksc_numimg * sizeof *vksc_fb))) {
597 fprintf(stderr, "failed to allocate array for swap chain framebuffers\n");
598 return -1;
599 }
601 for(i=0; i<vksc_numimg; i++) {
602 memset(&fbinf, 0, sizeof fbinf);
603 fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
604 fbinf.renderPass = vkrpass;
605 fbinf.attachmentCount = 1;
606 fbinf.pAttachments = vksc_view + i;
607 fbinf.width = vksc_extent.width;
608 fbinf.height = vksc_extent.height;
609 fbinf.layers = 1;
611 if(vkCreateFramebuffer(vkdev, &fbinf, 0, vksc_fb + i) != 0) {
612 fprintf(stderr, "failed to create framebuffer\n");
613 return -1;
614 }
615 }
617 return 0;
618 }
620 int create_cmdpool(void)
621 {
622 VkCommandPoolCreateInfo cpinf;
624 memset(&cpinf, 0, sizeof cpinf);
625 cpinf.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
626 cpinf.queueFamilyIndex = vkqfam_idx;
628 if(vkCreateCommandPool(vkdev, &cpinf, 0, &vkcmdpool) != 0) {
629 fprintf(stderr, "failed to create command pool\n");
630 return -1;
631 }
632 return 0;
633 }
635 int create_cmdbuf(void)
636 {
637 int i;
638 VkCommandBufferAllocateInfo cbinf;
640 if(!(vksc_cmdbuf = malloc(vksc_numimg * sizeof *vksc_cmdbuf))) {
641 fprintf(stderr, "failed to allocate array of command buffers\n");
642 return -1;
643 }
645 memset(&cbinf, 0, sizeof cbinf);
646 cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
647 cbinf.commandPool = vkcmdpool;
648 cbinf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
649 cbinf.commandBufferCount = vksc_numimg;
651 if(vkAllocateCommandBuffers(vkdev, &cbinf, vksc_cmdbuf) != 0) {
652 fprintf(stderr, "failed to allocate command buffers\n");
653 return -1;
654 }
656 /* pre-record command buffers, because why the fuck not */
657 for(i=0; i<vksc_numimg; i++) {
658 VkCommandBufferBeginInfo cbegin;
659 VkRenderPassBeginInfo rbegin;
660 VkClearValue clear;
662 memset(&cbegin, 0, sizeof cbegin);
663 cbegin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
664 cbegin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
666 if(vkBeginCommandBuffer(vksc_cmdbuf[i], &cbegin) != 0) {
667 fprintf(stderr, "failed to begin command buffer recording\n");
668 return -1;
669 }
671 clear.color.float32[0] = 0.2f;
672 clear.color.float32[1] = 0.2f;
673 clear.color.float32[2] = 0.2f;
674 clear.color.float32[3] = 1.0f;
676 memset(&rbegin, 0, sizeof rbegin);
677 rbegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
678 rbegin.renderPass = vkrpass;
679 rbegin.framebuffer = vksc_fb[i];
680 rbegin.renderArea.extent = vksc_extent;
681 rbegin.clearValueCount = 1;
682 rbegin.pClearValues = &clear;
684 vkCmdBeginRenderPass(vksc_cmdbuf[i], &rbegin, VK_SUBPASS_CONTENTS_INLINE);
685 vkCmdBindPipeline(vksc_cmdbuf[i], VK_PIPELINE_BIND_POINT_GRAPHICS, vkpipe);
686 vkCmdDraw(vksc_cmdbuf[i], 3, 1, 0, 0);
687 vkCmdEndRenderPass(vksc_cmdbuf[i]);
689 if(vkEndCommandBuffer(vksc_cmdbuf[i]) != 0) {
690 fprintf(stderr, "failed to record command buffer\n");
691 return -1;
692 }
693 }
694 return 0;
695 }
697 int create_semaphores(void)
698 {
699 VkSemaphoreCreateInfo sinf;
701 memset(&sinf, 0, sizeof sinf);
702 sinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
704 if(vkCreateSemaphore(vkdev, &sinf, 0, &sem_gotimg) != 0) {
705 fprintf(stderr, "failed to create semaphore\n");
706 return -1;
707 }
708 if(vkCreateSemaphore(vkdev, &sinf, 0, &sem_drawdone) != 0) {
709 fprintf(stderr, "failed to create semaphore\n");
710 return -1;
711 }
712 return 0;
713 }
715 VkShaderModule load_shader(const char *fname)
716 {
717 FILE *fp;
718 long sz;
719 void *buf;
720 VkShaderModuleCreateInfo sinf;
721 VkShaderModule sdr;
723 if(!(fp = fopen(fname, "rb"))) {
724 fprintf(stderr, "failed to open shader: %s: %s\n", fname, strerror(errno));
725 return 0;
726 }
727 fseek(fp, 0, SEEK_END);
728 sz = ftell(fp);
729 fseek(fp, 0, SEEK_SET);
731 buf = alloca(sz);
732 if(fread(buf, 1, sz, fp) < sz) {
733 fprintf(stderr, "unexpected EOF while reading shader: %s\n", fname);
734 fclose(fp);
735 return 0;
736 }
737 fclose(fp);
739 memset(&sinf, 0, sizeof sinf);
740 sinf.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
741 sinf.codeSize = sz;
742 sinf.pCode = buf;
744 if(vkCreateShaderModule(vkdev, &sinf, 0, &sdr) != 0) {
745 fprintf(stderr, "failed to create shader from %s\n", fname);
746 return 0;
747 }
748 return sdr;
749 }