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