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