5 #include <vulkan/vulkan.h>
11 #include <vulkan/vulkan_win32.h>
13 /*#include <vulkan/vulkan_xlib.h>*/
14 #include <X11/Xlib-xcb.h>
15 #include <vulkan/vulkan_xcb.h>
35 /* if rpasses[rpidx].vkobj != vkrpass, the framebuf is invalid */
39 VkImageView imgv[MAX_FB_IMGV];
50 VkShaderModule sdr[VKSDR_MAX];
51 VkPrimitiveTopology prim;
52 VkPolygonMode polymode;
55 VkFrontFace frontface;
56 VkColorComponentFlags colorwr;
59 int stencil, stencilwr;
60 VkStencilOp sfail, szfail, szpass;
62 unsigned int sref, smask;
64 VkBlendFactor srcblend, dstblend, srcblend_a, dstblend_a;
70 VkPipelineLayout vkobj_layout; /* TODO probably best to split this */
74 static struct rpass *rpasses;
75 static struct framebuf *framebufs;
76 static struct pipeline *pipelines;
79 static int create_instance(void);
80 static int create_surface(void);
81 static int choose_phys_dev(void);
82 static int create_device(void);
83 static int create_swapchain(void);
85 static int choose_pixfmt(void);
86 static int eval_pdev_score(VkPhysicalDevice dev);
87 static int have_inst_layer(const char *name);
88 static int have_ext(VkExtensionProperties *ext, int next, const char *name);
93 #define MAX_INIT_QUEUE 32
98 VkCommandPool cmdpool;
99 } initq[MAX_INIT_QUEUE];
100 static int num_initq;
102 static VkInstance vk;
103 static VkPhysicalDevice vkpdev;
104 static VkQueueFamilyProperties *qfam;
105 static uint32_t num_qfam;
106 static VkDevice vkdev;
107 static VkSurfaceKHR vksurf;
108 static VkSurfaceCapabilitiesKHR vksurf_caps;
109 static int vksurf_numfmt, vksurf_selfmt;
110 static VkSurfaceFormatKHR *vksurf_fmt;
111 static VkSwapchainKHR vksc;
112 static int vksc_numimg;
113 static VkImage *vksc_img;
114 static VkExtent2D vksc_extent;
115 static VkImageView *vksc_view;
117 static VkLayerProperties *inst_layers;
118 static VkExtensionProperties *inst_ext, *dev_ext;
119 static uint32_t inst_ext_count, dev_ext_count, inst_layers_count;
121 static VkPhysicalDevice *pdev_list;
122 static uint32_t num_pdev;
124 static int have_raytrace, have_debug_report;
126 void vk_init_xwin(Display *d, Window w)
132 void vk_init_queue(unsigned int qflags, int count)
136 for(i=0; i<num_initq; i++) {
137 if(initq[i].flags == qflags) {
138 initq[i].count += count;
143 if(num_initq >= MAX_INIT_QUEUE) {
144 fprintf(stderr, "vk_init_queue: too many queues\n");
147 initq[num_initq].flags = qflags;
148 initq[num_initq].count = count;
152 int vk_init(unsigned int flags, unsigned int *usedflags)
155 vk_init_queue(VKQ_GFX | VKQ_PRESENT, 1);
159 if(create_instance() == -1) return -1;
160 if(create_surface() == -1) return -1;
161 if(choose_phys_dev() == -1) return -1;
162 if(create_device() == -1) return -1;
164 if(initflags != flags) {
166 *usedflags = initflags;
175 void vk_cleanup(void)
184 for(i=0; i<vksc_numimg; i++) {
185 vkDestroyImageView(vkdev, vksc_view[i], 0);
190 vkDestroySwapchainKHR(vkdev, vksc, 0);
194 vkDestroyDevice(vkdev, 0);
198 vkDestroySurfaceKHR(vk, vksurf, 0);
202 vkDestroyInstance(vk, 0);
215 int vk_reshape(int xsz, int ysz)
219 if(vksc && vksc_extent.width == xsz && vksc_extent.height == ysz) {
224 for(i=0; i<vksc_numimg; i++) {
225 vkDestroyImageView(vkdev, vksc_view[i], 0);
228 if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
230 vksc_extent.width = xsz;
231 vksc_extent.height = ysz;
233 if(create_swapchain() == -1) return -1;
235 /* TODO create depth/stencil buffers as needed (initflags) */
239 int vk_find_qfamily(unsigned int flags)
244 if(!qfam) return -1; /* not initialized I guess... */
246 for(i=0; i<num_qfam; i++) {
247 vkGetPhysicalDeviceSurfaceSupportKHR(vkpdev, i, vksurf, &can_pres);
249 if((flags & VKQ_PRESENT) && !can_pres) {
252 if((flags & VKQ_GFX) && !(qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) {
255 if((flags & VKQ_COMPUTE) && !(qfam[i].queueFlags & VK_QUEUE_COMPUTE_BIT)) {
259 return i; /* found a suitabe queue family */
265 VkQueue vk_getq_fam(int fam, int n)
269 if(fam < 0) return 0;
270 if(n < 0 || n >= qfam[fam].queueCount) {
271 fprintf(stderr, "vk_getq_fam: invalid index %d, family %d has %d queues\n",
272 n, fam, qfam[fam].queueCount);
276 vkGetDeviceQueue(vkdev, fam, n, &q);
280 VkQueue vk_getq(unsigned int flags, int n)
282 return vk_getq_fam(vk_find_qfamily(flags), n);
285 static VkCommandPool find_cmdpool(int qfam)
288 VkCommandPoolCreateInfo pinf;
290 for(i=0; i<num_initq; i++) {
291 if(initq[i].qfam == qfam) {
292 if(!initq[i].cmdpool) {
293 /* allocate command pool for this queue family */
294 memset(&pinf, 0, sizeof pinf);
295 pinf.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
296 pinf.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
297 pinf.queueFamilyIndex = qfam;
299 if(vkCreateCommandPool(vkdev, &pinf, 0, &initq[i].cmdpool) != 0) {
300 fprintf(stderr, "ck_create_cmdbuf: failed to create command buffer pool\n");
304 return initq[i].cmdpool;
308 fprintf(stderr, "vk_create_cmdbuf: failed to find command pool for queue family: %d\n", qfam);
312 VkCommandBuffer vk_create_cmdbuf_fam(int qfam, int level)
314 VkCommandBufferAllocateInfo inf = {0};
315 VkCommandBuffer cmdbuf;
316 VkCommandPool cmdpool;
318 if(!(cmdpool = find_cmdpool(qfam))) {
322 inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
323 inf.commandPool = cmdpool;
325 inf.commandBufferCount = 1;
327 if(vkAllocateCommandBuffers(vkdev, &inf, &cmdbuf) != 0) {
328 fprintf(stderr, "vk_create_cmdbuf: failed to allocate command buffer\n");
334 VkCommandBuffer vk_create_cmdbuf(unsigned int qflags, int level)
338 if((qfam = vk_find_qfamily(qflags)) == -1) {
339 fprintf(stderr, "vk_create_cmdbuf: failed to find matching queue family\n");
342 return vk_create_cmdbuf_fam(qfam, level);
345 int vk_create_rpass(void)
348 struct rpass rpass = {0}, *rp = &rpass;
351 rpasses = darr_alloc(0, sizeof *rpasses);
352 darr_push(rpasses, &rpass); /* add dummy rpass */
355 for(i=1; i<darr_size(rpasses); i++) {
356 if(!rpasses[i].used) {
361 /* init renderpass defaults */
363 rp->fmt = vksurf_fmt[vksurf_selfmt].format;
364 rp->zfmt = VK_FORMAT_D24_UNORM_S8_UINT;
372 darr_push(rpasses, rp);
373 return darr_size(rpasses) - 1;
378 void vk_free_rpass(int rp)
380 if(!rpasses || rp < 1 || rp >= darr_size(rpasses)) {
384 if(rpasses[rp].used && rpasses[rp].vkobj) {
385 vkDestroyRenderPass(vkdev, rpasses[rp].vkobj, 0);
387 rpasses[rp].used = 0;
390 void vk_rpass_colorbuf(int rp, int fmt, int n)
392 rpasses[rp].fmt = fmt;
393 rpasses[rp].num_colbuf = n;
394 rpasses[rp].vkobj_valid = 0;
397 void vk_rpass_msaa(int rp, int nsamp)
399 rpasses[rp].num_samples = nsamp;
400 rpasses[rp].vkobj_valid = 0;
403 void vk_rpass_clear(int rp, int clear)
405 rpasses[rp].clear = clear;
406 rpasses[rp].vkobj_valid = 0;
409 VkRenderPass vk_rpass(int rp)
413 VkAttachmentDescription att[17];
414 VkAttachmentReference catref[16], zatref;
415 VkSubpassDescription subpass;
416 VkRenderPassCreateInfo pinf;
420 if(!r->vkobj_valid) {
422 vkDestroyRenderPass(vkdev, r->vkobj, 0);
426 zidx = r->num_colbuf;
427 memset(att, 0, sizeof att);
428 for(i=0; i<r->num_colbuf; i++) {
429 att[i].format = r->fmt;
430 att[i].samples = r->num_samples;
431 att[i].loadOp = r->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
432 att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
433 att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
434 att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
435 att[i].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
436 att[i].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
438 att[zidx].format = r->zfmt;
439 att[zidx].samples = 1;
440 att[zidx].loadOp = r->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
441 att[zidx].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
442 att[zidx].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
443 att[zidx].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
444 att[zidx].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
445 att[zidx].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
447 for(i=0; i<r->num_colbuf; i++) {
448 catref[i].attachment = i;
449 catref[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
451 zatref.attachment = zidx;
452 zatref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
454 memset(&subpass, 0, sizeof subpass);
455 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
456 subpass.colorAttachmentCount = r->num_colbuf;
457 subpass.pColorAttachments = catref;
458 subpass.pDepthStencilAttachment = &zatref;
460 memset(&pinf, 0, sizeof pinf);
461 pinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
462 pinf.attachmentCount = r->num_colbuf + 1;
463 pinf.pAttachments = att;
464 pinf.subpassCount = 1;
465 pinf.pSubpasses = &subpass;
467 if(vkCreateRenderPass(vkdev, &pinf, 0, &r->vkobj) != 0) {
468 fprintf(stderr, "failed to create render pass!\n");
478 int vk_create_fb(void)
481 struct framebuf framebuf = {0}, *fb = &framebuf;
484 framebufs = darr_alloc(0, sizeof *framebufs);
485 darr_push(framebufs, &framebuf); /* add dummy rpass */
488 for(i=1; i<darr_size(framebufs); i++) {
489 if(!framebufs[i].used) {
494 /* init framebuffer defaults */
495 memset(fb, 0, sizeof &fb);
498 if(fb == &framebuf) {
499 darr_push(framebufs, fb);
500 return darr_size(framebufs) - 1;
502 return fb - framebufs;
505 void vk_free_fb(int fb)
507 if(!framebufs || fb < 1 || fb >= darr_size(framebufs)) {
511 if(framebufs[fb].used && framebufs[fb].vkobj) {
512 vkDestroyFramebuffer(vkdev, framebufs[fb].vkobj, 0);
514 framebufs[fb].used = 0;
517 void vk_fb_size(int fb, int x, int y)
519 framebufs[fb].width = x;
520 framebufs[fb].height = y;
521 framebufs[fb].vkobj_valid = 0;
524 void vk_fb_rpass(int fb, int rpass)
526 if(rpass < 0 || rpass >= darr_size(rpasses) || !rpasses[rpass].used) {
527 fprintf(stderr, "vk_fb_rpass: %d is not a valid renderpass\n", rpass);
531 framebufs[fb].rpidx = rpass;
532 if(rpasses[rpass].vkobj_valid) {
533 framebufs[fb].vkrpass = rpasses[rpass].vkobj;
535 framebufs[fb].vkrpass = 0;
537 framebufs[fb].vkobj_valid = 0;
540 void vk_fb_images(int fb, int n, ...)
545 if(n > MAX_FB_IMGV) {
546 fprintf(stderr, "vk_fb_images: %d is too many images\n", n);
552 framebufs[fb].imgv[i] = va_arg(ap, VkImageView);
555 framebufs[fb].num_imgv = n;
556 framebufs[fb].vkobj_valid = 0;
559 VkFramebuffer vk_fb(int fb)
561 VkFramebufferCreateInfo fbinf;
567 if(!(rpass = vk_rpass(f->rpidx))) {
571 if(rpass != f->vkrpass || !f->vkobj_valid) {
574 vkDestroyFramebuffer(vkdev, f->vkobj, 0);
578 memset(&fbinf, 0, sizeof fbinf);
579 fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
580 fbinf.renderPass = rpass;
581 fbinf.attachmentCount = f->num_imgv;
582 fbinf.pAttachments = f->imgv;
583 fbinf.width = f->width;
584 fbinf.height = f->height;
586 if(vkCreateFramebuffer(vkdev, &fbinf, 0, &f->vkobj) != 0) {
587 fprintf(stderr, "vk_fb: failed to create framebuffer\n");
596 int vk_create_pipeln(void)
599 struct pipeline pipeln = {0}, *pp = &pipeln;
602 pipelines = darr_alloc(0, sizeof *pipelines);
603 darr_push(pipelines, &pipeln); /* add dummy pipeline */
606 for(i=1; i<darr_size(pipelines); i++) {
607 if(!pipelines[i].used) {
612 /* init pipeline defaults */
613 memset(pp, 0, sizeof *pp);
615 pp->vport.width = pp->scissor.extent.width = 640;
616 pp->vport.height = pp->scissor.extent.height = 480;
617 pp->vport.minDepth = 0.0f;
618 pp->vport.maxDepth = 1.0f;
619 pp->prim = VKPRIM_TRIANGLES;
620 pp->polymode = VK_POLYGON_MODE_FILL;
621 pp->cull = VK_CULL_MODE_BACK_BIT;
622 pp->frontface = VK_FRONT_FACE_COUNTER_CLOCKWISE;
623 pp->line_width = 1.0f;
624 pp->colorwr = 0xf; /* RGBA */
626 pp->zop = VK_COMPARE_OP_LESS;
630 pp->sop = VK_COMPARE_OP_ALWAYS;
631 pp->smask = 0xffffffff;
633 pp->srcblend = pp->srcblend_a = VK_BLEND_FACTOR_ONE;
634 pp->dstblend = pp->dstblend_a = VK_BLEND_FACTOR_ZERO;
637 darr_push(pipelines, pp);
638 return darr_size(pipelines) - 1;
640 return pp - pipelines;
643 void vk_free_pipeln(int pp)
645 if(!pipelines || pp < 1 || pp >= darr_size(pipelines)) {
649 if(pipelines[pp].used && pipelines[pp].vkobj) {
650 vkDestroyPipeline(vkdev, pipelines[pp].vkobj, 0);
652 pipelines[pp].used = 0;
655 void vk_pipeln_rpass(int pp, VkRenderPass rp)
657 struct pipeline *p = pipelines + pp;
662 void vk_pipeln_viewport(int pp, int x, int y, int width, int height)
664 struct pipeline *p = pipelines + pp;
667 p->vport.width = width;
668 p->vport.height = height;
672 void vk_pipeln_scissor(int pp, int x, int y, int width, int height)
674 struct pipeline *p = pipelines + pp;
675 p->scissor.offset.x = x;
676 p->scissor.offset.y = y;
677 p->scissor.extent.width = width;
678 p->scissor.extent.height = height;
682 void vk_pipeln_shader(int pp, int type, VkShaderModule sdr)
684 struct pipeline *p = pipelines + pp;
689 /* TODO: vertex input */
690 void vk_pipeln_prim(int pp, int prim)
692 struct pipeline *p = pipelines + pp;
697 void vk_pipeln_polymode(int pp, int mode)
699 struct pipeline *p = pipelines + pp;
704 void vk_pipeln_cull(int pp, int cull)
706 struct pipeline *p = pipelines + pp;
711 void vk_pipeln_frontface(int pp, int ff)
713 struct pipeline *p = pipelines + pp;
718 void vk_pipeln_linewidth(int pp, int w)
720 struct pipeline *p = pipelines + pp;
725 void vk_pipeln_multisample(int pp, int nsamples)
730 void vk_pipeln_colormask(int pp, int r, int g, int b, int a)
732 struct pipeline *p = pipelines + pp;
734 if(r) p->colorwr |= VK_COLOR_COMPONENT_R_BIT;
735 if(g) p->colorwr |= VK_COLOR_COMPONENT_G_BIT;
736 if(b) p->colorwr |= VK_COLOR_COMPONENT_B_BIT;
737 if(a) p->colorwr |= VK_COLOR_COMPONENT_A_BIT;
741 void vk_pipeln_depthmask(int pp, int z)
743 struct pipeline *p = pipelines + pp;
748 void vk_pipeln_stencilmask(int pp, int s)
750 struct pipeline *p = pipelines + pp;
755 void vk_pipeln_zbuffer(int pp, int enable)
757 struct pipeline *p = pipelines + pp;
762 void vk_pipeln_zbuffer_op(int pp, int op)
764 struct pipeline *p = pipelines + pp;
769 void vk_pipeln_stencil(int pp, int enable)
771 struct pipeline *p = pipelines + pp;
776 void vk_pipeln_stencil_op(int pp, int sfail, int zfail, int zpass)
778 struct pipeline *p = pipelines + pp;
785 void vk_pipeln_stencil_func(int pp, int op, unsigned int ref, unsigned int mask)
787 struct pipeline *p = pipelines + pp;
794 void vk_pipeln_blend(int pp, int enable)
796 struct pipeline *p = pipelines + pp;
801 void vk_pipeln_blendfunc(int pp, int src, int dst)
803 struct pipeline *p = pipelines + pp;
809 VkPipeline vk_pipeln(int pp)
812 struct pipeline *p = pipelines + pp;
813 VkPipelineShaderStageCreateInfo ssinf[VKSDR_MAX];
814 VkPipelineVertexInputStateCreateInfo vinp;
815 VkPipelineInputAssemblyStateCreateInfo vasm;
816 VkPipelineViewportStateCreateInfo vp;
817 VkPipelineRasterizationStateCreateInfo rast;
818 VkPipelineMultisampleStateCreateInfo msaa;
819 VkPipelineDepthStencilStateCreateInfo zst;
820 VkPipelineColorBlendAttachmentState bat;
821 VkPipelineColorBlendStateCreateInfo blend;
822 VkPipelineLayoutCreateInfo lay;
823 VkGraphicsPipelineCreateInfo pinf;
831 vkDestroyPipeline(vkdev, p->vkobj, 0);
835 memset(ssinf, 0, sizeof ssinf);
837 for(i=0; i<VKSDR_MAX; i++) {
839 ssinf[idx].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
840 ssinf[idx].stage = VKSDR_STAGE(i);
841 ssinf[idx].module = p->sdr[idx];
842 ssinf[idx].pName = "main";
848 memset(&vinp, 0, sizeof vinp);
849 vinp.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
851 memset(&vasm, 0, sizeof vasm);
852 vasm.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
853 vasm.topology = p->prim;
855 memset(&vp, 0, sizeof vp);
856 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
857 vp.viewportCount = 1;
858 vp.pViewports = &p->vport;
860 vp.pScissors = &p->scissor;
862 memset(&rast, 0, sizeof rast);
863 rast.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
864 rast.polygonMode = p->polymode;
865 rast.lineWidth = p->line_width;
866 rast.cullMode = p->cull;
867 rast.frontFace = p->frontface;
870 memset(&msaa, 0, sizeof msaa);
871 msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
872 msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
873 msaa.minSampleShading = 1.0f;
875 memset(&zst, 0, sizeof zst);
876 zst.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
877 zst.depthTestEnable = p->zbuf;
878 zst.depthWriteEnable = p->depthwr;
879 zst.depthCompareOp = p->zop;
880 zst.stencilTestEnable = p->stencil;
881 zst.front.writeMask = p->stencilwr;
882 zst.front.failOp = p->sfail;
883 zst.front.passOp = p->szpass;
884 zst.front.depthFailOp = p->szfail;
885 zst.front.compareOp = p->sop;
886 zst.front.compareMask = p->smask;
887 zst.front.reference = p->sref;
888 zst.back = zst.front;
890 memset(&bat, 0, sizeof bat);
891 bat.colorWriteMask = p->colorwr;
892 bat.blendEnable = p->blend;
893 bat.srcColorBlendFactor = p->srcblend;
894 bat.dstColorBlendFactor = p->dstblend;
895 bat.colorBlendOp = VK_BLEND_OP_ADD; /* TODO */
896 bat.srcAlphaBlendFactor = p->srcblend_a;
897 bat.dstAlphaBlendFactor = p->dstblend_a;
899 memset(&blend, 0, sizeof blend);
900 blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
901 blend.attachmentCount = 1;
902 blend.pAttachments = &bat;
905 memset(&lay, 0, sizeof lay);
906 lay.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
907 if(vkCreatePipelineLayout(vkdev, &lay, 0, &p->vkobj_layout) != 0) {
911 memset(&pinf, 0, sizeof pinf);
912 pinf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
913 pinf.stageCount = num_sdr;
914 pinf.pStages = ssinf;
915 pinf.pVertexInputState = &vinp;
916 pinf.pInputAssemblyState = &vasm;
917 pinf.pViewportState = &vp;
918 pinf.pRasterizationState = &rast;
919 pinf.pDepthStencilState = &zst;
920 pinf.pMultisampleState = &msaa;
921 pinf.pColorBlendState = &blend;
922 pinf.layout = p->vkobj_layout;
923 pinf.renderPass = p->rpass;
924 pinf.basePipelineIndex = -1;
926 if(vkCreateGraphicsPipelines(vkdev, 0, 1, &pinf, 0, &p->vkobj) != 0) {
934 #define ARRSZ(arr) (sizeof arr / sizeof *arr)
935 static const char *known_layer_list[] = {
936 "VK_LAYER_GOOGLE_threading",
937 "VK_LAYER_LUNARG_parameter_validation",
938 "VK_LAYER_LUNARG_object_tracker",
939 "VK_LAYER_LUNARG_image",
940 "VK_LAYER_LUNARG_core_validation",
941 "VK_LAYER_LUNARG_swapchain",
942 "VK_LAYER_GOOGLE_unique_objects"
948 } known_instext_list[] = {
949 {"VK_KHR_surface", 1},
951 {"VK_KHR_win32_surface", 1},
953 /*{"VK_KHR_xlib_surface", 1},*/
954 {"VK_KHR_xcb_surface", 1},
956 {"VK_KHR_debug_report", 0}
962 } known_devext_list[] = {
963 {"VK_KHR_swapchain", 1},
964 {"VK_KHR_acceleration_structure", 0},
965 {"VK_KHR_ray_tracing_pipeline", 0}
968 static int create_instance(void)
970 int i, nlayers = 0, next = 0;
971 VkInstanceCreateInfo instinf;
972 VkApplicationInfo appinf;
973 const char *layers[ARRSZ(known_layer_list)];
974 const char *ext[ARRSZ(known_instext_list)];
977 vkEnumerateInstanceVersion(&apiver);
978 printf("Vulkan API version: %d.%d.%d\n", (apiver >> 22) & 0x7f,
979 (apiver >> 12) & 0x3ff, apiver & 0xfff);
981 memset(&appinf, 0, sizeof appinf);
982 appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
983 appinf.pApplicationName = "vkray";
984 appinf.pEngineName = "vkray";
985 appinf.apiVersion = apiver;
987 vkEnumerateInstanceLayerProperties(&inst_layers_count, 0);
988 inst_layers = malloc_nf(inst_layers_count * sizeof *inst_layers);
989 vkEnumerateInstanceLayerProperties(&inst_layers_count, inst_layers);
991 vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, 0);
992 inst_ext = malloc_nf(inst_ext_count * sizeof *inst_ext);
993 vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, inst_ext);
996 for(i=0; i<inst_layers_count; i++) {
997 printf(" - %s: %s\n", inst_layers[i].layerName, inst_layers[i].description);
999 printf("Instance extensions:\n");
1000 for(i=0; i<inst_ext_count; i++) {
1001 printf(" - %s\n", inst_ext[i].extensionName);
1004 have_debug_report = have_ext(inst_ext, inst_ext_count, "VK_KHR_debug_report");
1006 for(i=0; i<ARRSZ(known_layer_list); i++) {
1007 if(have_inst_layer(known_layer_list[i])) {
1008 layers[nlayers++] = known_layer_list[i];
1011 for(i=0; i<ARRSZ(known_instext_list); i++) {
1012 if(have_ext(inst_ext, inst_ext_count, known_instext_list[i].name)) {
1013 ext[next++] = known_instext_list[i].name;
1014 } else if(known_instext_list[i].required) {
1015 fprintf(stderr, "Vulkan implementation lacks required instance extension: %s\n",
1016 known_instext_list[i].name);
1021 memset(&instinf, 0, sizeof instinf);
1022 instinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
1023 instinf.pApplicationInfo = &appinf;
1024 instinf.enabledLayerCount = nlayers;
1025 instinf.ppEnabledLayerNames = layers;
1026 instinf.enabledExtensionCount = next;
1027 instinf.ppEnabledExtensionNames = ext;
1028 if(vkCreateInstance(&instinf, 0, &vk) != 0) {
1029 fprintf(stderr, "failed to create vulkan instance\n");
1036 static int create_surface(void)
1039 VkXlibSurfaceCreateInfoKHR xinf = {0};
1040 xinf.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
1044 if(vkCreateXlibSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
1045 fprintf(stderr, "failed to create Xlib window surface\n");
1049 VkXcbSurfaceCreateInfoKHR xinf = {0};
1050 xinf.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
1051 xinf.connection = XGetXCBConnection(dpy);
1052 xinf.window = (xcb_window_t)win;
1054 if(vkCreateXcbSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
1055 fprintf(stderr, "failed to create XCB window surface\n");
1061 int choose_phys_dev(void)
1063 uint32_t i, num_pdev, score, best_score, best_dev;
1064 VkPhysicalDevice *pdev;
1065 VkPhysicalDeviceProperties pdevprop;
1068 vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
1070 fprintf(stderr, "no vulkan devices found\n");
1073 pdev = malloc_nf(num_pdev * sizeof *pdev);
1074 vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
1076 printf("Found %d physical devices\n", num_pdev);
1080 for(i=0; i<num_pdev; i++) {
1081 if((score = eval_pdev_score(pdev[i])) && score > best_score) {
1086 vkGetPhysicalDeviceProperties(pdev[i], &pdevprop);
1087 printf(" %d: %s (score: %d)\n", i, pdevprop.deviceName, score);
1089 if(best_dev == -1) {
1090 fprintf(stderr, "no suitable vulkan device found\n");
1094 vkpdev = pdev[best_dev];
1096 if(qfam) free(qfam);
1098 vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, 0);
1099 qfam = malloc_nf(num_qfam * sizeof *qfam);
1100 vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, qfam);
1107 static int create_device(void)
1110 VkDeviceQueueCreateInfo qinf[MAX_INIT_QUEUE] = {0};
1111 VkPhysicalDeviceFeatures feat = {0};
1112 VkDeviceCreateInfo devinf = {0};
1113 const char *ext[ARRSZ(known_devext_list) + 16];
1114 int i, j, num_ext, qfam, totalq;
1116 vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, 0);
1117 dev_ext = malloc_nf(dev_ext_count * sizeof *dev_ext);
1118 vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, dev_ext);
1121 for(i=0; i<ARRSZ(known_devext_list); i++) {
1122 if(have_ext(dev_ext, dev_ext_count, known_devext_list[i].name)) {
1123 ext[num_ext++] = known_devext_list[i].name;
1124 } else if(known_devext_list[i].required) {
1125 fprintf(stderr, "Vulkan device lacks required extension: %s\n",
1126 known_devext_list[i].name);
1131 if(initflags & VKINIT_RAY) {
1132 if(have_ext(dev_ext, dev_ext_count, "VK_KHR_acceleration_structure") &&
1133 have_ext(dev_ext, dev_ext_count, "VK_KHR_ray_tracing_pipeline")) {
1134 ext[num_ext++] = "VK_KHR_acceleration_structure";
1135 ext[num_ext++] = "VK_KHR_ray_tracing_pipeline";
1137 initflags &= ~VKINIT_RAY;
1142 for(i=0; i<num_initq; i++) {
1143 totalq += initq[i].count;
1146 fprintf(stderr, "create_device: arbitrary limit of total queues exceeded (%d)\n", totalq);
1149 prio = alloca(totalq * sizeof *prio);
1151 for(i=0; i<num_initq; i++) {
1152 if((qfam = vk_find_qfamily(initq[i].flags)) == -1) {
1153 fprintf(stderr, "create_device: failed to find queue family (flags: 0x%2x)\n",
1157 initq[i].qfam = qfam;
1158 initq[i].cmdpool = 0;
1160 qinf[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1161 qinf[i].queueFamilyIndex = qfam;
1162 qinf[i].queueCount = initq[i].count;
1163 qinf[i].pQueuePriorities = prio;
1164 for(j=0; j<initq[i].count; i++) {
1165 *prio++ = 1.0f; /* all queue priorities 1 */
1169 devinf.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
1170 devinf.pQueueCreateInfos = qinf;
1171 devinf.queueCreateInfoCount = num_initq;
1172 devinf.pEnabledFeatures = &feat;
1173 devinf.enabledExtensionCount = num_ext;
1174 devinf.ppEnabledExtensionNames = ext;
1176 if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
1177 fprintf(stderr, "failed to create vulkan device\n");
1183 static int create_swapchain(void)
1187 VkSwapchainCreateInfoKHR scinf = {0};
1188 VkImageViewCreateInfo ivinf;
1190 if(vksc_extent.width <= 0 || vksc_extent.height <= 0) {
1194 scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1195 scinf.surface = vksurf;
1196 scinf.minImageCount = 2;
1197 scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
1198 scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
1199 scinf.imageExtent = vksc_extent;
1200 scinf.imageArrayLayers = 1;
1201 scinf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1202 scinf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1203 scinf.preTransform = vksurf_caps.currentTransform;
1204 scinf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1205 scinf.presentMode = VK_PRESENT_MODE_FIFO_KHR;
1206 scinf.clipped = VK_TRUE;
1208 if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
1209 fprintf(stderr, "failed to create swapchain\n");
1213 if(!vksc_img || vksc_numimg != num) {
1215 vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
1216 vksc_img = malloc_nf(num * sizeof *vksc_img);
1217 vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
1219 if(!vksc_view || vksc_numimg != num) {
1221 vksc_view = malloc_nf(num * sizeof *vksc_view);
1225 for(i=0; i<num; i++) {
1226 memset(&ivinf, 0, sizeof ivinf);
1227 ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1228 ivinf.image = vksc_img[i];
1229 ivinf.format = vksurf_fmt[vksurf_selfmt].format;
1230 ivinf.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
1231 ivinf.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
1232 ivinf.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
1233 ivinf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
1234 ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1235 ivinf.subresourceRange.levelCount = 1;
1236 ivinf.subresourceRange.layerCount = 1;
1237 ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
1239 if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
1240 fprintf(stderr, "failed to create image view (%d)\n", i);
1248 static int eval_pdev_score(VkPhysicalDevice dev)
1251 uint32_t i, num_fmt, num_qfam, num_ext;
1252 VkQueueFamilyProperties *qfam;
1253 VkExtensionProperties *ext;
1254 VkPhysicalDeviceProperties prop;
1255 VkPhysicalDeviceFeatures feat;
1256 VkSurfaceFormatKHR *sfmt;
1259 vkGetPhysicalDeviceProperties(dev, &prop);
1260 vkGetPhysicalDeviceFeatures(dev, &feat);
1262 /* check if we have the swapchain extension */
1263 vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, 0);
1264 ext = malloc_nf(num_ext * sizeof *ext);
1265 vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, ext);
1267 if(!have_ext(ext, num_ext, "VK_KHR_swapchain")) {
1272 /* populate format and present modes arrays, and make sure we have some of each */
1273 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
1278 sfmt = malloc_nf(num_fmt * sizeof *sfmt);
1279 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, sfmt);
1281 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
1283 /* find a queue family which can do graphics and can present */
1284 vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
1285 qfam = malloc_nf(num_qfam * sizeof *qfam);
1286 vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
1288 for(i=0; i<num_qfam; i++) {
1289 vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, vksurf, &can_pres);
1290 if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
1295 switch(prop.deviceType) {
1296 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
1299 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
1302 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
1309 if(initflags & VKINIT_RAY) {
1310 if(have_ext(ext, num_ext, "VK_KHR_acceleration_structure") &&
1311 have_ext(ext, num_ext, "VK_KHR_ray_tracing_pipeline")) {
1322 static int choose_pixfmt(void)
1324 static const VkFormat pref[] = {
1325 VK_FORMAT_B8G8R8_UNORM,
1326 VK_FORMAT_R8G8B8_UNORM,
1327 VK_FORMAT_B8G8R8A8_UNORM,
1328 VK_FORMAT_R8G8B8A8_UNORM
1333 vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, 0);
1334 if(!num_fmt) return -1;
1335 vksurf_fmt = malloc_nf(num_fmt * sizeof *vksurf_fmt);
1336 vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, vksurf_fmt);
1339 for(i=0; i<num_fmt; i++) {
1340 if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
1343 for(j=0; j<sizeof pref / sizeof *pref; j++) {
1344 if(vksurf_fmt[i].format == pref[j]) {
1346 vksurf_numfmt = num_fmt;
1357 static int have_inst_layer(const char *name)
1360 for(i=0; i<inst_layers_count; i++) {
1361 if(strcmp(inst_layers[i].layerName, name) == 0) {
1368 static int have_ext(VkExtensionProperties *ext, int next, const char *name)
1371 for(i=0; i<next; i++) {
1372 if(strcmp(ext[i].extensionName, name) == 0) {