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