a22b7a36932de643712a63aeeec09e5e6be87f52
[vktest3] / src / vk.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <stdarg.h>
5 #include <vulkan/vulkan.h>
6 #include "vk.h"
7 #include "util.h"
8 #include "darray.h"
9
10 #ifdef __WIN32__
11 #include <vulkan/vulkan_win32.h>
12 #else
13 /*#include <vulkan/vulkan_xlib.h>*/
14 #include <X11/Xlib-xcb.h>
15 #include <vulkan/vulkan_xcb.h>
16 #endif
17
18 struct rpass {
19         int used;
20         int fmt;
21         int zfmt;
22         int num_colbuf;
23         int num_samples;
24         int clear;
25
26         int vkobj_valid;
27         VkRenderPass vkobj;
28 };
29
30 #define MAX_FB_IMGV     8
31 struct framebuf {
32         int used;
33         int width, height;
34
35         /* if rpasses[rpidx].vkobj != vkrpass, the framebuf is invalid */
36         int rpidx;
37         VkRenderPass vkrpass;
38
39         VkImageView imgv[MAX_FB_IMGV];
40         int num_imgv;
41
42         int vkobj_valid;
43         VkFramebuffer vkobj;
44 };
45
46 struct pipeline {
47         int used;
48         int vport[4], scissor[4];
49         VkShaderModule sdr[VKSDR_MAX];
50         VkPrimitiveTopology prim;
51         VkPolygonMode polymode;
52         VkCullModeFlags cull;
53         VkFrontFace     frontface;
54         VkColorComponentFlags colorwr;
55         int zbuf, depthwr;
56         int stencil, stencilwr;
57         VkStencilOp sfail, szfail, szpass;
58         VkCompareOp sop;
59         unsigned int sref, smask;
60         int blend;
61         VkBlendFactor srcblend, dstblend, srcblend_a, dstblend_a;
62
63         int vkobj_valid;
64         VkPipeline vkobj;
65 };
66
67
68 static struct rpass *rpasses;
69 static struct framebuf *framebufs;
70 static struct pipeline *pipelines;
71
72
73 static int create_instance(void);
74 static int create_surface(void);
75 static int choose_phys_dev(void);
76 static int create_device(void);
77 static int create_swapchain(void);
78
79 static int choose_pixfmt(void);
80 static int eval_pdev_score(VkPhysicalDevice dev);
81 static int have_inst_layer(const char *name);
82 static int have_ext(VkExtensionProperties *ext, int next, const char *name);
83
84 static Display *dpy;
85 static Window win;
86 static int initflags;
87 #define MAX_INIT_QUEUE  32
88 static struct {
89         unsigned int flags;
90         int count;
91         int qfam;
92         VkCommandPool cmdpool;
93 } initq[MAX_INIT_QUEUE];
94 static int num_initq;
95
96 static VkInstance vk;
97 static VkPhysicalDevice vkpdev;
98 static VkQueueFamilyProperties *qfam;
99 static uint32_t num_qfam;
100 static VkDevice vkdev;
101 static VkSurfaceKHR vksurf;
102 static VkSurfaceCapabilitiesKHR vksurf_caps;
103 static int vksurf_numfmt, vksurf_selfmt;
104 static VkSurfaceFormatKHR *vksurf_fmt;
105 static VkSwapchainKHR vksc;
106 static int vksc_numimg;
107 static VkImage *vksc_img;
108 static VkExtent2D vksc_extent;
109 static VkImageView *vksc_view;
110
111 static VkLayerProperties *inst_layers;
112 static VkExtensionProperties *inst_ext, *dev_ext;
113 static uint32_t inst_ext_count, dev_ext_count, inst_layers_count;
114
115 static VkPhysicalDevice *pdev_list;
116 static uint32_t num_pdev;
117
118 static int have_raytrace, have_debug_report;
119
120 void vk_init_xwin(Display *d, Window w)
121 {
122         dpy = d;
123         win = w;
124 }
125
126 void vk_init_queue(unsigned int qflags, int count)
127 {
128         int i;
129
130         for(i=0; i<num_initq; i++) {
131                 if(initq[i].flags == qflags) {
132                         initq[i].count += count;
133                         return;
134                 }
135         }
136
137         if(num_initq >= MAX_INIT_QUEUE) {
138                 fprintf(stderr, "vk_init_queue: too many queues\n");
139                 return;
140         }
141         initq[num_initq].flags = qflags;
142         initq[num_initq].count = count;
143         num_initq++;
144 }
145
146 int vk_init(unsigned int flags, unsigned int *usedflags)
147 {
148         if(!num_initq) {
149                 vk_init_queue(VKQ_GFX | VKQ_PRESENT, 1);
150         }
151
152         initflags = flags;
153         if(create_instance() == -1)     return -1;
154         if(create_surface() == -1) return -1;
155         if(choose_phys_dev() == -1) return -1;
156         if(create_device() == -1) return -1;
157
158         if(initflags != flags) {
159                 if(usedflags) {
160                         *usedflags = initflags;
161                 } else {
162                         vk_cleanup();
163                         return -1;
164                 }
165         }
166         return 0;
167 }
168
169 void vk_cleanup(void)
170 {
171         int i;
172
173         free(vksc_img);
174         vksc_img = 0;
175         free(vksc_view);
176         vksc_view = 0;
177         if(vksc_view) {
178                 for(i=0; i<vksc_numimg; i++) {
179                         vkDestroyImageView(vkdev, vksc_view[i], 0);
180                 }
181                 vksc_view = 0;
182         }
183         if(vksc) {
184                 vkDestroySwapchainKHR(vkdev, vksc, 0);
185                 vksc = 0;
186         }
187         if(vkdev) {
188                 vkDestroyDevice(vkdev, 0);
189                 vkdev = 0;
190         }
191         if(vksurf) {
192                 vkDestroySurfaceKHR(vk, vksurf, 0);
193                 vksurf = 0;
194         }
195         if(vk) {
196                 vkDestroyInstance(vk, 0);
197                 vk = 0;
198         }
199         free(inst_layers);
200         inst_layers = 0;
201         free(inst_ext);
202         inst_ext = 0;
203         free(dev_ext);
204         dev_ext = 0;
205         free(pdev_list);
206         pdev_list = 0;
207 }
208
209 int vk_reshape(int xsz, int ysz)
210 {
211         int i;
212
213         if(vksc && vksc_extent.width == xsz && vksc_extent.height == ysz) {
214                 return 0;
215         }
216
217         if(vksc_view) {
218                 for(i=0; i<vksc_numimg; i++) {
219                         vkDestroyImageView(vkdev, vksc_view[i], 0);
220                 }
221         }
222         if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
223
224         vksc_extent.width = xsz;
225         vksc_extent.height = ysz;
226
227         if(create_swapchain() == -1) return -1;
228
229         /* TODO create depth/stencil buffers as needed (initflags) */
230         return 0;
231 }
232
233 int vk_find_qfamily(unsigned int flags)
234 {
235         int i, famidx = -1;
236         VkBool32 can_pres;
237
238         if(!qfam) return -1;    /* not initialized I guess... */
239
240         for(i=0; i<num_qfam; i++) {
241                 vkGetPhysicalDeviceSurfaceSupportKHR(vkpdev, i, vksurf, &can_pres);
242
243                 if((flags & VKQ_PRESENT) && !can_pres) {
244                         continue;
245                 }
246                 if((flags & VKQ_GFX) && !(qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) {
247                         continue;
248                 }
249                 if((flags & VKQ_COMPUTE) && !(qfam[i].queueFlags & VK_QUEUE_COMPUTE_BIT)) {
250                         continue;
251                 }
252
253                 return i;       /* found a suitabe queue family */
254         }
255
256         return -1;
257 }
258
259 VkQueue vk_getq_fam(int fam, int n)
260 {
261         VkQueue q;
262
263         if(fam < 0) return 0;
264         if(n < 0 || n >= qfam[fam].queueCount) {
265                 fprintf(stderr, "vk_getq_fam: invalid index %d, family %d has %d queues\n",
266                            n, fam, qfam[fam].queueCount);
267                 return 0;
268         }
269
270         vkGetDeviceQueue(vkdev, fam, n, &q);
271         return q;
272 }
273
274 VkQueue vk_getq(unsigned int flags, int n)
275 {
276         return vk_getq_fam(vk_find_qfamily(flags), n);
277 }
278
279 static VkCommandPool find_cmdpool(int qfam)
280 {
281         int i;
282         VkCommandPoolCreateInfo pinf;
283
284         for(i=0; i<num_initq; i++) {
285                 if(initq[i].qfam == qfam) {
286                         if(!initq[i].cmdpool) {
287                                 /* allocate command pool for this queue family */
288                                 memset(&pinf, 0, sizeof pinf);
289                                 pinf.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
290                                 pinf.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
291                                 pinf.queueFamilyIndex = qfam;
292
293                                 if(vkCreateCommandPool(vkdev, &pinf, 0, &initq[i].cmdpool) != 0) {
294                                         fprintf(stderr, "ck_create_cmdbuf: failed to create command buffer pool\n");
295                                         return 0;
296                                 }
297                         }
298                         return initq[i].cmdpool;
299                 }
300         }
301
302         fprintf(stderr, "vk_create_cmdbuf: failed to find command pool for queue family: %d\n", qfam);
303         return 0;
304 }
305
306 VkCommandBuffer vk_create_cmdbuf_fam(int qfam, int level)
307 {
308         VkCommandBufferAllocateInfo inf = {0};
309         VkCommandBuffer cmdbuf;
310         VkCommandPool cmdpool;
311
312         if(!(cmdpool = find_cmdpool(qfam))) {
313                 return 0;
314         }
315
316         inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
317         inf.commandPool = cmdpool;
318         inf.level = level;
319         inf.commandBufferCount = 1;
320
321         if(vkAllocateCommandBuffers(vkdev, &inf, &cmdbuf) != 0) {
322                 fprintf(stderr, "vk_create_cmdbuf: failed to allocate command buffer\n");
323                 return 0;
324         }
325         return cmdbuf;
326 }
327
328 VkCommandBuffer vk_create_cmdbuf(unsigned int qflags, int level)
329 {
330         int qfam;
331
332         if((qfam = vk_find_qfamily(qflags)) == -1) {
333                 fprintf(stderr, "vk_create_cmdbuf: failed to find matching queue family\n");
334                 return 0;
335         }
336         return vk_create_cmdbuf_fam(qfam, level);
337 }
338
339 int vk_create_rpass(void)
340 {
341         int i;
342         struct rpass rpass = {0}, *rp = &rpass;
343
344         if(!rpasses) {
345                 rpasses = darr_alloc(0, sizeof *rpasses);
346                 darr_push(rpasses, &rpass);     /* add dummy rpass */
347         }
348
349         for(i=1; i<darr_size(rpasses); i++) {
350                 if(!rpasses[i].used) {
351                         rp = rpasses + i;
352                 }
353         }
354
355         /* init renderpass defaults */
356         rp->used = 1;
357         rp->fmt = vksurf_fmt[vksurf_selfmt].format;
358         rp->zfmt = VK_FORMAT_D24_UNORM_S8_UINT;
359         rp->num_colbuf = 1;
360         rp->num_samples = 1;
361         rp->clear = 1;
362         rp->vkobj_valid = 0;
363         rp->vkobj = 0;
364
365         if(rp == &rpass) {
366                 darr_push(rpasses, rp);
367                 return darr_size(rpasses) - 1;
368         }
369         return rp - rpasses;
370 }
371
372 void vk_free_rpass(int rp)
373 {
374         if(!rpasses || rp < 1 || rp >= darr_size(rpasses)) {
375                 return;
376         }
377
378         if(rpasses[rp].used && rpasses[rp].vkobj) {
379                 vkDestroyRenderPass(vkdev, rpasses[rp].vkobj, 0);
380         }
381         rpasses[rp].used = 0;
382 }
383
384 void vk_rpass_colorbuf(int rp, int fmt, int n)
385 {
386         rpasses[rp].fmt = fmt;
387         rpasses[rp].num_colbuf = n;
388         rpasses[rp].vkobj_valid = 0;
389 }
390
391 void vk_rpass_msaa(int rp, int nsamp)
392 {
393         rpasses[rp].num_samples = nsamp;
394         rpasses[rp].vkobj_valid = 0;
395 }
396
397 void vk_rpass_clear(int rp, int clear)
398 {
399         rpasses[rp].clear = clear;
400         rpasses[rp].vkobj_valid = 0;
401 }
402
403 VkRenderPass vk_rpass(int rp)
404 {
405         int i, zidx;
406         struct rpass *r;
407         VkAttachmentDescription att[17];
408         VkAttachmentReference catref[16], zatref;
409         VkSubpassDescription subpass;
410         VkRenderPassCreateInfo pinf;
411
412         r = rpasses + rp;
413
414         if(!r->vkobj_valid) {
415                 if(r->vkobj) {
416                         vkDestroyRenderPass(vkdev, r->vkobj, 0);
417                         r->vkobj = 0;
418                 }
419
420                 zidx = r->num_colbuf;
421                 memset(att, 0, sizeof att);
422                 for(i=0; i<r->num_colbuf; i++) {
423                         att[i].format = r->fmt;
424                         att[i].samples = r->num_samples;
425                         att[i].loadOp = r->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
426                         att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
427                         att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
428                         att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
429                         att[i].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
430                         att[i].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
431                 }
432                 att[zidx].format = r->zfmt;
433                 att[zidx].samples = 1;
434                 att[zidx].loadOp = r->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
435                 att[zidx].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
436                 att[zidx].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
437                 att[zidx].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
438                 att[zidx].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
439                 att[zidx].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
440
441                 for(i=0; i<r->num_colbuf; i++) {
442                         catref[i].attachment = i;
443                         catref[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
444                 }
445                 zatref.attachment = zidx;
446                 zatref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
447
448                 memset(&subpass, 0, sizeof subpass);
449                 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
450                 subpass.colorAttachmentCount = r->num_colbuf;
451                 subpass.pColorAttachments = catref;
452                 subpass.pDepthStencilAttachment = &zatref;
453
454                 memset(&pinf, 0, sizeof pinf);
455                 pinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
456                 pinf.attachmentCount = r->num_colbuf + 1;
457                 pinf.pAttachments = att;
458                 pinf.subpassCount = 1;
459                 pinf.pSubpasses = &subpass;
460
461                 if(vkCreateRenderPass(vkdev, &pinf, 0, &r->vkobj) != 0) {
462                         fprintf(stderr, "failed to create render pass!\n");
463                         return 0;
464                 }
465                 r->vkobj_valid = 1;
466         }
467
468         return r->vkobj;
469 }
470
471
472 int vk_create_fb(void)
473 {
474         int i;
475         struct framebuf framebuf = {0}, *fb = &framebuf;
476
477         if(!framebufs) {
478                 framebufs = darr_alloc(0, sizeof *framebufs);
479                 darr_push(framebufs, &framebuf);        /* add dummy rpass */
480         }
481
482         for(i=1; i<darr_size(framebufs); i++) {
483                 if(!framebufs[i].used) {
484                         fb = framebufs + i;
485                 }
486         }
487
488         /* init framebuffer defaults */
489         memset(fb, 0, sizeof &fb);
490         fb->used = 1;
491
492         if(fb == &framebuf) {
493                 darr_push(framebufs, fb);
494                 return darr_size(framebufs) - 1;
495         }
496         return fb - framebufs;
497 }
498
499 void vk_free_fb(int fb)
500 {
501         if(!framebufs || fb < 1 || fb >= darr_size(framebufs)) {
502                 return;
503         }
504
505         if(framebufs[fb].used && framebufs[fb].vkobj) {
506                 vkDestroyFramebuffer(vkdev, framebufs[fb].vkobj, 0);
507         }
508         framebufs[fb].used = 0;
509 }
510
511 void vk_fb_size(int fb, int x, int  y)
512 {
513         framebufs[fb].width = x;
514         framebufs[fb].height = y;
515         framebufs[fb].vkobj_valid = 0;
516 }
517
518 void vk_fb_rpass(int fb, int rpass)
519 {
520         if(rpass < 0 || rpass >= darr_size(rpasses) || !rpasses[rpass].used) {
521                 fprintf(stderr, "vk_fb_rpass: %d is not a valid renderpass\n", rpass);
522                 return;
523         }
524
525         framebufs[fb].rpidx = rpass;
526         if(rpasses[rpass].vkobj_valid) {
527                 framebufs[fb].vkrpass = rpasses[rpass].vkobj;
528         } else {
529                 framebufs[fb].vkrpass = 0;
530         }
531         framebufs[fb].vkobj_valid = 0;
532 }
533
534 void vk_fb_images(int fb, int n, ...)
535 {
536         int i;
537         va_list ap;
538
539         if(n > MAX_FB_IMGV) {
540                 fprintf(stderr, "vk_fb_images: %d is too many images\n", n);
541                 n = MAX_FB_IMGV;
542         }
543
544         va_start(ap, n);
545         for(i=0; i<n; i++) {
546                 framebufs[fb].imgv[i] = va_arg(ap, VkImageView);
547         }
548         va_end(ap);
549         framebufs[fb].num_imgv = n;
550         framebufs[fb].vkobj_valid = 0;
551 }
552
553 VkFramebuffer vk_fb(int fb)
554 {
555         VkFramebufferCreateInfo fbinf;
556         VkRenderPass rpass;
557         struct framebuf *f;
558
559         f = framebufs + fb;
560
561         if(!(rpass = vk_rpass(f->rpidx))) {
562                 return 0;
563         }
564
565         if(rpass != f->vkrpass || !f->vkobj_valid) {
566                 f->vkrpass = rpass;
567                 if(f->vkobj) {
568                         vkDestroyFramebuffer(vkdev, f->vkobj, 0);
569                         f->vkobj = 0;
570                 }
571
572                 memset(&fbinf, 0, sizeof fbinf);
573                 fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
574                 fbinf.renderPass = rpass;
575                 fbinf.attachmentCount = f->num_imgv;
576                 fbinf.pAttachments = f->imgv;
577                 fbinf.width = f->width;
578                 fbinf.height = f->height;
579
580                 if(vkCreateFramebuffer(vkdev, &fbinf, 0, &f->vkobj) != 0) {
581                         fprintf(stderr, "vk_fb: failed to create framebuffer\n");
582                         return 0;
583                 }
584                 f->vkobj_valid = 1;
585         }
586         return f->vkobj;
587 }
588
589
590 int vk_create_pipeln(void)
591 {
592         int i;
593         struct pipeline pipeln = {0}, *pp = &pipeln;
594
595         if(!pipelines) {
596                 pipelines = darr_alloc(0, sizeof *pipelines);
597                 darr_push(pipelines, &pipeln);  /* add dummy pipeline */
598         }
599
600         for(i=1; i<darr_size(pipelines); i++) {
601                 if(!pipelines[i].used) {
602                         pp = pipelines + i;
603                 }
604         }
605
606         /* init pipeline defaults */
607         memset(pp, 0, sizeof *pp);
608         pp->used = 1;
609         pp->vport[2] = pp->scissor[2] = 640;
610         pp->vport[3] = pp->scissor[3] = 480;
611         pp->prim = VKPRIM_TRIANGLES;
612         pp->polymode = VK_POLYGON_MODE_FILL;
613         pp->cull = VK_CULL_MODE_BACK_BIT;
614         pp->frontface = VK_FRONT_FACE_COUNTER_CLOCKWISE;
615         pp->colorwr = 0xf;      /* RGBA */
616         pp->zbuf = 1;
617         pp->depthwr = 1;
618         pp->stencil = 0;
619         pp->stencilwr = 1;
620         pp->sop = VK_COMPARE_OP_ALWAYS;
621         pp->smask = 0xffffffff;
622         pp->blend = 0;
623         pp->srcblend = pp->srcblend_a = VK_BLEND_FACTOR_ONE;
624         pp->dstblend = pp->dstblend_a = VK_BLEND_FACTOR_ZERO;
625
626         if(pp == &pipeln) {
627                 darr_push(pipelines, pp);
628                 return darr_size(pipelines) - 1;
629         }
630         return pp - pipelines;
631 }
632
633 void vk_free_pipeln(int pp)
634 {
635         if(!pipelines || pp < 1 || pp >= darr_size(pipelines)) {
636                 return;
637         }
638
639         if(pipelines[pp].used && pipelines[pp].vkobj) {
640                 vkDestroyPipeline(vkdev, pipelines[pp].vkobj, 0);
641         }
642         pipelines[pp].used = 0;
643 }
644
645 void vk_viewport(int pp, int x, int y, int width, int height)
646 {
647         struct pipeline *p = pipelines + pp;
648         p->vport[0] = x;
649         p->vport[1] = y;
650         p->vport[2] = width;
651         p->vport[3] = height;
652         p->vkobj_valid = 0;
653 }
654
655 void vk_scissor(int pp, int x, int y, int width, int height)
656 {
657         struct pipeline *p = pipelines + pp;
658         p->scissor[0] = x;
659         p->scissor[1] = y;
660         p->scissor[2] = width;
661         p->scissor[3] = height;
662         p->vkobj_valid = 0;
663 }
664
665 void vk_pipeln_shader(int pp, int type, VkShaderModule sdr)
666 {
667         struct pipeline *p = pipelines + pp;
668         p->sdr[type] = sdr;
669         p->vkobj_valid = 0;
670 }
671
672 /* TODO: vertex input */
673 void vk_pipeln_prim(int pp, int prim)
674 {
675         struct pipeline *p = pipelines + pp;
676         p->prim = prim;
677         p->vkobj_valid = 0;
678 }
679
680 void vk_pipeln_polymode(int pp, int mode)
681 {
682         struct pipeline *p = pipelines + pp;
683         p->polymode = mode;
684         p->vkobj_valid = 0;
685 }
686
687 void vk_pipeln_cull(int pp, int cull)
688 {
689         struct pipeline *p = pipelines + pp;
690         p->cull = cull;
691         p->vkobj_valid = 0;
692 }
693
694 void vk_pipeln_frontface(int pp, int ff)
695 {
696         struct pipeline *p = pipelines + pp;
697         p->frontface = ff;
698         p->vkobj_valid = 0;
699 }
700
701 void vk_pipeln_multisample(int pp, int nsamples)
702 {
703         /* TODO */
704 }
705
706 void vk_pipeln_colormask(int pp, int r, int g, int b, int a)
707 {
708         struct pipeline *p = pipelines + pp;
709         p->colorwr = 0;
710         if(r) p->colorwr |= VK_COLOR_COMPONENT_R_BIT;
711         if(g) p->colorwr |= VK_COLOR_COMPONENT_G_BIT;
712         if(b) p->colorwr |= VK_COLOR_COMPONENT_B_BIT;
713         if(a) p->colorwr |= VK_COLOR_COMPONENT_A_BIT;
714         p->vkobj_valid = 0;
715 }
716
717 void vk_pipeln_depthmask(int pp, int z)
718 {
719         struct pipeline *p = pipelines + pp;
720         p->depthwr = z;
721         p->vkobj_valid = 0;
722 }
723
724 void vk_pipeln_stencilmask(int pp, int s)
725 {
726         struct pipeline *p = pipelines + pp;
727         p->stencilwr = s;
728         p->vkobj_valid = 0;
729 }
730
731 void vk_pipeln_zbuffer(int pp, int enable)
732 {
733         struct pipeline *p = pipelines + pp;
734         p->zbuf = enable;
735         p->vkobj_valid = 0;
736 }
737
738 void vk_pipeln_stencil(int pp, int enable)
739 {
740         struct pipeline *p = pipelines + pp;
741         p->stencil = enable;
742         p->vkobj_valid = 0;
743 }
744
745 void vk_pipeln_stencil_op(int pp, int sfail, int zfail, int zpass)
746 {
747         struct pipeline *p = pipelines + pp;
748         p->sfail = sfail;
749         p->szfail = zfail;
750         p->szpass = zpass;
751         p->vkobj_valid = 0;
752 }
753
754 void vk_pipeln_stencil_func(int pp, int op, unsigned int ref, unsigned int mask)
755 {
756         struct pipeline *p = pipelines + pp;
757         p->sop = op;
758         p->sref = ref;
759         p->smask = mask;
760         p->vkobj_valid = 0;
761 }
762
763 void vk_pipeln_blend(int pp, int enable)
764 {
765         struct pipeline *p = pipelines + pp;
766         p->blend = enable;
767         p->vkobj_valid = 0;
768 }
769
770 void vk_pipeln_blendfunc(int pp, int src, int dst)
771 {
772         struct pipeline *p = pipelines + pp;
773         p->srcblend = src;
774         p->dstblend = dst;
775         p->vkobj_valid = 0;
776 }
777
778 VkPipeline vk_pipeln(int pp)
779 {
780         struct pipeline *p = pipelines + pp;
781
782         if(p->vkobj_valid) {
783                 return p->vkobj;
784         }
785         /* TODO */
786 }
787
788
789 #define ARRSZ(arr)      (sizeof arr / sizeof *arr)
790 static const char *known_layer_list[] = {
791         "VK_LAYER_GOOGLE_threading",
792         "VK_LAYER_LUNARG_parameter_validation",
793         "VK_LAYER_LUNARG_object_tracker",
794         "VK_LAYER_LUNARG_image",
795         "VK_LAYER_LUNARG_core_validation",
796         "VK_LAYER_LUNARG_swapchain",
797         "VK_LAYER_GOOGLE_unique_objects"
798 };
799
800 static struct {
801         const char *name;
802         int required;
803 } known_instext_list[] = {
804         {"VK_KHR_surface", 1},
805 #ifdef __WIN32__
806         {"VK_KHR_win32_surface", 1},
807 #else
808         /*{"VK_KHR_xlib_surface", 1},*/
809         {"VK_KHR_xcb_surface", 1},
810 #endif
811         {"VK_KHR_debug_report", 0}
812 };
813
814 static struct {
815         const char *name;
816         int required;
817 } known_devext_list[] = {
818         {"VK_KHR_swapchain", 1},
819         {"VK_KHR_acceleration_structure", 0},
820         {"VK_KHR_ray_tracing_pipeline", 0}
821 };
822
823 static int create_instance(void)
824 {
825         int i, nlayers = 0, next = 0;
826         VkInstanceCreateInfo instinf;
827         VkApplicationInfo appinf;
828         const char *layers[ARRSZ(known_layer_list)];
829         const char *ext[ARRSZ(known_instext_list)];
830         uint32_t apiver;
831
832         vkEnumerateInstanceVersion(&apiver);
833         printf("Vulkan API version: %d.%d.%d\n", (apiver >> 22) & 0x7f,
834                         (apiver >> 12) & 0x3ff, apiver & 0xfff);
835
836         memset(&appinf, 0, sizeof appinf);
837         appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
838         appinf.pApplicationName = "vkray";
839         appinf.pEngineName = "vkray";
840         appinf.apiVersion = apiver;
841
842         vkEnumerateInstanceLayerProperties(&inst_layers_count, 0);
843         inst_layers = malloc_nf(inst_layers_count * sizeof *inst_layers);
844         vkEnumerateInstanceLayerProperties(&inst_layers_count, inst_layers);
845
846         vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, 0);
847         inst_ext = malloc_nf(inst_ext_count * sizeof *inst_ext);
848         vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, inst_ext);
849
850         printf("Layers:\n");
851         for(i=0; i<inst_layers_count; i++) {
852                 printf(" - %s: %s\n", inst_layers[i].layerName, inst_layers[i].description);
853         }
854         printf("Instance extensions:\n");
855         for(i=0; i<inst_ext_count; i++) {
856                 printf(" - %s\n", inst_ext[i].extensionName);
857         }
858
859         have_debug_report = have_ext(inst_ext, inst_ext_count, "VK_KHR_debug_report");
860
861         for(i=0; i<ARRSZ(known_layer_list); i++) {
862                 if(have_inst_layer(known_layer_list[i])) {
863                         layers[nlayers++] = known_layer_list[i];
864                 }
865         }
866         for(i=0; i<ARRSZ(known_instext_list); i++) {
867                 if(have_ext(inst_ext, inst_ext_count, known_instext_list[i].name)) {
868                         ext[next++] = known_instext_list[i].name;
869                 } else if(known_instext_list[i].required) {
870                         fprintf(stderr, "Vulkan implementation lacks required instance extension: %s\n",
871                                         known_instext_list[i].name);
872                         return -1;
873                 }
874         }
875
876         memset(&instinf, 0, sizeof instinf);
877         instinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
878         instinf.pApplicationInfo = &appinf;
879         instinf.enabledLayerCount = nlayers;
880         instinf.ppEnabledLayerNames = layers;
881         instinf.enabledExtensionCount = next;
882         instinf.ppEnabledExtensionNames = ext;
883         if(vkCreateInstance(&instinf, 0, &vk) != 0) {
884                 fprintf(stderr, "failed to create vulkan instance\n");
885                 return -1;
886         }
887
888         return 0;
889 }
890
891 static int create_surface(void)
892 {
893         /*
894         VkXlibSurfaceCreateInfoKHR xinf = {0};
895         xinf.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
896         xinf.dpy = dpy;
897         xinf.window = win;
898
899         if(vkCreateXlibSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
900                 fprintf(stderr, "failed to create Xlib window surface\n");
901                 return -1;
902         }
903         */
904         VkXcbSurfaceCreateInfoKHR xinf = {0};
905         xinf.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
906         xinf.connection = XGetXCBConnection(dpy);
907         xinf.window = (xcb_window_t)win;
908
909         if(vkCreateXcbSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
910                 fprintf(stderr, "failed to create XCB window surface\n");
911                 return -1;
912         }
913         return 0;
914 }
915
916 int choose_phys_dev(void)
917 {
918         uint32_t i, num_pdev, score, best_score, best_dev;
919         VkPhysicalDevice *pdev;
920         VkPhysicalDeviceProperties pdevprop;
921         VkBool32 can_pres;
922
923         vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
924         if(!num_pdev) {
925                 fprintf(stderr, "no vulkan devices found\n");
926                 return -1;
927         }
928         pdev = malloc_nf(num_pdev * sizeof *pdev);
929         vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
930
931         printf("Found %d physical devices\n", num_pdev);
932
933         best_score = 0;
934         best_dev = -1;
935         for(i=0; i<num_pdev; i++) {
936                 if((score = eval_pdev_score(pdev[i])) && score > best_score) {
937                         best_score = score;
938                         best_dev = i;
939                 }
940
941                 vkGetPhysicalDeviceProperties(pdev[i], &pdevprop);
942                 printf(" %d: %s (score: %d)\n", i, pdevprop.deviceName, score);
943         }
944         if(best_dev == -1) {
945                 fprintf(stderr, "no suitable vulkan device found\n");
946                 free(pdev);
947                 return -1;
948         }
949         vkpdev = pdev[best_dev];
950
951         if(qfam) free(qfam);
952
953         vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, 0);
954         qfam = malloc_nf(num_qfam * sizeof *qfam);
955         vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, qfam);
956
957         free(pdev);
958         choose_pixfmt();
959         return 0;
960 }
961
962 static int create_device(void)
963 {
964         float *prio;
965         VkDeviceQueueCreateInfo qinf[MAX_INIT_QUEUE] = {0};
966         VkPhysicalDeviceFeatures feat = {0};
967         VkDeviceCreateInfo devinf = {0};
968         const char *ext[ARRSZ(known_devext_list) + 16];
969         int i, j, num_ext, qfam, totalq;
970
971         vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, 0);
972         dev_ext = malloc_nf(dev_ext_count * sizeof *dev_ext);
973         vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, dev_ext);
974
975         num_ext = 0;
976         for(i=0; i<ARRSZ(known_devext_list); i++) {
977                 if(have_ext(dev_ext, dev_ext_count, known_devext_list[i].name)) {
978                         ext[num_ext++] = known_devext_list[i].name;
979                 } else if(known_devext_list[i].required) {
980                         fprintf(stderr, "Vulkan device lacks required extension: %s\n",
981                                         known_devext_list[i].name);
982                         return -1;
983                 }
984         }
985
986         if(initflags & VKINIT_RAY) {
987                 if(have_ext(dev_ext, dev_ext_count, "VK_KHR_acceleration_structure") &&
988                                 have_ext(dev_ext, dev_ext_count, "VK_KHR_ray_tracing_pipeline")) {
989                         ext[num_ext++] = "VK_KHR_acceleration_structure";
990                         ext[num_ext++] = "VK_KHR_ray_tracing_pipeline";
991                 } else {
992                         initflags &= ~VKINIT_RAY;
993                 }
994         }
995
996         totalq = 0;
997         for(i=0; i<num_initq; i++) {
998                 totalq += initq[i].count;
999         }
1000         if(totalq > 1024) {
1001                 fprintf(stderr, "create_device: arbitrary limit of total queues exceeded (%d)\n", totalq);
1002                 return -1;
1003         }
1004         prio = alloca(totalq * sizeof *prio);
1005
1006         for(i=0; i<num_initq; i++) {
1007                 if((qfam = vk_find_qfamily(initq[i].flags)) == -1) {
1008                         fprintf(stderr, "create_device: failed to find queue family (flags: 0x%2x)\n",
1009                                         initq[i].flags);
1010                         return -1;
1011                 }
1012                 initq[i].qfam = qfam;
1013                 initq[i].cmdpool = 0;
1014
1015                 qinf[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1016                 qinf[i].queueFamilyIndex = qfam;
1017                 qinf[i].queueCount = initq[i].count;
1018                 qinf[i].pQueuePriorities = prio;
1019                 for(j=0; j<initq[i].count; i++) {
1020                         *prio++ = 1.0f; /* all queue priorities 1 */
1021                 }
1022         }
1023
1024         devinf.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
1025         devinf.pQueueCreateInfos = qinf;
1026         devinf.queueCreateInfoCount = num_initq;
1027         devinf.pEnabledFeatures = &feat;
1028         devinf.enabledExtensionCount = num_ext;
1029         devinf.ppEnabledExtensionNames = ext;
1030
1031         if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
1032                 fprintf(stderr, "failed to create vulkan device\n");
1033                 return -1;
1034         }
1035         return 0;
1036 }
1037
1038 static int create_swapchain(void)
1039 {
1040         int i;
1041         uint32_t num;
1042         VkSwapchainCreateInfoKHR scinf = {0};
1043         VkImageViewCreateInfo ivinf;
1044
1045         if(vksc_extent.width <= 0 || vksc_extent.height <= 0) {
1046                 return -1;
1047         }
1048
1049         scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1050         scinf.surface = vksurf;
1051         scinf.minImageCount = 2;
1052         scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
1053         scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
1054         scinf.imageExtent = vksc_extent;
1055         scinf.imageArrayLayers = 1;
1056         scinf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1057         scinf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1058         scinf.preTransform = vksurf_caps.currentTransform;
1059         scinf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1060         scinf.presentMode = VK_PRESENT_MODE_FIFO_KHR;
1061         scinf.clipped = VK_TRUE;
1062
1063         if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
1064                 fprintf(stderr, "failed to create swapchain\n");
1065                 return -1;
1066         }
1067
1068         if(!vksc_img || vksc_numimg != num) {
1069                 free(vksc_img);
1070                 vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
1071                 vksc_img = malloc_nf(num * sizeof *vksc_img);
1072                 vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
1073         }
1074         if(!vksc_view || vksc_numimg != num) {
1075                 free(vksc_view);
1076                 vksc_view = malloc_nf(num * sizeof *vksc_view);
1077         }
1078         vksc_numimg = num;
1079
1080         for(i=0; i<num; i++) {
1081                 memset(&ivinf, 0, sizeof ivinf);
1082                 ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1083                 ivinf.image = vksc_img[i];
1084                 ivinf.format = vksurf_fmt[vksurf_selfmt].format;
1085                 ivinf.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
1086                 ivinf.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
1087                 ivinf.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
1088                 ivinf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
1089                 ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1090                 ivinf.subresourceRange.levelCount = 1;
1091                 ivinf.subresourceRange.layerCount = 1;
1092                 ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
1093
1094                 if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
1095                         fprintf(stderr, "failed to create image view (%d)\n", i);
1096                         return -1;
1097                 }
1098         }
1099         return 0;
1100 }
1101
1102
1103 static int eval_pdev_score(VkPhysicalDevice dev)
1104 {
1105         int score = 0;
1106         uint32_t i, num_fmt, num_qfam, num_ext;
1107         VkQueueFamilyProperties *qfam;
1108         VkExtensionProperties *ext;
1109         VkPhysicalDeviceProperties prop;
1110         VkPhysicalDeviceFeatures feat;
1111         VkSurfaceFormatKHR *sfmt;
1112         VkBool32 can_pres;
1113
1114         vkGetPhysicalDeviceProperties(dev, &prop);
1115         vkGetPhysicalDeviceFeatures(dev, &feat);
1116
1117         /* check if we have the swapchain extension */
1118         vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, 0);
1119         ext = malloc_nf(num_ext * sizeof *ext);
1120         vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, ext);
1121
1122         if(!have_ext(ext, num_ext, "VK_KHR_swapchain")) {
1123                 free(ext);
1124                 return 0;
1125         }
1126
1127         /* populate format and present modes arrays, and make sure we have some of each */
1128         vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
1129         if(!num_fmt) {
1130                 free(ext);
1131                 return 0;
1132         }
1133         sfmt = malloc_nf(num_fmt * sizeof *sfmt);
1134         vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, sfmt);
1135
1136         vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
1137
1138         /* find a queue family which can do graphics and can present */
1139         vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
1140         qfam = malloc_nf(num_qfam * sizeof *qfam);
1141         vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
1142
1143         for(i=0; i<num_qfam; i++) {
1144                 vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, vksurf, &can_pres);
1145                 if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
1146                         score = 1;
1147                 }
1148         }
1149
1150         switch(prop.deviceType) {
1151         case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
1152                 score++;
1153                 break;
1154         case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
1155                 score += 2;
1156                 break;
1157         case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
1158                 score += 4;
1159                 break;
1160         default:
1161                 break;
1162         }
1163
1164         if(initflags & VKINIT_RAY) {
1165                 if(have_ext(ext, num_ext, "VK_KHR_acceleration_structure") &&
1166                                 have_ext(ext, num_ext, "VK_KHR_ray_tracing_pipeline")) {
1167                         score += 100;
1168                 }
1169         }
1170
1171         free(ext);
1172         free(sfmt);
1173         free(qfam);
1174         return score;
1175 }
1176
1177 static int choose_pixfmt(void)
1178 {
1179         static const VkFormat pref[] = {
1180                 VK_FORMAT_B8G8R8_UNORM,
1181                 VK_FORMAT_R8G8B8_UNORM,
1182                 VK_FORMAT_B8G8R8A8_UNORM,
1183                 VK_FORMAT_R8G8B8A8_UNORM
1184         };
1185         int i, j;
1186         uint32_t num_fmt;
1187
1188         vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, 0);
1189         if(!num_fmt) return -1;
1190         vksurf_fmt = malloc_nf(num_fmt * sizeof *vksurf_fmt);
1191         vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, vksurf_fmt);
1192
1193         vksurf_selfmt = 0;
1194         for(i=0; i<num_fmt; i++) {
1195                 if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
1196                         continue;
1197                 }
1198                 for(j=0; j<sizeof pref / sizeof *pref; j++) {
1199                         if(vksurf_fmt[i].format == pref[j]) {
1200                                 vksurf_selfmt = i;
1201                                 vksurf_numfmt = num_fmt;
1202                                 return i;
1203                         }
1204                 }
1205         }
1206         free(vksurf_fmt);
1207         vksurf_fmt = 0;
1208         return -1;
1209 }
1210
1211
1212 static int have_inst_layer(const char *name)
1213 {
1214         int i;
1215         for(i=0; i<inst_layers_count; i++) {
1216                 if(strcmp(inst_layers[i].layerName, name) == 0) {
1217                         return 1;
1218                 }
1219         }
1220         return 0;
1221 }
1222
1223 static int have_ext(VkExtensionProperties *ext, int next, const char *name)
1224 {
1225         int i;
1226         for(i=0; i<next; i++) {
1227                 if(strcmp(ext[i].extensionName, name) == 0) {
1228                         return 1;
1229                 }
1230         }
1231         return 0;
1232 }