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];
48 int vport[4], scissor[4];
49 VkShaderModule sdr[VKSDR_MAX];
50 VkPrimitiveTopology prim;
51 VkPolygonMode polymode;
53 VkFrontFace frontface;
54 VkColorComponentFlags colorwr;
56 int stencil, stencilwr;
57 VkStencilOp sfail, szfail, szpass;
59 unsigned int sref, smask;
61 VkBlendFactor srcblend, dstblend, srcblend_a, dstblend_a;
68 static struct rpass *rpasses;
69 static struct framebuf *framebufs;
70 static struct pipeline *pipelines;
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);
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);
87 #define MAX_INIT_QUEUE 32
92 VkCommandPool cmdpool;
93 } initq[MAX_INIT_QUEUE];
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;
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;
115 static VkPhysicalDevice *pdev_list;
116 static uint32_t num_pdev;
118 static int have_raytrace, have_debug_report;
120 void vk_init_xwin(Display *d, Window w)
126 void vk_init_queue(unsigned int qflags, int count)
130 for(i=0; i<num_initq; i++) {
131 if(initq[i].flags == qflags) {
132 initq[i].count += count;
137 if(num_initq >= MAX_INIT_QUEUE) {
138 fprintf(stderr, "vk_init_queue: too many queues\n");
141 initq[num_initq].flags = qflags;
142 initq[num_initq].count = count;
146 int vk_init(unsigned int flags, unsigned int *usedflags)
149 vk_init_queue(VKQ_GFX | VKQ_PRESENT, 1);
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;
158 if(initflags != flags) {
160 *usedflags = initflags;
169 void vk_cleanup(void)
178 for(i=0; i<vksc_numimg; i++) {
179 vkDestroyImageView(vkdev, vksc_view[i], 0);
184 vkDestroySwapchainKHR(vkdev, vksc, 0);
188 vkDestroyDevice(vkdev, 0);
192 vkDestroySurfaceKHR(vk, vksurf, 0);
196 vkDestroyInstance(vk, 0);
209 int vk_reshape(int xsz, int ysz)
213 if(vksc && vksc_extent.width == xsz && vksc_extent.height == ysz) {
218 for(i=0; i<vksc_numimg; i++) {
219 vkDestroyImageView(vkdev, vksc_view[i], 0);
222 if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
224 vksc_extent.width = xsz;
225 vksc_extent.height = ysz;
227 if(create_swapchain() == -1) return -1;
229 /* TODO create depth/stencil buffers as needed (initflags) */
233 int vk_find_qfamily(unsigned int flags)
238 if(!qfam) return -1; /* not initialized I guess... */
240 for(i=0; i<num_qfam; i++) {
241 vkGetPhysicalDeviceSurfaceSupportKHR(vkpdev, i, vksurf, &can_pres);
243 if((flags & VKQ_PRESENT) && !can_pres) {
246 if((flags & VKQ_GFX) && !(qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) {
249 if((flags & VKQ_COMPUTE) && !(qfam[i].queueFlags & VK_QUEUE_COMPUTE_BIT)) {
253 return i; /* found a suitabe queue family */
259 VkQueue vk_getq_fam(int fam, int n)
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);
270 vkGetDeviceQueue(vkdev, fam, n, &q);
274 VkQueue vk_getq(unsigned int flags, int n)
276 return vk_getq_fam(vk_find_qfamily(flags), n);
279 static VkCommandPool find_cmdpool(int qfam)
282 VkCommandPoolCreateInfo pinf;
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;
293 if(vkCreateCommandPool(vkdev, &pinf, 0, &initq[i].cmdpool) != 0) {
294 fprintf(stderr, "ck_create_cmdbuf: failed to create command buffer pool\n");
298 return initq[i].cmdpool;
302 fprintf(stderr, "vk_create_cmdbuf: failed to find command pool for queue family: %d\n", qfam);
306 VkCommandBuffer vk_create_cmdbuf_fam(int qfam, int level)
308 VkCommandBufferAllocateInfo inf = {0};
309 VkCommandBuffer cmdbuf;
310 VkCommandPool cmdpool;
312 if(!(cmdpool = find_cmdpool(qfam))) {
316 inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
317 inf.commandPool = cmdpool;
319 inf.commandBufferCount = 1;
321 if(vkAllocateCommandBuffers(vkdev, &inf, &cmdbuf) != 0) {
322 fprintf(stderr, "vk_create_cmdbuf: failed to allocate command buffer\n");
328 VkCommandBuffer vk_create_cmdbuf(unsigned int qflags, int level)
332 if((qfam = vk_find_qfamily(qflags)) == -1) {
333 fprintf(stderr, "vk_create_cmdbuf: failed to find matching queue family\n");
336 return vk_create_cmdbuf_fam(qfam, level);
339 int vk_create_rpass(void)
342 struct rpass rpass = {0}, *rp = &rpass;
345 rpasses = darr_alloc(0, sizeof *rpasses);
346 darr_push(rpasses, &rpass); /* add dummy rpass */
349 for(i=1; i<darr_size(rpasses); i++) {
350 if(!rpasses[i].used) {
355 /* init renderpass defaults */
357 rp->fmt = vksurf_fmt[vksurf_selfmt].format;
358 rp->zfmt = VK_FORMAT_D24_UNORM_S8_UINT;
366 darr_push(rpasses, rp);
367 return darr_size(rpasses) - 1;
372 void vk_free_rpass(int rp)
374 if(!rpasses || rp < 1 || rp >= darr_size(rpasses)) {
378 if(rpasses[rp].used && rpasses[rp].vkobj) {
379 vkDestroyRenderPass(vkdev, rpasses[rp].vkobj, 0);
381 rpasses[rp].used = 0;
384 void vk_rpass_colorbuf(int rp, int fmt, int n)
386 rpasses[rp].fmt = fmt;
387 rpasses[rp].num_colbuf = n;
388 rpasses[rp].vkobj_valid = 0;
391 void vk_rpass_msaa(int rp, int nsamp)
393 rpasses[rp].num_samples = nsamp;
394 rpasses[rp].vkobj_valid = 0;
397 void vk_rpass_clear(int rp, int clear)
399 rpasses[rp].clear = clear;
400 rpasses[rp].vkobj_valid = 0;
403 VkRenderPass vk_rpass(int rp)
407 VkAttachmentDescription att[17];
408 VkAttachmentReference catref[16], zatref;
409 VkSubpassDescription subpass;
410 VkRenderPassCreateInfo pinf;
414 if(!r->vkobj_valid) {
416 vkDestroyRenderPass(vkdev, r->vkobj, 0);
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;
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;
441 for(i=0; i<r->num_colbuf; i++) {
442 catref[i].attachment = i;
443 catref[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
445 zatref.attachment = zidx;
446 zatref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
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;
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;
461 if(vkCreateRenderPass(vkdev, &pinf, 0, &r->vkobj) != 0) {
462 fprintf(stderr, "failed to create render pass!\n");
472 int vk_create_fb(void)
475 struct framebuf framebuf = {0}, *fb = &framebuf;
478 framebufs = darr_alloc(0, sizeof *framebufs);
479 darr_push(framebufs, &framebuf); /* add dummy rpass */
482 for(i=1; i<darr_size(framebufs); i++) {
483 if(!framebufs[i].used) {
488 /* init framebuffer defaults */
489 memset(fb, 0, sizeof &fb);
492 if(fb == &framebuf) {
493 darr_push(framebufs, fb);
494 return darr_size(framebufs) - 1;
496 return fb - framebufs;
499 void vk_free_fb(int fb)
501 if(!framebufs || fb < 1 || fb >= darr_size(framebufs)) {
505 if(framebufs[fb].used && framebufs[fb].vkobj) {
506 vkDestroyFramebuffer(vkdev, framebufs[fb].vkobj, 0);
508 framebufs[fb].used = 0;
511 void vk_fb_size(int fb, int x, int y)
513 framebufs[fb].width = x;
514 framebufs[fb].height = y;
515 framebufs[fb].vkobj_valid = 0;
518 void vk_fb_rpass(int fb, int rpass)
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);
525 framebufs[fb].rpidx = rpass;
526 if(rpasses[rpass].vkobj_valid) {
527 framebufs[fb].vkrpass = rpasses[rpass].vkobj;
529 framebufs[fb].vkrpass = 0;
531 framebufs[fb].vkobj_valid = 0;
534 void vk_fb_images(int fb, int n, ...)
539 if(n > MAX_FB_IMGV) {
540 fprintf(stderr, "vk_fb_images: %d is too many images\n", n);
546 framebufs[fb].imgv[i] = va_arg(ap, VkImageView);
549 framebufs[fb].num_imgv = n;
550 framebufs[fb].vkobj_valid = 0;
553 VkFramebuffer vk_fb(int fb)
555 VkFramebufferCreateInfo fbinf;
561 if(!(rpass = vk_rpass(f->rpidx))) {
565 if(rpass != f->vkrpass || !f->vkobj_valid) {
568 vkDestroyFramebuffer(vkdev, f->vkobj, 0);
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;
580 if(vkCreateFramebuffer(vkdev, &fbinf, 0, &f->vkobj) != 0) {
581 fprintf(stderr, "vk_fb: failed to create framebuffer\n");
590 int vk_create_pipeln(void)
593 struct pipeline pipeln = {0}, *pp = &pipeln;
596 pipelines = darr_alloc(0, sizeof *pipelines);
597 darr_push(pipelines, &pipeln); /* add dummy pipeline */
600 for(i=1; i<darr_size(pipelines); i++) {
601 if(!pipelines[i].used) {
606 /* init pipeline defaults */
607 memset(pp, 0, sizeof *pp);
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 */
620 pp->sop = VK_COMPARE_OP_ALWAYS;
621 pp->smask = 0xffffffff;
623 pp->srcblend = pp->srcblend_a = VK_BLEND_FACTOR_ONE;
624 pp->dstblend = pp->dstblend_a = VK_BLEND_FACTOR_ZERO;
627 darr_push(pipelines, pp);
628 return darr_size(pipelines) - 1;
630 return pp - pipelines;
633 void vk_free_pipeln(int pp)
635 if(!pipelines || pp < 1 || pp >= darr_size(pipelines)) {
639 if(pipelines[pp].used && pipelines[pp].vkobj) {
640 vkDestroyPipeline(vkdev, pipelines[pp].vkobj, 0);
642 pipelines[pp].used = 0;
645 void vk_viewport(int pp, int x, int y, int width, int height)
647 struct pipeline *p = pipelines + pp;
651 p->vport[3] = height;
655 void vk_scissor(int pp, int x, int y, int width, int height)
657 struct pipeline *p = pipelines + pp;
660 p->scissor[2] = width;
661 p->scissor[3] = height;
665 void vk_pipeln_shader(int pp, int type, VkShaderModule sdr)
667 struct pipeline *p = pipelines + pp;
672 /* TODO: vertex input */
673 void vk_pipeln_prim(int pp, int prim)
675 struct pipeline *p = pipelines + pp;
680 void vk_pipeln_polymode(int pp, int mode)
682 struct pipeline *p = pipelines + pp;
687 void vk_pipeln_cull(int pp, int cull)
689 struct pipeline *p = pipelines + pp;
694 void vk_pipeln_frontface(int pp, int ff)
696 struct pipeline *p = pipelines + pp;
701 void vk_pipeln_multisample(int pp, int nsamples)
706 void vk_pipeln_colormask(int pp, int r, int g, int b, int a)
708 struct pipeline *p = pipelines + pp;
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;
717 void vk_pipeln_depthmask(int pp, int z)
719 struct pipeline *p = pipelines + pp;
724 void vk_pipeln_stencilmask(int pp, int s)
726 struct pipeline *p = pipelines + pp;
731 void vk_pipeln_zbuffer(int pp, int enable)
733 struct pipeline *p = pipelines + pp;
738 void vk_pipeln_stencil(int pp, int enable)
740 struct pipeline *p = pipelines + pp;
745 void vk_pipeln_stencil_op(int pp, int sfail, int zfail, int zpass)
747 struct pipeline *p = pipelines + pp;
754 void vk_pipeln_stencil_func(int pp, int op, unsigned int ref, unsigned int mask)
756 struct pipeline *p = pipelines + pp;
763 void vk_pipeln_blend(int pp, int enable)
765 struct pipeline *p = pipelines + pp;
770 void vk_pipeln_blendfunc(int pp, int src, int dst)
772 struct pipeline *p = pipelines + pp;
778 VkPipeline vk_pipeln(int pp)
780 struct pipeline *p = pipelines + pp;
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"
803 } known_instext_list[] = {
804 {"VK_KHR_surface", 1},
806 {"VK_KHR_win32_surface", 1},
808 /*{"VK_KHR_xlib_surface", 1},*/
809 {"VK_KHR_xcb_surface", 1},
811 {"VK_KHR_debug_report", 0}
817 } known_devext_list[] = {
818 {"VK_KHR_swapchain", 1},
819 {"VK_KHR_acceleration_structure", 0},
820 {"VK_KHR_ray_tracing_pipeline", 0}
823 static int create_instance(void)
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)];
832 vkEnumerateInstanceVersion(&apiver);
833 printf("Vulkan API version: %d.%d.%d\n", (apiver >> 22) & 0x7f,
834 (apiver >> 12) & 0x3ff, apiver & 0xfff);
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;
842 vkEnumerateInstanceLayerProperties(&inst_layers_count, 0);
843 inst_layers = malloc_nf(inst_layers_count * sizeof *inst_layers);
844 vkEnumerateInstanceLayerProperties(&inst_layers_count, inst_layers);
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);
851 for(i=0; i<inst_layers_count; i++) {
852 printf(" - %s: %s\n", inst_layers[i].layerName, inst_layers[i].description);
854 printf("Instance extensions:\n");
855 for(i=0; i<inst_ext_count; i++) {
856 printf(" - %s\n", inst_ext[i].extensionName);
859 have_debug_report = have_ext(inst_ext, inst_ext_count, "VK_KHR_debug_report");
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];
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);
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");
891 static int create_surface(void)
894 VkXlibSurfaceCreateInfoKHR xinf = {0};
895 xinf.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
899 if(vkCreateXlibSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
900 fprintf(stderr, "failed to create Xlib window surface\n");
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;
909 if(vkCreateXcbSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
910 fprintf(stderr, "failed to create XCB window surface\n");
916 int choose_phys_dev(void)
918 uint32_t i, num_pdev, score, best_score, best_dev;
919 VkPhysicalDevice *pdev;
920 VkPhysicalDeviceProperties pdevprop;
923 vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
925 fprintf(stderr, "no vulkan devices found\n");
928 pdev = malloc_nf(num_pdev * sizeof *pdev);
929 vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
931 printf("Found %d physical devices\n", num_pdev);
935 for(i=0; i<num_pdev; i++) {
936 if((score = eval_pdev_score(pdev[i])) && score > best_score) {
941 vkGetPhysicalDeviceProperties(pdev[i], &pdevprop);
942 printf(" %d: %s (score: %d)\n", i, pdevprop.deviceName, score);
945 fprintf(stderr, "no suitable vulkan device found\n");
949 vkpdev = pdev[best_dev];
953 vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, 0);
954 qfam = malloc_nf(num_qfam * sizeof *qfam);
955 vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, qfam);
962 static int create_device(void)
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;
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);
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);
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";
992 initflags &= ~VKINIT_RAY;
997 for(i=0; i<num_initq; i++) {
998 totalq += initq[i].count;
1001 fprintf(stderr, "create_device: arbitrary limit of total queues exceeded (%d)\n", totalq);
1004 prio = alloca(totalq * sizeof *prio);
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",
1012 initq[i].qfam = qfam;
1013 initq[i].cmdpool = 0;
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 */
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;
1031 if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
1032 fprintf(stderr, "failed to create vulkan device\n");
1038 static int create_swapchain(void)
1042 VkSwapchainCreateInfoKHR scinf = {0};
1043 VkImageViewCreateInfo ivinf;
1045 if(vksc_extent.width <= 0 || vksc_extent.height <= 0) {
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;
1063 if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
1064 fprintf(stderr, "failed to create swapchain\n");
1068 if(!vksc_img || vksc_numimg != num) {
1070 vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
1071 vksc_img = malloc_nf(num * sizeof *vksc_img);
1072 vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
1074 if(!vksc_view || vksc_numimg != num) {
1076 vksc_view = malloc_nf(num * sizeof *vksc_view);
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;
1094 if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
1095 fprintf(stderr, "failed to create image view (%d)\n", i);
1103 static int eval_pdev_score(VkPhysicalDevice dev)
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;
1114 vkGetPhysicalDeviceProperties(dev, &prop);
1115 vkGetPhysicalDeviceFeatures(dev, &feat);
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);
1122 if(!have_ext(ext, num_ext, "VK_KHR_swapchain")) {
1127 /* populate format and present modes arrays, and make sure we have some of each */
1128 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
1133 sfmt = malloc_nf(num_fmt * sizeof *sfmt);
1134 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, sfmt);
1136 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
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);
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) {
1150 switch(prop.deviceType) {
1151 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
1154 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
1157 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
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")) {
1177 static int choose_pixfmt(void)
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
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);
1194 for(i=0; i<num_fmt; i++) {
1195 if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
1198 for(j=0; j<sizeof pref / sizeof *pref; j++) {
1199 if(vksurf_fmt[i].format == pref[j]) {
1201 vksurf_numfmt = num_fmt;
1212 static int have_inst_layer(const char *name)
1215 for(i=0; i<inst_layers_count; i++) {
1216 if(strcmp(inst_layers[i].layerName, name) == 0) {
1223 static int have_ext(VkExtensionProperties *ext, int next, const char *name)
1226 for(i=0; i<next; i++) {
1227 if(strcmp(ext[i].extensionName, name) == 0) {