foo
[vktest3] / src / vk.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <stdarg.h>
5 #include <errno.h>
6 #include <assert.h>
7 #include <vulkan/vulkan.h>
8 #include "vk.h"
9 #include "util.h"
10 #include "darray.h"
11
12 #ifdef __WIN32__
13 #include <vulkan/vulkan_win32.h>
14 #else
15 /*#include <vulkan/vulkan_xlib.h>*/
16 #include <X11/Xlib-xcb.h>
17 #include <vulkan/vulkan_xcb.h>
18 #endif
19
20 struct rpass {
21         int used;
22         int fmt;
23         int zfmt;
24         int num_colbuf;
25         int num_samples;
26         int clear;
27
28         int vkobj_valid;
29         VkRenderPass vkobj;
30 };
31
32 #define MAX_FB_IMGV     8
33 struct framebuf {
34         int used;
35         int width, height;
36
37         /* if rpasses[rpidx].vkobj != vkrpass, the framebuf is invalid */
38         int rpidx;
39         VkRenderPass vkrpass;
40
41         VkImageView imgv[MAX_FB_IMGV];
42         int num_imgv;
43
44         int vkobj_valid;
45         VkFramebuffer vkobj;
46 };
47
48 struct pipeline {
49         int used;
50         VkViewport vport;
51         VkRect2D scissor;
52         VkShaderModule sdr[VKSDR_MAX];
53         VkPrimitiveTopology prim;
54         VkPolygonMode polymode;
55         float line_width;
56         VkCullModeFlags cull;
57         VkFrontFace     frontface;
58         VkColorComponentFlags colorwr;
59         int zbuf, depthwr;
60         VkCompareOp zop;
61         int stencil, stencilwr;
62         VkStencilOp sfail, szfail, szpass;
63         VkCompareOp sop;
64         unsigned int sref, smask;
65         int blend;
66         VkBlendFactor srcblend, dstblend, srcblend_a, dstblend_a;
67
68         VkRenderPass rpass;
69
70         int vkobj_valid;
71         VkPipeline vkobj;
72         VkPipelineLayout vkobj_layout;  /* TODO probably best to split this */
73 };
74
75
76 static struct rpass *rpasses;
77 static struct framebuf *framebufs;
78 static struct pipeline *pipelines;
79
80
81 static int create_instance(void);
82 static int create_surface(void);
83 static int choose_phys_dev(void);
84 static int create_device(void);
85 static int create_swapchain(void);
86 static int create_default_cmdbuf(void);
87
88 static int choose_pixfmt(void);
89 static int eval_pdev_score(VkPhysicalDevice dev);
90 static int have_inst_layer(const char *name);
91 static int have_ext(VkExtensionProperties *ext, int next, const char *name);
92
93 static Display *dpy;
94 static Window win;
95 static int initflags;
96 #define MAX_INIT_QUEUE  32
97 static struct {
98         unsigned int flags;
99         int count;
100         int qfam;
101         VkCommandPool cmdpool;
102 } initq[MAX_INIT_QUEUE];
103 static int num_initq;
104
105 static VkInstance vk;
106 static VkPhysicalDevice vkpdev;
107 static VkQueueFamilyProperties *qfam;
108 static uint32_t num_qfam;
109 static VkDevice vkdev;
110 static VkSurfaceKHR vksurf;
111 static VkSurfaceCapabilitiesKHR vksurf_caps;
112 static int vksurf_numfmt, vksurf_selfmt;
113 static VkSurfaceFormatKHR *vksurf_fmt;
114 static VkSwapchainKHR vksc;
115 static int vksc_numimg;
116 static VkImage *vksc_img;
117 static VkExtent2D vksc_extent;
118 static VkImageView *vksc_view;
119 static VkCommandBuffer *vksc_cmdbuf;    /* default command buffers (vksc_numimg) */
120
121 static VkLayerProperties *inst_layers;
122 static VkExtensionProperties *inst_ext, *dev_ext;
123 static uint32_t inst_ext_count, dev_ext_count, inst_layers_count;
124
125 static VkPhysicalDevice *pdev_list;
126 static uint32_t num_pdev;
127
128 static int have_raytrace, have_debug_report;
129
130 void vk_init_xwin(Display *d, Window w)
131 {
132         dpy = d;
133         win = w;
134 }
135
136 void vk_init_queue(unsigned int qflags, int count)
137 {
138         int i;
139
140         for(i=0; i<num_initq; i++) {
141                 if(initq[i].flags == qflags) {
142                         initq[i].count += count;
143                         return;
144                 }
145         }
146
147         if(num_initq >= MAX_INIT_QUEUE) {
148                 fprintf(stderr, "vk_init_queue: too many queues\n");
149                 return;
150         }
151         initq[num_initq].flags = qflags;
152         initq[num_initq].count = count;
153         num_initq++;
154 }
155
156 int vk_init(unsigned int flags, unsigned int *usedflags)
157 {
158         if(!num_initq) {
159                 vk_init_queue(VKQ_GFX | VKQ_PRESENT, 1);
160         }
161
162         initflags = flags;
163         if(create_instance() == -1)     return -1;
164         if(create_surface() == -1) return -1;
165         if(choose_phys_dev() == -1) return -1;
166         if(create_device() == -1) return -1;
167
168         if(initflags != flags) {
169                 if(usedflags) {
170                         *usedflags = initflags;
171                 } else {
172                         vk_cleanup();
173                         return -1;
174                 }
175         }
176         return 0;
177 }
178
179 void vk_cleanup(void)
180 {
181         int i;
182
183         free(vksc_img);
184         vksc_img = 0;
185         free(vksc_view);
186         vksc_view = 0;
187         if(vksc_view) {
188                 for(i=0; i<vksc_numimg; i++) {
189                         vkDestroyImageView(vkdev, vksc_view[i], 0);
190                 }
191                 vksc_view = 0;
192         }
193         if(vksc) {
194                 vkDestroySwapchainKHR(vkdev, vksc, 0);
195                 vksc = 0;
196         }
197         if(vkdev) {
198                 vkDestroyDevice(vkdev, 0);
199                 vkdev = 0;
200         }
201         if(vksurf) {
202                 vkDestroySurfaceKHR(vk, vksurf, 0);
203                 vksurf = 0;
204         }
205         if(vk) {
206                 vkDestroyInstance(vk, 0);
207                 vk = 0;
208         }
209         free(inst_layers);
210         inst_layers = 0;
211         free(inst_ext);
212         inst_ext = 0;
213         free(dev_ext);
214         dev_ext = 0;
215         free(pdev_list);
216         pdev_list = 0;
217 }
218
219 int vk_reshape(int xsz, int ysz)
220 {
221         int i;
222
223         if(vksc && vksc_extent.width == xsz && vksc_extent.height == ysz) {
224                 return 0;
225         }
226
227         if(vksc_view) {
228                 for(i=0; i<vksc_numimg; i++) {
229                         vkDestroyImageView(vkdev, vksc_view[i], 0);
230                 }
231         }
232         if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
233
234         vksc_extent.width = xsz;
235         vksc_extent.height = ysz;
236
237         if(create_swapchain() == -1) return -1;
238
239         if(!vksc_cmdbuf) {
240                 if(create_default_cmdbuf() == -1) return -1;
241         }
242
243         /* TODO create depth/stencil buffers as needed (initflags) */
244         return 0;
245 }
246
247 int vk_next_image(VkSemaphore sem)
248 {
249         uint32_t idx;
250         if(vkAcquireNextImageKHR(vkdev, vksc, UINT64_MAX, sem, 0, &idx) != 0) {
251                 return -1;
252         }
253         return (int)idx;
254 }
255
256 int vk_submit(VkQueue q, VkCommandBuffer cmdbuf, VkSemaphore semwait, VkSemaphore semsig)
257 {
258         /* TODO: investigate if we need to expose the wait stage */
259         VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
260         VkSubmitInfo sinf = {0};
261         sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
262         sinf.waitSemaphoreCount = semwait ? 1 : 0;
263         sinf.pWaitSemaphores = &semwait;
264         sinf.pWaitDstStageMask = &wait_stage;
265         sinf.commandBufferCount = 1;
266         sinf.pCommandBuffers = &cmdbuf;
267         sinf.signalSemaphoreCount = semsig ? 1 : 0;
268         sinf.pSignalSemaphores = &semsig;
269
270         if(vkQueueSubmit(q, 1, &sinf, 0) != 0) {
271                 fprintf(stderr, "failed to submit command buffer\n");
272                 return -1;
273         }
274         return 0;
275 }
276
277 int vk_present(VkQueue q, int imgid, VkSemaphore semwait)
278 {
279         VkPresentInfoKHR pinf = {0};
280
281         pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
282         pinf.waitSemaphoreCount = semwait ? 1 : 0;
283         pinf.pWaitSemaphores = &semwait;
284         pinf.swapchainCount = 1;
285         pinf.pSwapchains = &vksc;
286         pinf.pImageIndices = (unsigned int*)&imgid;
287
288         if(vkQueuePresentKHR(q, &pinf) != 0) {
289                 fprintf(stderr, "present failed\n");
290                 return -1;
291         }
292         return 0;
293 }
294
295 int vk_find_qfamily(unsigned int flags)
296 {
297         int i, famidx = -1;
298         VkBool32 can_pres;
299
300         if(!qfam) return -1;    /* not initialized I guess... */
301
302         for(i=0; i<num_qfam; i++) {
303                 vkGetPhysicalDeviceSurfaceSupportKHR(vkpdev, i, vksurf, &can_pres);
304
305                 if((flags & VKQ_PRESENT) && !can_pres) {
306                         continue;
307                 }
308                 if((flags & VKQ_GFX) && !(qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) {
309                         continue;
310                 }
311                 if((flags & VKQ_COMPUTE) && !(qfam[i].queueFlags & VK_QUEUE_COMPUTE_BIT)) {
312                         continue;
313                 }
314
315                 return i;       /* found a suitabe queue family */
316         }
317
318         return -1;
319 }
320
321 VkQueue vk_getq_fam(int fam, int n)
322 {
323         VkQueue q;
324
325         if(fam < 0) return 0;
326         if(n < 0 || n >= qfam[fam].queueCount) {
327                 fprintf(stderr, "vk_getq_fam: invalid index %d, family %d has %d queues\n",
328                            n, fam, qfam[fam].queueCount);
329                 return 0;
330         }
331
332         vkGetDeviceQueue(vkdev, fam, n, &q);
333         return q;
334 }
335
336 VkQueue vk_getq(unsigned int flags, int n)
337 {
338         return vk_getq_fam(vk_find_qfamily(flags), n);
339 }
340
341 static VkCommandPool find_cmdpool(int qfam)
342 {
343         int i;
344         VkCommandPoolCreateInfo pinf;
345
346         for(i=0; i<num_initq; i++) {
347                 if(initq[i].qfam == qfam) {
348                         if(!initq[i].cmdpool) {
349                                 /* allocate command pool for this queue family */
350                                 memset(&pinf, 0, sizeof pinf);
351                                 pinf.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
352                                 pinf.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
353                                 pinf.queueFamilyIndex = qfam;
354
355                                 if(vkCreateCommandPool(vkdev, &pinf, 0, &initq[i].cmdpool) != 0) {
356                                         fprintf(stderr, "ck_create_cmdbuf: failed to create command buffer pool\n");
357                                         return 0;
358                                 }
359                         }
360                         return initq[i].cmdpool;
361                 }
362         }
363
364         fprintf(stderr, "vk_create_cmdbuf: failed to find command pool for queue family: %d\n", qfam);
365         return 0;
366 }
367
368 VkCommandBuffer vk_create_cmdbuf_fam(int qfam, int level)
369 {
370         VkCommandBufferAllocateInfo inf = {0};
371         VkCommandBuffer cmdbuf;
372         VkCommandPool cmdpool;
373
374         if(!(cmdpool = find_cmdpool(qfam))) {
375                 return 0;
376         }
377
378         inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
379         inf.commandPool = cmdpool;
380         inf.level = level;
381         inf.commandBufferCount = 1;
382
383         if(vkAllocateCommandBuffers(vkdev, &inf, &cmdbuf) != 0) {
384                 fprintf(stderr, "vk_create_cmdbuf: failed to allocate command buffer\n");
385                 return 0;
386         }
387         return cmdbuf;
388 }
389
390 VkCommandBuffer vk_create_cmdbuf(unsigned int qflags, int level)
391 {
392         int qfam;
393
394         if((qfam = vk_find_qfamily(qflags)) == -1) {
395                 fprintf(stderr, "vk_create_cmdbuf: failed to find matching queue family\n");
396                 return 0;
397         }
398         return vk_create_cmdbuf_fam(qfam, level);
399 }
400
401 VkCommandBuffer vk_get_cmdbuf(int imgid)
402 {
403         if(imgid < 0 || imgid >= vksc_numimg) {
404                 fprintf(stderr, "vk_get_cmdbuf: invalid id %d, swap chain has %d images\n",
405                                 imgid, vksc_numimg);
406                 return 0;
407         }
408         return vksc_cmdbuf[imgid];
409 }
410
411 int vk_create_rpass(void)
412 {
413         int i;
414         struct rpass rpass = {0}, *rp = &rpass;
415
416         if(!rpasses) {
417                 rpasses = darr_alloc(0, sizeof *rpasses);
418                 darr_push(rpasses, &rpass);     /* add dummy rpass */
419         }
420
421         for(i=1; i<darr_size(rpasses); i++) {
422                 if(!rpasses[i].used) {
423                         rp = rpasses + i;
424                 }
425         }
426
427         /* init renderpass defaults */
428         rp->used = 1;
429         rp->fmt = vksurf_fmt[vksurf_selfmt].format;
430         rp->zfmt = VK_FORMAT_D24_UNORM_S8_UINT;
431         rp->num_colbuf = 1;
432         rp->num_samples = 1;
433         rp->clear = 1;
434         rp->vkobj_valid = 0;
435         rp->vkobj = 0;
436
437         if(rp == &rpass) {
438                 darr_push(rpasses, rp);
439                 return darr_size(rpasses) - 1;
440         }
441         return rp - rpasses;
442 }
443
444 void vk_free_rpass(int rp)
445 {
446         if(!rpasses || rp < 1 || rp >= darr_size(rpasses)) {
447                 return;
448         }
449
450         if(rpasses[rp].used && rpasses[rp].vkobj) {
451                 vkDestroyRenderPass(vkdev, rpasses[rp].vkobj, 0);
452         }
453         rpasses[rp].used = 0;
454 }
455
456 void vk_rpass_colorbuf(int rp, int fmt, int n)
457 {
458         rpasses[rp].fmt = fmt;
459         rpasses[rp].num_colbuf = n;
460         rpasses[rp].vkobj_valid = 0;
461 }
462
463 void vk_rpass_msaa(int rp, int nsamp)
464 {
465         rpasses[rp].num_samples = nsamp;
466         rpasses[rp].vkobj_valid = 0;
467 }
468
469 void vk_rpass_clear(int rp, int clear)
470 {
471         rpasses[rp].clear = clear;
472         rpasses[rp].vkobj_valid = 0;
473 }
474
475 VkRenderPass vk_rpass(int rp)
476 {
477         int i, zidx;
478         struct rpass *r;
479         VkAttachmentDescription att[17];
480         VkAttachmentReference catref[16], zatref;
481         VkSubpassDescription subpass;
482         VkRenderPassCreateInfo pinf;
483
484         r = rpasses + rp;
485
486         if(!r->vkobj_valid) {
487                 if(r->vkobj) {
488                         vkDestroyRenderPass(vkdev, r->vkobj, 0);
489                         r->vkobj = 0;
490                 }
491
492                 zidx = r->num_colbuf;
493                 memset(att, 0, sizeof att);
494                 for(i=0; i<r->num_colbuf; i++) {
495                         att[i].format = r->fmt;
496                         att[i].samples = r->num_samples;
497                         att[i].loadOp = r->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
498                         att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
499                         att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
500                         att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
501                         att[i].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
502                         att[i].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
503                 }
504                 att[zidx].format = r->zfmt;
505                 att[zidx].samples = 1;
506                 att[zidx].loadOp = r->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
507                 att[zidx].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
508                 att[zidx].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
509                 att[zidx].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
510                 att[zidx].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
511                 att[zidx].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
512
513                 for(i=0; i<r->num_colbuf; i++) {
514                         catref[i].attachment = i;
515                         catref[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
516                 }
517                 zatref.attachment = zidx;
518                 zatref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
519
520                 memset(&subpass, 0, sizeof subpass);
521                 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
522                 subpass.colorAttachmentCount = r->num_colbuf;
523                 subpass.pColorAttachments = catref;
524                 subpass.pDepthStencilAttachment = &zatref;
525
526                 memset(&pinf, 0, sizeof pinf);
527                 pinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
528                 pinf.attachmentCount = r->num_colbuf + 1;
529                 pinf.pAttachments = att;
530                 pinf.subpassCount = 1;
531                 pinf.pSubpasses = &subpass;
532
533                 if(vkCreateRenderPass(vkdev, &pinf, 0, &r->vkobj) != 0) {
534                         fprintf(stderr, "failed to create render pass!\n");
535                         return 0;
536                 }
537                 r->vkobj_valid = 1;
538         }
539
540         return r->vkobj;
541 }
542
543
544 int vk_create_fb(void)
545 {
546         int i;
547         struct framebuf framebuf = {0}, *fb = &framebuf;
548
549         if(!framebufs) {
550                 framebufs = darr_alloc(0, sizeof *framebufs);
551                 darr_push(framebufs, &framebuf);        /* add dummy framebuffer */
552         }
553
554         for(i=1; i<darr_size(framebufs); i++) {
555                 if(!framebufs[i].used) {
556                         fb = framebufs + i;
557                 }
558         }
559
560         /* init framebuffer defaults */
561         memset(fb, 0, sizeof &fb);
562         fb->used = 1;
563
564         if(fb == &framebuf) {
565                 darr_push(framebufs, fb);
566                 return darr_size(framebufs) - 1;
567         }
568         return fb - framebufs;
569 }
570
571 void vk_free_fb(int fb)
572 {
573         if(!framebufs || fb < 1 || fb >= darr_size(framebufs)) {
574                 return;
575         }
576
577         if(framebufs[fb].used && framebufs[fb].vkobj) {
578                 vkDestroyFramebuffer(vkdev, framebufs[fb].vkobj, 0);
579         }
580         framebufs[fb].used = 0;
581 }
582
583 void vk_fb_size(int fb, int x, int  y)
584 {
585         framebufs[fb].width = x;
586         framebufs[fb].height = y;
587         framebufs[fb].vkobj_valid = 0;
588 }
589
590 void vk_fb_rpass(int fb, int rpass)
591 {
592         if(rpass < 0 || rpass >= darr_size(rpasses) || !rpasses[rpass].used) {
593                 fprintf(stderr, "vk_fb_rpass: %d is not a valid renderpass\n", rpass);
594                 return;
595         }
596
597         framebufs[fb].rpidx = rpass;
598         if(rpasses[rpass].vkobj_valid) {
599                 framebufs[fb].vkrpass = rpasses[rpass].vkobj;
600         } else {
601                 framebufs[fb].vkrpass = 0;
602         }
603         framebufs[fb].vkobj_valid = 0;
604 }
605
606 void vk_fb_images(int fb, int n, ...)
607 {
608         int i;
609         va_list ap;
610
611         if(n > MAX_FB_IMGV) {
612                 fprintf(stderr, "vk_fb_images: %d is too many images\n", n);
613                 n = MAX_FB_IMGV;
614         }
615
616         va_start(ap, n);
617         for(i=0; i<n; i++) {
618                 framebufs[fb].imgv[i] = va_arg(ap, VkImageView);
619         }
620         va_end(ap);
621         framebufs[fb].num_imgv = n;
622         framebufs[fb].vkobj_valid = 0;
623 }
624
625 VkFramebuffer vk_fb(int fb)
626 {
627         VkFramebufferCreateInfo fbinf;
628         VkRenderPass rpass;
629         struct framebuf *f;
630
631         f = framebufs + fb;
632
633         if(!(rpass = vk_rpass(f->rpidx))) {
634                 return 0;
635         }
636
637         if(rpass != f->vkrpass || !f->vkobj_valid) {
638                 f->vkrpass = rpass;
639                 if(f->vkobj) {
640                         vkDestroyFramebuffer(vkdev, f->vkobj, 0);
641                         f->vkobj = 0;
642                 }
643
644                 memset(&fbinf, 0, sizeof fbinf);
645                 fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
646                 fbinf.renderPass = rpass;
647                 fbinf.attachmentCount = f->num_imgv;
648                 fbinf.pAttachments = f->imgv;
649                 fbinf.width = f->width;
650                 fbinf.height = f->height;
651
652                 if(vkCreateFramebuffer(vkdev, &fbinf, 0, &f->vkobj) != 0) {
653                         fprintf(stderr, "vk_fb: failed to create framebuffer\n");
654                         return 0;
655                 }
656                 f->vkobj_valid = 1;
657         }
658         return f->vkobj;
659 }
660
661
662 int vk_create_pipeln(void)
663 {
664         int i;
665         struct pipeline pipeln = {0}, *pp = &pipeln;
666
667         if(!pipelines) {
668                 pipelines = darr_alloc(0, sizeof *pipelines);
669                 darr_push(pipelines, &pipeln);  /* add dummy pipeline */
670         }
671
672         for(i=1; i<darr_size(pipelines); i++) {
673                 if(!pipelines[i].used) {
674                         pp = pipelines + i;
675                 }
676         }
677
678         /* init pipeline defaults */
679         memset(pp, 0, sizeof *pp);
680         pp->used = 1;
681         pp->vport.width = pp->scissor.extent.width = 640;
682         pp->vport.height = pp->scissor.extent.height = 480;
683         pp->vport.minDepth = 0.0f;
684         pp->vport.maxDepth = 1.0f;
685         pp->prim = VKPRIM_TRIANGLES;
686         pp->polymode = VK_POLYGON_MODE_FILL;
687         pp->cull = VK_CULL_MODE_BACK_BIT;
688         pp->frontface = VK_FRONT_FACE_COUNTER_CLOCKWISE;
689         pp->line_width = 1.0f;
690         pp->colorwr = 0xf;      /* RGBA */
691         pp->zbuf = 1;
692         pp->zop = VK_COMPARE_OP_LESS;
693         pp->depthwr = 1;
694         pp->stencil = 0;
695         pp->stencilwr = 1;
696         pp->sop = VK_COMPARE_OP_ALWAYS;
697         pp->smask = 0xffffffff;
698         pp->blend = 0;
699         pp->srcblend = pp->srcblend_a = VK_BLEND_FACTOR_ONE;
700         pp->dstblend = pp->dstblend_a = VK_BLEND_FACTOR_ZERO;
701
702         if(pp == &pipeln) {
703                 darr_push(pipelines, pp);
704                 return darr_size(pipelines) - 1;
705         }
706         return pp - pipelines;
707 }
708
709 void vk_free_pipeln(int pp)
710 {
711         if(!pipelines || pp < 1 || pp >= darr_size(pipelines)) {
712                 return;
713         }
714
715         if(pipelines[pp].used && pipelines[pp].vkobj) {
716                 vkDestroyPipeline(vkdev, pipelines[pp].vkobj, 0);
717         }
718         pipelines[pp].used = 0;
719 }
720
721 void vk_pipeln_rpass(int pp, VkRenderPass rp)
722 {
723         struct pipeline *p = pipelines + pp;
724         p->rpass = rp;
725         p->vkobj_valid = 0;
726 }
727
728 void vk_pipeln_viewport(int pp, int x, int y, int width, int height)
729 {
730         struct pipeline *p = pipelines + pp;
731         p->vport.x = x;
732         p->vport.y = y;
733         p->vport.width = width;
734         p->vport.height = height;
735         p->vkobj_valid = 0;
736 }
737
738 void vk_pipeln_scissor(int pp, int x, int y, int width, int height)
739 {
740         struct pipeline *p = pipelines + pp;
741         p->scissor.offset.x = x;
742         p->scissor.offset.y = y;
743         p->scissor.extent.width = width;
744         p->scissor.extent.height = height;
745         p->vkobj_valid = 0;
746 }
747
748 void vk_pipeln_shader(int pp, int type, VkShaderModule sdr)
749 {
750         struct pipeline *p = pipelines + pp;
751         p->sdr[type] = sdr;
752         p->vkobj_valid = 0;
753 }
754
755 /* TODO: vertex input */
756 void vk_pipeln_prim(int pp, int prim)
757 {
758         struct pipeline *p = pipelines + pp;
759         p->prim = prim;
760         p->vkobj_valid = 0;
761 }
762
763 void vk_pipeln_polymode(int pp, int mode)
764 {
765         struct pipeline *p = pipelines + pp;
766         p->polymode = mode;
767         p->vkobj_valid = 0;
768 }
769
770 void vk_pipeln_cull(int pp, int cull)
771 {
772         struct pipeline *p = pipelines + pp;
773         p->cull = cull;
774         p->vkobj_valid = 0;
775 }
776
777 void vk_pipeln_frontface(int pp, int ff)
778 {
779         struct pipeline *p = pipelines + pp;
780         p->frontface = ff;
781         p->vkobj_valid = 0;
782 }
783
784 void vk_pipeln_linewidth(int pp, int w)
785 {
786         struct pipeline *p = pipelines + pp;
787         p->line_width = w;
788         p->vkobj_valid = 0;
789 }
790
791 void vk_pipeln_multisample(int pp, int nsamples)
792 {
793         /* TODO */
794 }
795
796 void vk_pipeln_colormask(int pp, int r, int g, int b, int a)
797 {
798         struct pipeline *p = pipelines + pp;
799         p->colorwr = 0;
800         if(r) p->colorwr |= VK_COLOR_COMPONENT_R_BIT;
801         if(g) p->colorwr |= VK_COLOR_COMPONENT_G_BIT;
802         if(b) p->colorwr |= VK_COLOR_COMPONENT_B_BIT;
803         if(a) p->colorwr |= VK_COLOR_COMPONENT_A_BIT;
804         p->vkobj_valid = 0;
805 }
806
807 void vk_pipeln_depthmask(int pp, int z)
808 {
809         struct pipeline *p = pipelines + pp;
810         p->depthwr = z;
811         p->vkobj_valid = 0;
812 }
813
814 void vk_pipeln_stencilmask(int pp, int s)
815 {
816         struct pipeline *p = pipelines + pp;
817         p->stencilwr = s;
818         p->vkobj_valid = 0;
819 }
820
821 void vk_pipeln_zbuffer(int pp, int enable)
822 {
823         struct pipeline *p = pipelines + pp;
824         p->zbuf = enable;
825         p->vkobj_valid = 0;
826 }
827
828 void vk_pipeln_zbuffer_op(int pp, int op)
829 {
830         struct pipeline *p = pipelines + pp;
831         p->zop = op;
832         p->vkobj_valid = 0;
833 }
834
835 void vk_pipeln_stencil(int pp, int enable)
836 {
837         struct pipeline *p = pipelines + pp;
838         p->stencil = enable;
839         p->vkobj_valid = 0;
840 }
841
842 void vk_pipeln_stencil_op(int pp, int sfail, int zfail, int zpass)
843 {
844         struct pipeline *p = pipelines + pp;
845         p->sfail = sfail;
846         p->szfail = zfail;
847         p->szpass = zpass;
848         p->vkobj_valid = 0;
849 }
850
851 void vk_pipeln_stencil_func(int pp, int op, unsigned int ref, unsigned int mask)
852 {
853         struct pipeline *p = pipelines + pp;
854         p->sop = op;
855         p->sref = ref;
856         p->smask = mask;
857         p->vkobj_valid = 0;
858 }
859
860 void vk_pipeln_blend(int pp, int enable)
861 {
862         struct pipeline *p = pipelines + pp;
863         p->blend = enable;
864         p->vkobj_valid = 0;
865 }
866
867 void vk_pipeln_blendfunc(int pp, int src, int dst)
868 {
869         struct pipeline *p = pipelines + pp;
870         p->srcblend = src;
871         p->dstblend = dst;
872         p->vkobj_valid = 0;
873 }
874
875 VkPipeline vk_pipeln(int pp)
876 {
877         int i, idx, num_sdr;
878         struct pipeline *p = pipelines + pp;
879         VkPipelineShaderStageCreateInfo ssinf[VKSDR_MAX];
880         VkPipelineVertexInputStateCreateInfo vinp;
881         VkPipelineInputAssemblyStateCreateInfo vasm;
882         VkPipelineViewportStateCreateInfo vp;
883         VkPipelineRasterizationStateCreateInfo rast;
884         VkPipelineMultisampleStateCreateInfo msaa;
885         VkPipelineDepthStencilStateCreateInfo zst;
886         VkPipelineColorBlendAttachmentState bat;
887         VkPipelineColorBlendStateCreateInfo blend;
888         VkPipelineLayoutCreateInfo lay;
889         VkGraphicsPipelineCreateInfo pinf;
890
891
892         if(p->vkobj_valid) {
893                 return p->vkobj;
894         }
895
896         if(p->vkobj) {
897                 vkDestroyPipeline(vkdev, p->vkobj, 0);
898                 p->vkobj = 0;
899         }
900
901         memset(ssinf, 0, sizeof ssinf);
902         idx = 0;
903         for(i=0; i<VKSDR_MAX; i++) {
904                 if(p->sdr[idx]) {
905                         ssinf[idx].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
906                         ssinf[idx].stage = VKSDR_STAGE(i);
907                         ssinf[idx].module = p->sdr[idx];
908                         ssinf[idx].pName = "main";
909                         idx++;
910                 }
911         }
912         num_sdr = idx;
913
914         memset(&vinp, 0, sizeof vinp);
915         vinp.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
916
917         memset(&vasm, 0, sizeof vasm);
918         vasm.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
919         vasm.topology = p->prim;
920
921         memset(&vp, 0, sizeof vp);
922         vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
923         vp.viewportCount = 1;
924         vp.pViewports = &p->vport;
925         vp.scissorCount = 1;
926         vp.pScissors = &p->scissor;
927
928         memset(&rast, 0, sizeof rast);
929         rast.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
930         rast.polygonMode = p->polymode;
931         rast.lineWidth = p->line_width;
932         rast.cullMode = p->cull;
933         rast.frontFace = p->frontface;
934
935         /* TODO */
936         memset(&msaa, 0, sizeof msaa);
937         msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
938         msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
939         msaa.minSampleShading = 1.0f;
940
941         memset(&zst, 0, sizeof zst);
942         zst.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
943         zst.depthTestEnable = p->zbuf;
944         zst.depthWriteEnable = p->depthwr;
945         zst.depthCompareOp = p->zop;
946         zst.stencilTestEnable = p->stencil;
947         zst.front.writeMask = p->stencilwr;
948         zst.front.failOp = p->sfail;
949         zst.front.passOp = p->szpass;
950         zst.front.depthFailOp = p->szfail;
951         zst.front.compareOp = p->sop;
952         zst.front.compareMask = p->smask;
953         zst.front.reference = p->sref;
954         zst.back = zst.front;
955
956         memset(&bat, 0, sizeof bat);
957         bat.colorWriteMask = p->colorwr;
958         bat.blendEnable = p->blend;
959         bat.srcColorBlendFactor = p->srcblend;
960         bat.dstColorBlendFactor = p->dstblend;
961         bat.colorBlendOp = VK_BLEND_OP_ADD;     /* TODO */
962         bat.srcAlphaBlendFactor = p->srcblend_a;
963         bat.dstAlphaBlendFactor = p->dstblend_a;
964
965         memset(&blend, 0, sizeof blend);
966         blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
967         blend.attachmentCount = 1;
968         blend.pAttachments = &bat;
969
970         /* TODO */
971         memset(&lay, 0, sizeof lay);
972         lay.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
973         if(vkCreatePipelineLayout(vkdev, &lay, 0, &p->vkobj_layout) != 0) {
974                 return 0;
975         }
976
977         memset(&pinf, 0, sizeof pinf);
978         pinf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
979         pinf.stageCount = num_sdr;
980         pinf.pStages = ssinf;
981         pinf.pVertexInputState = &vinp;
982         pinf.pInputAssemblyState = &vasm;
983         pinf.pViewportState = &vp;
984         pinf.pRasterizationState = &rast;
985         pinf.pDepthStencilState = &zst;
986         pinf.pMultisampleState = &msaa;
987         pinf.pColorBlendState = &blend;
988         pinf.layout = p->vkobj_layout;
989         pinf.renderPass = p->rpass;
990         pinf.basePipelineIndex = -1;
991
992         if(vkCreateGraphicsPipelines(vkdev, 0, 1, &pinf, 0, &p->vkobj) != 0) {
993                 return 0;
994         }
995         p->vkobj_valid = 1;
996         return p->vkobj;
997 }
998
999
1000 VkShaderModule vk_load_shader(const char *fname)
1001 {
1002         FILE *fp;
1003         long sz;
1004         void *buf;
1005         VkShaderModuleCreateInfo sinf;
1006         VkShaderModule sdr;
1007
1008         if(!(fp = fopen(fname, "rb"))) {
1009                 fprintf(stderr, "failed to open shader: %s: %s\n", fname, strerror(errno));
1010                 return 0;
1011         }
1012         fseek(fp, 0, SEEK_END);
1013         sz = ftell(fp);
1014         fseek(fp, 0, SEEK_SET);
1015
1016         buf = alloca(sz);
1017         if(fread(buf, 1, sz, fp) < sz) {
1018                 fprintf(stderr, "unexpected EOF while reading shader: %s\n", fname);
1019                 fclose(fp);
1020                 return 0;
1021         }
1022         fclose(fp);
1023
1024         memset(&sinf, 0, sizeof sinf);
1025         sinf.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1026         sinf.codeSize = sz;
1027         sinf.pCode = buf;
1028
1029         if(vkCreateShaderModule(vkdev, &sinf, 0, &sdr) != 0) {
1030                 fprintf(stderr, "failed to create shader from %s\n", fname);
1031                 return 0;
1032         }
1033         return sdr;
1034 }
1035
1036 void vk_free_shader(VkShaderModule sdr)
1037 {
1038         vkDestroyShaderModule(vkdev, sdr, 0);
1039 }
1040
1041 VkSemaphore vk_create_sem(void)
1042 {
1043         VkSemaphore sem;
1044         VkSemaphoreCreateInfo sinf = {0};
1045
1046         sinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1047         if(vkCreateSemaphore(vkdev, &sinf, 0, &sem) != 0) {
1048                 return 0;
1049         }
1050         return sem;
1051 }
1052
1053 void vk_free_sem(VkSemaphore sem)
1054 {
1055         vkDestroySemaphore(vkdev, sem, 0);
1056 }
1057
1058 #define ARRSZ(arr)      (sizeof arr / sizeof *arr)
1059 static const char *known_layer_list[] = {
1060         "VK_LAYER_GOOGLE_threading",
1061         "VK_LAYER_LUNARG_parameter_validation",
1062         "VK_LAYER_LUNARG_object_tracker",
1063         "VK_LAYER_LUNARG_image",
1064         "VK_LAYER_LUNARG_core_validation",
1065         "VK_LAYER_LUNARG_swapchain",
1066         "VK_LAYER_GOOGLE_unique_objects"
1067 };
1068
1069 static struct {
1070         const char *name;
1071         int required;
1072 } known_instext_list[] = {
1073         {"VK_KHR_surface", 1},
1074 #ifdef __WIN32__
1075         {"VK_KHR_win32_surface", 1},
1076 #else
1077         /*{"VK_KHR_xlib_surface", 1},*/
1078         {"VK_KHR_xcb_surface", 1},
1079 #endif
1080         {"VK_KHR_debug_report", 0}
1081 };
1082
1083 static struct {
1084         const char *name;
1085         int required;
1086 } known_devext_list[] = {
1087         {"VK_KHR_swapchain", 1},
1088         {"VK_KHR_acceleration_structure", 0},
1089         {"VK_KHR_ray_tracing_pipeline", 0}
1090 };
1091
1092 static int create_instance(void)
1093 {
1094         int i, nlayers = 0, next = 0;
1095         VkInstanceCreateInfo instinf;
1096         VkApplicationInfo appinf;
1097         const char *layers[ARRSZ(known_layer_list)];
1098         const char *ext[ARRSZ(known_instext_list)];
1099         uint32_t apiver;
1100
1101         vkEnumerateInstanceVersion(&apiver);
1102         printf("Vulkan API version: %d.%d.%d\n", (apiver >> 22) & 0x7f,
1103                         (apiver >> 12) & 0x3ff, apiver & 0xfff);
1104
1105         memset(&appinf, 0, sizeof appinf);
1106         appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
1107         appinf.pApplicationName = "vkray";
1108         appinf.pEngineName = "vkray";
1109         appinf.apiVersion = apiver;
1110
1111         vkEnumerateInstanceLayerProperties(&inst_layers_count, 0);
1112         inst_layers = malloc_nf(inst_layers_count * sizeof *inst_layers);
1113         vkEnumerateInstanceLayerProperties(&inst_layers_count, inst_layers);
1114
1115         vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, 0);
1116         inst_ext = malloc_nf(inst_ext_count * sizeof *inst_ext);
1117         vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, inst_ext);
1118
1119         printf("Layers:\n");
1120         for(i=0; i<inst_layers_count; i++) {
1121                 printf(" - %s: %s\n", inst_layers[i].layerName, inst_layers[i].description);
1122         }
1123         printf("Instance extensions:\n");
1124         for(i=0; i<inst_ext_count; i++) {
1125                 printf(" - %s\n", inst_ext[i].extensionName);
1126         }
1127
1128         have_debug_report = have_ext(inst_ext, inst_ext_count, "VK_KHR_debug_report");
1129
1130         for(i=0; i<ARRSZ(known_layer_list); i++) {
1131                 if(have_inst_layer(known_layer_list[i])) {
1132                         layers[nlayers++] = known_layer_list[i];
1133                 }
1134         }
1135         for(i=0; i<ARRSZ(known_instext_list); i++) {
1136                 if(have_ext(inst_ext, inst_ext_count, known_instext_list[i].name)) {
1137                         ext[next++] = known_instext_list[i].name;
1138                 } else if(known_instext_list[i].required) {
1139                         fprintf(stderr, "Vulkan implementation lacks required instance extension: %s\n",
1140                                         known_instext_list[i].name);
1141                         return -1;
1142                 }
1143         }
1144
1145         memset(&instinf, 0, sizeof instinf);
1146         instinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
1147         instinf.pApplicationInfo = &appinf;
1148         instinf.enabledLayerCount = nlayers;
1149         instinf.ppEnabledLayerNames = layers;
1150         instinf.enabledExtensionCount = next;
1151         instinf.ppEnabledExtensionNames = ext;
1152         if(vkCreateInstance(&instinf, 0, &vk) != 0) {
1153                 fprintf(stderr, "failed to create vulkan instance\n");
1154                 return -1;
1155         }
1156
1157         return 0;
1158 }
1159
1160 static int create_surface(void)
1161 {
1162         /*
1163         VkXlibSurfaceCreateInfoKHR xinf = {0};
1164         xinf.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
1165         xinf.dpy = dpy;
1166         xinf.window = win;
1167
1168         if(vkCreateXlibSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
1169                 fprintf(stderr, "failed to create Xlib window surface\n");
1170                 return -1;
1171         }
1172         */
1173         VkXcbSurfaceCreateInfoKHR xinf = {0};
1174         xinf.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
1175         xinf.connection = XGetXCBConnection(dpy);
1176         xinf.window = (xcb_window_t)win;
1177
1178         if(vkCreateXcbSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
1179                 fprintf(stderr, "failed to create XCB window surface\n");
1180                 return -1;
1181         }
1182         return 0;
1183 }
1184
1185 int choose_phys_dev(void)
1186 {
1187         uint32_t i, num_pdev, score, best_score, best_dev;
1188         VkPhysicalDevice *pdev;
1189         VkPhysicalDeviceProperties pdevprop;
1190         VkBool32 can_pres;
1191
1192         vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
1193         if(!num_pdev) {
1194                 fprintf(stderr, "no vulkan devices found\n");
1195                 return -1;
1196         }
1197         pdev = malloc_nf(num_pdev * sizeof *pdev);
1198         vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
1199
1200         printf("Found %d physical devices\n", num_pdev);
1201
1202         best_score = 0;
1203         best_dev = -1;
1204         for(i=0; i<num_pdev; i++) {
1205                 if((score = eval_pdev_score(pdev[i])) && score > best_score) {
1206                         best_score = score;
1207                         best_dev = i;
1208                 }
1209
1210                 vkGetPhysicalDeviceProperties(pdev[i], &pdevprop);
1211                 printf(" %d: %s (score: %d)\n", i, pdevprop.deviceName, score);
1212         }
1213         if(best_dev == -1) {
1214                 fprintf(stderr, "no suitable vulkan device found\n");
1215                 free(pdev);
1216                 return -1;
1217         }
1218         vkpdev = pdev[best_dev];
1219
1220         if(qfam) free(qfam);
1221
1222         vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, 0);
1223         qfam = malloc_nf(num_qfam * sizeof *qfam);
1224         vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, qfam);
1225
1226         free(pdev);
1227         choose_pixfmt();
1228         return 0;
1229 }
1230
1231 static int create_device(void)
1232 {
1233         float *prio;
1234         VkDeviceQueueCreateInfo qinf[MAX_INIT_QUEUE] = {0};
1235         VkPhysicalDeviceFeatures feat = {0};
1236         VkDeviceCreateInfo devinf = {0};
1237         const char *ext[ARRSZ(known_devext_list) + 16];
1238         int i, j, num_ext, qfam, totalq;
1239
1240         vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, 0);
1241         dev_ext = malloc_nf(dev_ext_count * sizeof *dev_ext);
1242         vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, dev_ext);
1243
1244         num_ext = 0;
1245         for(i=0; i<ARRSZ(known_devext_list); i++) {
1246                 if(have_ext(dev_ext, dev_ext_count, known_devext_list[i].name)) {
1247                         ext[num_ext++] = known_devext_list[i].name;
1248                 } else if(known_devext_list[i].required) {
1249                         fprintf(stderr, "Vulkan device lacks required extension: %s\n",
1250                                         known_devext_list[i].name);
1251                         return -1;
1252                 }
1253         }
1254
1255         if(initflags & VKINIT_RAY) {
1256                 if(have_ext(dev_ext, dev_ext_count, "VK_KHR_acceleration_structure") &&
1257                                 have_ext(dev_ext, dev_ext_count, "VK_KHR_ray_tracing_pipeline")) {
1258                         ext[num_ext++] = "VK_KHR_acceleration_structure";
1259                         ext[num_ext++] = "VK_KHR_ray_tracing_pipeline";
1260                 } else {
1261                         initflags &= ~VKINIT_RAY;
1262                 }
1263         }
1264
1265         totalq = 0;
1266         for(i=0; i<num_initq; i++) {
1267                 totalq += initq[i].count;
1268         }
1269         if(totalq > 1024) {
1270                 fprintf(stderr, "create_device: arbitrary limit of total queues exceeded (%d)\n", totalq);
1271                 return -1;
1272         }
1273         prio = alloca(totalq * sizeof *prio);
1274
1275         for(i=0; i<num_initq; i++) {
1276                 if((qfam = vk_find_qfamily(initq[i].flags)) == -1) {
1277                         fprintf(stderr, "create_device: failed to find queue family (flags: 0x%2x)\n",
1278                                         initq[i].flags);
1279                         return -1;
1280                 }
1281                 initq[i].qfam = qfam;
1282                 initq[i].cmdpool = 0;
1283
1284                 qinf[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1285                 qinf[i].queueFamilyIndex = qfam;
1286                 qinf[i].queueCount = initq[i].count;
1287                 qinf[i].pQueuePriorities = prio;
1288                 for(j=0; j<initq[i].count; i++) {
1289                         *prio++ = 1.0f; /* all queue priorities 1 */
1290                 }
1291         }
1292
1293         devinf.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
1294         devinf.pQueueCreateInfos = qinf;
1295         devinf.queueCreateInfoCount = num_initq;
1296         devinf.pEnabledFeatures = &feat;
1297         devinf.enabledExtensionCount = num_ext;
1298         devinf.ppEnabledExtensionNames = ext;
1299
1300         if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
1301                 fprintf(stderr, "failed to create vulkan device\n");
1302                 return -1;
1303         }
1304         return 0;
1305 }
1306
1307 static int create_swapchain(void)
1308 {
1309         int i;
1310         uint32_t num;
1311         VkSwapchainCreateInfoKHR scinf = {0};
1312         VkImageViewCreateInfo ivinf;
1313
1314         if(vksc_extent.width <= 0 || vksc_extent.height <= 0) {
1315                 return -1;
1316         }
1317
1318         scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1319         scinf.surface = vksurf;
1320         scinf.minImageCount = 2;
1321         scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
1322         scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
1323         scinf.imageExtent = vksc_extent;
1324         scinf.imageArrayLayers = 1;
1325         scinf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1326         scinf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1327         scinf.preTransform = vksurf_caps.currentTransform;
1328         scinf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1329         scinf.presentMode = VK_PRESENT_MODE_FIFO_KHR;
1330         scinf.clipped = VK_TRUE;
1331
1332         if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
1333                 fprintf(stderr, "failed to create swapchain\n");
1334                 return -1;
1335         }
1336
1337         if(!vksc_img || vksc_numimg != num) {
1338                 free(vksc_img);
1339                 vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
1340                 vksc_img = malloc_nf(num * sizeof *vksc_img);
1341                 vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
1342         }
1343         if(!vksc_view || vksc_numimg != num) {
1344                 free(vksc_view);
1345                 vksc_view = malloc_nf(num * sizeof *vksc_view);
1346         }
1347         vksc_numimg = num;
1348
1349         for(i=0; i<num; i++) {
1350                 memset(&ivinf, 0, sizeof ivinf);
1351                 ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1352                 ivinf.image = vksc_img[i];
1353                 ivinf.format = vksurf_fmt[vksurf_selfmt].format;
1354                 ivinf.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
1355                 ivinf.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
1356                 ivinf.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
1357                 ivinf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
1358                 ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1359                 ivinf.subresourceRange.levelCount = 1;
1360                 ivinf.subresourceRange.layerCount = 1;
1361                 ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
1362
1363                 if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
1364                         fprintf(stderr, "failed to create image view (%d)\n", i);
1365                         return -1;
1366                 }
1367         }
1368         return 0;
1369 }
1370
1371 static int create_default_cmdbuf(void)
1372 {
1373         int i, qfam;
1374         VkCommandPool cmdpool;
1375         VkCommandBufferAllocateInfo cbinf = {0};
1376
1377         assert(!vksc_cmdbuf);
1378
1379         if((qfam = vk_find_qfamily(VKQ_GFX | VKQ_PRESENT)) == -1) {
1380                 fprintf(stderr, "failed to find a gfx|present capable queue family\n");
1381                 return -1;
1382         }
1383         if(!(cmdpool = find_cmdpool(qfam))) {
1384                 fprintf(stderr, "failed to find usable command pool for default command buffers\n");
1385                 return -1;
1386         }
1387         if(!(vksc_cmdbuf = malloc(vksc_numimg * sizeof *vksc_cmdbuf))) {
1388                 fprintf(stderr, "failed to allocate %d command buffers for the swap-chain\n", vksc_numimg);
1389                 return -1;
1390         }
1391
1392         cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1393         cbinf.commandPool = cmdpool;
1394         cbinf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1395         cbinf.commandBufferCount = vksc_numimg;
1396
1397         if(vkAllocateCommandBuffers(vkdev, &cbinf, vksc_cmdbuf) != 0) {
1398                 fprintf(stderr, "failed to create %d command buffers for the swap-chain\n", vksc_numimg);
1399                 return -1;
1400         }
1401         return 0;
1402 }
1403
1404 static int eval_pdev_score(VkPhysicalDevice dev)
1405 {
1406         int score = 0;
1407         uint32_t i, num_fmt, num_qfam, num_ext;
1408         VkQueueFamilyProperties *qfam;
1409         VkExtensionProperties *ext;
1410         VkPhysicalDeviceProperties prop;
1411         VkPhysicalDeviceFeatures feat;
1412         VkSurfaceFormatKHR *sfmt;
1413         VkBool32 can_pres;
1414
1415         vkGetPhysicalDeviceProperties(dev, &prop);
1416         vkGetPhysicalDeviceFeatures(dev, &feat);
1417
1418         /* check if we have the swapchain extension */
1419         vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, 0);
1420         ext = malloc_nf(num_ext * sizeof *ext);
1421         vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, ext);
1422
1423         if(!have_ext(ext, num_ext, "VK_KHR_swapchain")) {
1424                 free(ext);
1425                 return 0;
1426         }
1427
1428         /* populate format and present modes arrays, and make sure we have some of each */
1429         vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
1430         if(!num_fmt) {
1431                 free(ext);
1432                 return 0;
1433         }
1434         sfmt = malloc_nf(num_fmt * sizeof *sfmt);
1435         vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, sfmt);
1436
1437         vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
1438
1439         /* find a queue family which can do graphics and can present */
1440         vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
1441         qfam = malloc_nf(num_qfam * sizeof *qfam);
1442         vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
1443
1444         for(i=0; i<num_qfam; i++) {
1445                 vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, vksurf, &can_pres);
1446                 if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
1447                         score = 1;
1448                 }
1449         }
1450
1451         switch(prop.deviceType) {
1452         case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
1453                 score++;
1454                 break;
1455         case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
1456                 score += 2;
1457                 break;
1458         case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
1459                 score += 4;
1460                 break;
1461         default:
1462                 break;
1463         }
1464
1465         if(initflags & VKINIT_RAY) {
1466                 if(have_ext(ext, num_ext, "VK_KHR_acceleration_structure") &&
1467                                 have_ext(ext, num_ext, "VK_KHR_ray_tracing_pipeline")) {
1468                         score += 100;
1469                 }
1470         }
1471
1472         free(ext);
1473         free(sfmt);
1474         free(qfam);
1475         return score;
1476 }
1477
1478 static int choose_pixfmt(void)
1479 {
1480         static const VkFormat pref[] = {
1481                 VK_FORMAT_B8G8R8_UNORM,
1482                 VK_FORMAT_R8G8B8_UNORM,
1483                 VK_FORMAT_B8G8R8A8_UNORM,
1484                 VK_FORMAT_R8G8B8A8_UNORM
1485         };
1486         int i, j;
1487         uint32_t num_fmt;
1488
1489         vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, 0);
1490         if(!num_fmt) return -1;
1491         vksurf_fmt = malloc_nf(num_fmt * sizeof *vksurf_fmt);
1492         vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, vksurf_fmt);
1493
1494         vksurf_selfmt = 0;
1495         for(i=0; i<num_fmt; i++) {
1496                 if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
1497                         continue;
1498                 }
1499                 for(j=0; j<sizeof pref / sizeof *pref; j++) {
1500                         if(vksurf_fmt[i].format == pref[j]) {
1501                                 vksurf_selfmt = i;
1502                                 vksurf_numfmt = num_fmt;
1503                                 return i;
1504                         }
1505                 }
1506         }
1507         free(vksurf_fmt);
1508         vksurf_fmt = 0;
1509         return -1;
1510 }
1511
1512
1513 static int have_inst_layer(const char *name)
1514 {
1515         int i;
1516         for(i=0; i<inst_layers_count; i++) {
1517                 if(strcmp(inst_layers[i].layerName, name) == 0) {
1518                         return 1;
1519                 }
1520         }
1521         return 0;
1522 }
1523
1524 static int have_ext(VkExtensionProperties *ext, int next, const char *name)
1525 {
1526         int i;
1527         for(i=0; i<next; i++) {
1528                 if(strcmp(ext[i].extensionName, name) == 0) {
1529                         return 1;
1530                 }
1531         }
1532         return 0;
1533 }