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