f3cb5082d5560b4c1bac35b932062eecd779e0f9
[vkray] / src / vk.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <vulkan/vulkan.h>
5 #include "vk.h"
6 #include "util.h"
7
8 #ifdef __WIN32__
9 #include <vulkan/vulkan_win32.h>
10 #else
11 /*#include <vulkan/vulkan_xlib.h>*/
12 #include <X11/Xlib-xcb.h>
13 #include <vulkan/vulkan_xcb.h>
14 #endif
15
16 static int create_instance(void);
17 static int create_surface(void);
18 static int choose_phys_dev(void);
19 static int create_device(void);
20 static int create_swapchain(void);
21
22 static int choose_pixfmt(void);
23 static int eval_pdev_score(VkPhysicalDevice dev);
24 static int have_inst_layer(const char *name);
25 static int have_ext(VkExtensionProperties *ext, int next, const char *name);
26
27 static Display *dpy;
28 static Window win;
29
30 static VkInstance vk;
31 static VkPhysicalDevice vkpdev;
32 static int vkqfam_idx, vkqfam_maxq;
33 static VkDevice vkdev;
34 static VkQueue vkq;
35 static VkSurfaceKHR vksurf;
36 static VkSurfaceCapabilitiesKHR vksurf_caps;
37 static int vksurf_numfmt, vksurf_selfmt;
38 static VkSurfaceFormatKHR *vksurf_fmt;
39 static VkSwapchainKHR vksc;
40 static int vksc_numimg;
41 static VkImage *vksc_img;
42 static VkExtent2D vksc_extent;
43 static VkImageView *vksc_view;
44
45 static VkLayerProperties *inst_layers;
46 static VkExtensionProperties *inst_ext, *dev_ext;
47 static uint32_t inst_ext_count, dev_ext_count, inst_layers_count;
48
49 static VkPhysicalDevice *pdev_list;
50 static uint32_t num_pdev;
51
52 static int have_raytrace, have_debug_report;
53
54 void vk_init_xwin(Display *d, Window w)
55 {
56         dpy = d;
57         win = w;
58 }
59
60 int vk_init(void)
61 {
62         if(create_instance() == -1)     return -1;
63         if(create_surface() == -1) return -1;
64         if(choose_phys_dev() == -1) return -1;
65         if(create_device() == -1) return -1;
66         return 0;
67 }
68
69 void vk_cleanup(void)
70 {
71         int i;
72
73         free(vksc_img);
74         vksc_img = 0;
75         free(vksc_view);
76         vksc_view = 0;
77         if(vksc_view) {
78                 for(i=0; i<vksc_numimg; i++) {
79                         vkDestroyImageView(vkdev, vksc_view[i], 0);
80                 }
81                 vksc_view = 0;
82         }
83         if(vksc) {
84                 vkDestroySwapchainKHR(vkdev, vksc, 0);
85                 vksc = 0;
86         }
87         if(vkdev) {
88                 vkDestroyDevice(vkdev, 0);
89                 vkdev = 0;
90         }
91         if(vksurf) {
92                 vkDestroySurfaceKHR(vk, vksurf, 0);
93                 vksurf = 0;
94         }
95         if(vk) {
96                 vkDestroyInstance(vk, 0);
97                 vk = 0;
98         }
99         free(inst_layers);
100         inst_layers = 0;
101         free(inst_ext);
102         inst_ext = 0;
103         free(dev_ext);
104         dev_ext = 0;
105         free(pdev_list);
106         pdev_list = 0;
107 }
108
109 int vk_reshape(int xsz, int ysz)
110 {
111         int i;
112
113         if(vksc && vksc_extent.width == xsz && vksc_extent.height == ysz) {
114                 return 0;
115         }
116
117         if(vksc_view) {
118                 for(i=0; i<vksc_numimg; i++) {
119                         vkDestroyImageView(vkdev, vksc_view[i], 0);
120                 }
121         }
122         if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
123
124         vksc_extent.width = xsz;
125         vksc_extent.height = ysz;
126
127         return create_swapchain();
128 }
129
130 #define ARRSZ(arr)      (sizeof arr / sizeof *arr)
131 static const char *known_layer_list[] = {
132         "VK_LAYER_GOOGLE_threading",
133         "VK_LAYER_LUNARG_parameter_validation",
134         "VK_LAYER_LUNARG_object_tracker",
135         "VK_LAYER_LUNARG_image",
136         "VK_LAYER_LUNARG_core_validation",
137         "VK_LAYER_LUNARG_swapchain",
138         "VK_LAYER_GOOGLE_unique_objects"
139 };
140
141 static struct {
142         const char *name;
143         int required;
144 } known_instext_list[] = {
145         {"VK_KHR_surface", 1},
146 #ifdef __WIN32__
147         {"VK_KHR_win32_surface", 1},
148 #else
149         /*{"VK_KHR_xlib_surface", 1},*/
150         {"VK_KHR_xcb_surface", 1},
151 #endif
152         {"VK_KHR_debug_report", 0}
153 };
154
155 static struct {
156         const char *name;
157         int required;
158 } known_devext_list[] = {
159         {"VK_KHR_swapchain", 1},
160         {"VK_KHR_acceleration_structure", 0},
161         {"VK_KHR_ray_tracing_pipeline", 0}
162 };
163
164 static int create_instance(void)
165 {
166         int i, nlayers = 0, next = 0;
167         VkInstanceCreateInfo instinf;
168         VkApplicationInfo appinf;
169         const char *layers[ARRSZ(known_layer_list)];
170         const char *ext[ARRSZ(known_instext_list)];
171         uint32_t apiver;
172
173         vkEnumerateInstanceVersion(&apiver);
174         printf("Vulkan API version: %d.%d.%d\n", (apiver >> 22) & 0x7f,
175                         (apiver >> 12) & 0x3ff, apiver & 0xfff);
176
177         memset(&appinf, 0, sizeof appinf);
178         appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
179         appinf.pApplicationName = "vkray";
180         appinf.pEngineName = "vkray";
181         appinf.apiVersion = apiver;
182
183         vkEnumerateInstanceLayerProperties(&inst_layers_count, 0);
184         inst_layers = malloc_nf(inst_layers_count * sizeof *inst_layers);
185         vkEnumerateInstanceLayerProperties(&inst_layers_count, inst_layers);
186
187         vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, 0);
188         inst_ext = malloc_nf(inst_ext_count * sizeof *inst_ext);
189         vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, inst_ext);
190
191         printf("Layers:\n");
192         for(i=0; i<inst_layers_count; i++) {
193                 printf(" - %s: %s\n", inst_layers[i].layerName, inst_layers[i].description);
194         }
195         printf("Instance extensions:\n");
196         for(i=0; i<inst_ext_count; i++) {
197                 printf(" - %s\n", inst_ext[i].extensionName);
198         }
199
200         have_debug_report = have_ext(inst_ext, inst_ext_count, "VK_KHR_debug_report");
201
202         for(i=0; i<ARRSZ(known_layer_list); i++) {
203                 if(have_inst_layer(known_layer_list[i])) {
204                         layers[nlayers++] = known_layer_list[i];
205                 }
206         }
207         for(i=0; i<ARRSZ(known_instext_list); i++) {
208                 if(have_ext(inst_ext, inst_ext_count, known_instext_list[i].name)) {
209                         ext[next++] = known_instext_list[i].name;
210                 } else if(known_instext_list[i].required) {
211                         fprintf(stderr, "Vulkan implementation lacks required instance extension: %s\n",
212                                         known_instext_list[i].name);
213                         return -1;
214                 }
215         }
216
217         memset(&instinf, 0, sizeof instinf);
218         instinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
219         instinf.pApplicationInfo = &appinf;
220         instinf.enabledLayerCount = nlayers;
221         instinf.ppEnabledLayerNames = layers;
222         instinf.enabledExtensionCount = next;
223         instinf.ppEnabledExtensionNames = ext;
224         if(vkCreateInstance(&instinf, 0, &vk) != 0) {
225                 fprintf(stderr, "failed to create vulkan instance\n");
226                 return -1;
227         }
228
229         return 0;
230 }
231
232 static int create_surface(void)
233 {
234         /*
235         VkXlibSurfaceCreateInfoKHR xinf = {0};
236         xinf.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
237         xinf.dpy = dpy;
238         xinf.window = win;
239
240         if(vkCreateXlibSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
241                 fprintf(stderr, "failed to create Xlib window surface\n");
242                 return -1;
243         }
244         */
245         VkXcbSurfaceCreateInfoKHR xinf = {0};
246         xinf.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
247         xinf.connection = XGetXCBConnection(dpy);
248         xinf.window = (xcb_window_t)win;
249
250         if(vkCreateXcbSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
251                 fprintf(stderr, "failed to create XCB window surface\n");
252                 return -1;
253         }
254         return 0;
255 }
256
257 int choose_phys_dev(void)
258 {
259         uint32_t i, num_pdev, num_qfam, score, best_score, best_dev;
260         VkPhysicalDevice *pdev;
261         VkPhysicalDeviceProperties pdevprop;
262         VkQueueFamilyProperties *qfam;
263         VkBool32 can_pres;
264
265         vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
266         if(!num_pdev) {
267                 fprintf(stderr, "no vulkan devices found\n");
268                 return -1;
269         }
270         pdev = malloc_nf(num_pdev * sizeof *pdev);
271         vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
272
273         printf("Found %d physical devices\n", num_pdev);
274
275         best_score = 0;
276         best_dev = -1;
277         for(i=0; i<num_pdev; i++) {
278                 if((score = eval_pdev_score(pdev[i])) && score > best_score) {
279                         best_score = score;
280                         best_dev = i;
281                 }
282
283                 vkGetPhysicalDeviceProperties(pdev[i], &pdevprop);
284                 printf(" %d: %s (score: %d)\n", i, pdevprop.deviceName, score);
285         }
286         if(best_dev == -1) {
287                 fprintf(stderr, "no suitable vulkan device found\n");
288                 free(pdev);
289                 return -1;
290         }
291         vkpdev = pdev[best_dev];
292
293         vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, 0);
294         qfam = malloc_nf(num_qfam * sizeof *qfam);
295         vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, qfam);
296
297         vkqfam_idx = -1;
298         for(i=0; i<num_qfam; i++) {
299                 vkGetPhysicalDeviceSurfaceSupportKHR(vkpdev, i, vksurf, &can_pres);
300                 if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
301                         vkqfam_maxq = qfam[i].queueCount;
302                         vkqfam_idx = i;
303                         break;
304                 }
305         }
306
307         free(qfam);
308         free(pdev);
309         choose_pixfmt();
310         return 0;
311 }
312
313 static int create_device(void)
314 {
315         float prio = 1.0f;
316         VkDeviceQueueCreateInfo qinf = {0};
317         VkPhysicalDeviceFeatures feat = {0};
318         VkDeviceCreateInfo devinf = {0};
319         const char *ext[ARRSZ(known_devext_list)];
320         int i, num_ext;
321
322         vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, 0);
323         dev_ext = malloc_nf(dev_ext_count * sizeof *dev_ext);
324         vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, dev_ext);
325
326         num_ext = 0;
327         for(i=0; i<ARRSZ(known_devext_list); i++) {
328                 if(have_ext(dev_ext, dev_ext_count, known_devext_list[i].name)) {
329                         ext[num_ext++] = known_devext_list[i].name;
330                 } else if(known_devext_list[i].required) {
331                         fprintf(stderr, "Vulkan device lacks required extension: %s\n",
332                                         known_devext_list[i].name);
333                         return -1;
334                 }
335         }
336
337         qinf.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
338         qinf.queueFamilyIndex = vkqfam_idx;
339         qinf.queueCount = 1;
340         qinf.pQueuePriorities = &prio;
341
342         devinf.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
343         devinf.pQueueCreateInfos = &qinf;
344         devinf.queueCreateInfoCount = 1;
345         devinf.pEnabledFeatures = &feat;
346         devinf.enabledExtensionCount = num_ext;
347         devinf.ppEnabledExtensionNames = ext;
348
349         if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
350                 fprintf(stderr, "failed to create vulkan device\n");
351                 return -1;
352         }
353
354         vkGetDeviceQueue(vkdev, vkqfam_idx, 0, &vkq);
355         return 0;
356 }
357
358 static int create_swapchain(void)
359 {
360         int i;
361         uint32_t num;
362         VkSwapchainCreateInfoKHR scinf = {0};
363         VkImageViewCreateInfo ivinf;
364
365         if(vksc_extent.width <= 0 || vksc_extent.height <= 0) {
366                 return -1;
367         }
368
369         scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
370         scinf.surface = vksurf;
371         scinf.minImageCount = 2;
372         scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
373         scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
374         scinf.imageExtent = vksc_extent;
375         scinf.imageArrayLayers = 1;
376         scinf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
377         scinf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
378         scinf.preTransform = vksurf_caps.currentTransform;
379         scinf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
380         scinf.presentMode = VK_PRESENT_MODE_FIFO_KHR;
381         scinf.clipped = VK_TRUE;
382
383         if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
384                 fprintf(stderr, "failed to create swapchain\n");
385                 return -1;
386         }
387
388         if(!vksc_img || vksc_numimg != num) {
389                 free(vksc_img);
390                 vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
391                 vksc_img = malloc_nf(num * sizeof *vksc_img);
392                 vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
393         }
394         if(!vksc_view || vksc_numimg != num) {
395                 free(vksc_view);
396                 vksc_view = malloc_nf(num * sizeof *vksc_view);
397         }
398         vksc_numimg = num;
399
400         for(i=0; i<num; i++) {
401                 memset(&ivinf, 0, sizeof ivinf);
402                 ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
403                 ivinf.image = vksc_img[i];
404                 ivinf.format = vksurf_fmt[vksurf_selfmt].format;
405                 ivinf.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
406                 ivinf.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
407                 ivinf.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
408                 ivinf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
409                 ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
410                 ivinf.subresourceRange.levelCount = 1;
411                 ivinf.subresourceRange.layerCount = 1;
412                 ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
413
414                 if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
415                         fprintf(stderr, "failed to create image view (%d)\n", i);
416                         return -1;
417                 }
418         }
419         return 0;
420 }
421
422
423 static int eval_pdev_score(VkPhysicalDevice dev)
424 {
425         uint32_t i, num_fmt, num_qfam, num_ext;
426         VkQueueFamilyProperties *qfam;
427         VkExtensionProperties *ext;
428         VkPhysicalDeviceProperties prop;
429         VkPhysicalDeviceFeatures feat;
430         VkSurfaceFormatKHR *sfmt;
431         VkBool32 can_pres;
432
433         vkGetPhysicalDeviceProperties(dev, &prop);
434         vkGetPhysicalDeviceFeatures(dev, &feat);
435
436         /* check if we have the swapchain extension */
437         vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, 0);
438         ext = malloc_nf(num_ext * sizeof *ext);
439         vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, ext);
440
441         if(!have_ext(ext, num_ext, "VK_KHR_swapchain")) {
442                 free(ext);
443                 return 0;
444         }
445
446         /* populate format and present modes arrays, and make sure we have some of each */
447         vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
448         if(!num_fmt) {
449                 free(ext);
450                 return 0;
451         }
452         sfmt = malloc_nf(num_fmt * sizeof *sfmt);
453         vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, sfmt);
454
455         vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
456
457         /* find a queue family which can do graphics and can present */
458         vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
459         qfam = malloc_nf(num_qfam * sizeof *qfam);
460         vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
461
462         for(i=0; i<num_qfam; i++) {
463                 vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, vksurf, &can_pres);
464                 if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
465                         free(ext);
466                         free(sfmt);
467                         free(qfam);
468                         return 1;
469                 }
470         }
471
472         free(ext);
473         free(sfmt);
474         free(qfam);
475         return 0;
476 }
477
478 static int choose_pixfmt(void)
479 {
480         static const VkFormat pref[] = {
481                 VK_FORMAT_B8G8R8_UNORM,
482                 VK_FORMAT_R8G8B8_UNORM,
483                 VK_FORMAT_B8G8R8A8_UNORM,
484                 VK_FORMAT_R8G8B8A8_UNORM
485         };
486         int i, j;
487         uint32_t num_fmt;
488
489         vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, 0);
490         if(!num_fmt) return -1;
491         vksurf_fmt = malloc_nf(num_fmt * sizeof *vksurf_fmt);
492         vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, vksurf_fmt);
493
494         vksurf_selfmt = 0;
495         for(i=0; i<num_fmt; i++) {
496                 if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
497                         continue;
498                 }
499                 for(j=0; j<sizeof pref / sizeof *pref; j++) {
500                         if(vksurf_fmt[i].format == pref[j]) {
501                                 vksurf_selfmt = i;
502                                 vksurf_numfmt = num_fmt;
503                                 return i;
504                         }
505                 }
506         }
507         free(vksurf_fmt);
508         vksurf_fmt = 0;
509         return -1;
510 }
511
512
513 static int have_inst_layer(const char *name)
514 {
515         int i;
516         for(i=0; i<inst_layers_count; i++) {
517                 if(strcmp(inst_layers[i].layerName, name) == 0) {
518                         return 1;
519                 }
520         }
521         return 0;
522 }
523
524 static int have_ext(VkExtensionProperties *ext, int next, const char *name)
525 {
526         int i;
527         for(i=0; i<next; i++) {
528                 if(strcmp(ext[i].extensionName, name) == 0) {
529                         return 1;
530                 }
531         }
532         return 0;
533 }